1 /*
  2  * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @bug 7093325 8006694 8129962
 27  * @summary Redundant entry in bytecode exception table
 28  *  temporarily workaround combo tests are causing time out in several platforms
 29  * @library /tools/javac/lib
 30  * @enablePreview
 31  * @modules java.base/jdk.internal.classfile.impl
 32  *          jdk.compiler/com.sun.tools.javac.api
 33  *          jdk.compiler/com.sun.tools.javac.file
 34  *          jdk.compiler/com.sun.tools.javac.util
 35  * @build combo.ComboTestHelper
 36  * @run main T7093325
 37  */
 38 
 39 import java.io.IOException;
 40 import java.io.InputStream;
 41 
 42 import java.lang.classfile.*;
 43 import java.lang.classfile.attribute.CodeAttribute;
 44 import java.lang.classfile.constantpool.ClassEntry;
 45 
 46 import javax.tools.JavaFileObject;
 47 
 48 import combo.ComboInstance;
 49 import combo.ComboParameter;
 50 import combo.ComboTask.Result;
 51 import combo.ComboTestHelper;
 52 
 53 public class T7093325 extends ComboInstance<T7093325> {
 54 
 55     enum StatementKind implements ComboParameter {
 56         NONE(null, false, false),
 57         THROW("throw new RuntimeException();", false, false),
 58         RETURN_NONEMPTY("System.out.println(); return;", true, false),
 59         RETURN_EMPTY("return;", true, true),
 60         APPLY("System.out.println();", true, false);
 61 
 62         String stmt;
 63         boolean canInline;
 64         boolean empty;
 65 
 66         StatementKind(String stmt, boolean canInline, boolean empty) {
 67             this.stmt = stmt;
 68             this.canInline = canInline;
 69             this.empty = empty;
 70         }
 71 
 72         @Override
 73         public String expand(String optParameter) {
 74             return stmt;
 75         }
 76     }
 77 
 78     enum CatchArity implements ComboParameter {
 79         NONE(""),
 80         ONE("catch (A a) { #{STMT[1]} }"),
 81         TWO("catch (B b) { #{STMT[2]} }"),
 82         THREE("catch (C c) { #{STMT[3]} }"),
 83         FOUR("catch (D d) { #{STMT[4]} }");
 84 
 85         String catchStr;
 86 
 87         CatchArity(String catchStr) {
 88             this.catchStr = catchStr;
 89         }
 90 
 91         @Override
 92         public String expand(String optParameter) {
 93             if (this.ordinal() == 0) {
 94                 return catchStr;
 95             } else {
 96                 return CatchArity.values()[this.ordinal() - 1].expand(optParameter) +
 97                         catchStr;
 98             }
 99         }
100     }
101 
102     public static void main(String... args) throws Exception {
103         new ComboTestHelper<T7093325>()
104                 .withFilter(T7093325::testFilter)
105                 .withDimension("CATCH", (x, ca) -> x.ca = ca, CatchArity.values())
106                 .withArrayDimension("STMT", (x, stmt, idx) -> x.stmts[idx] = stmt, 5, StatementKind.values())
107                 .run(T7093325::new);
108     }
109 
110     /** instance decls **/
111 
112     CatchArity ca;
113     StatementKind[] stmts = new StatementKind[5];
114 
115     boolean testFilter() {
116         int lastPos = ca.ordinal() + 1;
117         for (int i = 0; i < stmts.length ; i++) {
118             boolean shouldBeSet = i < lastPos;
119             boolean isSet = stmts[i] != StatementKind.NONE;
120             if (shouldBeSet != isSet) {
121                 return false;
122             }
123         }
124         return true;
125     }
126 
127     @Override
128     public void doWork() throws IOException {
129         newCompilationTask()
130                 .withSourceFromTemplate(source_template)
131                 .generate(this::verifyBytecode);
132     }
133 
134     void verifyBytecode(Result<Iterable<? extends JavaFileObject>> result) {
135         boolean lastInlined = false;
136         boolean hasCode = false;
137         int gapsCount = 0;
138         for (int i = 0; i < ca.ordinal() + 1 ; i++) {
139             lastInlined = stmts[i].canInline;
140             hasCode = hasCode || !stmts[i].empty;
141             if (lastInlined && hasCode) {
142                 hasCode = false;
143                 gapsCount++;
144             }
145         }
146         if (!lastInlined) {
147             gapsCount++;
148         }
149 
150         try (InputStream is = result.get().iterator().next().openInputStream()) {
151             ClassModel cf = ClassFile.of().parse(is.readAllBytes());
152             if (cf == null) {
153                 fail("ClassFile not found: " + result.compilationInfo());
154                 return;
155             }
156 
157             MethodModel test_method = null;
158             for (MethodModel m : cf.methods()) {
159                 if (m.methodName().equalsString("test")) {
160                     test_method = m;
161                     break;
162                 }
163             }
164 
165             if (test_method == null) {
166                 fail("Method test() not found in class Test" + result.compilationInfo());
167                 return;
168             }
169 
170             CodeAttribute code = test_method.findAttribute(Attributes.CODE).orElse(null);
171 
172             if (code == null) {
173                 fail("Code attribute not found in method test()");
174                 return;
175             }
176 
177             int actualGapsCount = 0;
178             for (int i = 0; i < code.exceptionHandlers().size() ; i++) {
179                 ClassEntry catchType = code.exceptionHandlers().get(i).catchType().orElse(null);
180                 if (catchType == null) { //any
181                     actualGapsCount++;
182                 }
183             }
184 
185             if (actualGapsCount != gapsCount) {
186                 fail("Bad exception table for test()\n" +
187                             "expected gaps: " + gapsCount + "\n" +
188                             "found gaps: " + actualGapsCount + "\n" +
189                         result.compilationInfo());
190             }
191         } catch (IOException e) {
192             e.printStackTrace();
193             fail("error reading classfile: " + e);
194         }
195 
196     }
197 
198     static final String source_template =
199                 "class Test {\n" +
200                 "   void test() {\n" +
201                 "   try { #{STMT[0]} } #{CATCH} finally { System.out.println(); }\n" +
202                 "   }\n" +
203                 "}\n" +
204                 "class A extends RuntimeException {} \n" +
205                 "class B extends RuntimeException {} \n" +
206                 "class C extends RuntimeException {} \n" +
207                 "class D extends RuntimeException {} \n" +
208                 "class E extends RuntimeException {}";
209 }