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  * @modules jdk.jdeps/com.sun.tools.classfile
31  *          jdk.compiler/com.sun.tools.javac.api
32  *          jdk.compiler/com.sun.tools.javac.code
33  *          jdk.compiler/com.sun.tools.javac.comp
34  *          jdk.compiler/com.sun.tools.javac.main
35  *          jdk.compiler/com.sun.tools.javac.tree
36  *          jdk.compiler/com.sun.tools.javac.util
37  * @build combo.ComboTestHelper
38  * @run main T7093325
39  */
40 
41 import java.io.IOException;
42 import java.io.InputStream;
43 
44 import com.sun.tools.classfile.Attribute;
45 import com.sun.tools.classfile.ClassFile;
46 import com.sun.tools.classfile.Code_attribute;
47 import com.sun.tools.classfile.ConstantPoolException;
48 import com.sun.tools.classfile.Method;
49 
50 import javax.tools.JavaFileObject;
51 
52 import combo.ComboInstance;
53 import combo.ComboParameter;
54 import combo.ComboTask.Result;
55 import combo.ComboTestHelper;
56 
57 public class T7093325 extends ComboInstance<T7093325> {
58 
59     enum StatementKind implements ComboParameter {
60         NONE(null, false, false),
61         THROW("throw new RuntimeException();", false, false),
62         RETURN_NONEMPTY("System.out.println(); return;", true, false),
63         RETURN_EMPTY("return;", true, true),
64         APPLY("System.out.println();", true, false);
65 
66         String stmt;
67         boolean canInline;
68         boolean empty;
69 
StatementKind(String stmt, boolean canInline, boolean empty)70         StatementKind(String stmt, boolean canInline, boolean empty) {
71             this.stmt = stmt;
72             this.canInline = canInline;
73             this.empty = empty;
74         }
75 
76         @Override
expand(String optParameter)77         public String expand(String optParameter) {
78             return stmt;
79         }
80     }
81 
82     enum CatchArity implements ComboParameter {
83         NONE(""),
84         ONE("catch (A a) { #{STMT[1]} }"),
85         TWO("catch (B b) { #{STMT[2]} }"),
86         THREE("catch (C c) { #{STMT[3]} }"),
87         FOUR("catch (D d) { #{STMT[4]} }");
88 
89         String catchStr;
90 
CatchArity(String catchStr)91         CatchArity(String catchStr) {
92             this.catchStr = catchStr;
93         }
94 
95         @Override
expand(String optParameter)96         public String expand(String optParameter) {
97             if (this.ordinal() == 0) {
98                 return catchStr;
99             } else {
100                 return CatchArity.values()[this.ordinal() - 1].expand(optParameter) +
101                         catchStr;
102             }
103         }
104     }
105 
main(String... args)106     public static void main(String... args) throws Exception {
107         new ComboTestHelper<T7093325>()
108                 .withFilter(T7093325::testFilter)
109                 .withDimension("CATCH", (x, ca) -> x.ca = ca, CatchArity.values())
110                 .withArrayDimension("STMT", (x, stmt, idx) -> x.stmts[idx] = stmt, 5, StatementKind.values())
111                 .run(T7093325::new);
112     }
113 
114     /** instance decls **/
115 
116     CatchArity ca;
117     StatementKind[] stmts = new StatementKind[5];
118 
testFilter()119     boolean testFilter() {
120         int lastPos = ca.ordinal() + 1;
121         for (int i = 0; i < stmts.length ; i++) {
122             boolean shouldBeSet = i < lastPos;
123             boolean isSet = stmts[i] != StatementKind.NONE;
124             if (shouldBeSet != isSet) {
125                 return false;
126             }
127         }
128         return true;
129     }
130 
131     @Override
132     public void doWork() throws IOException {
133         newCompilationTask()
134                 .withSourceFromTemplate(source_template)
135                 .generate(this::verifyBytecode);
136     }
137 
138     void verifyBytecode(Result<Iterable<? extends JavaFileObject>> result) {
139         boolean lastInlined = false;
140         boolean hasCode = false;
141         int gapsCount = 0;
142         for (int i = 0; i < ca.ordinal() + 1 ; i++) {
143             lastInlined = stmts[i].canInline;
144             hasCode = hasCode || !stmts[i].empty;
145             if (lastInlined && hasCode) {
146                 hasCode = false;
147                 gapsCount++;
148             }
149         }
150         if (!lastInlined) {
151             gapsCount++;
152         }
153 
154         try (InputStream is = result.get().iterator().next().openInputStream()) {
155             ClassFile cf = ClassFile.read(is);
156             if (cf == null) {
157                 fail("Classfile not found: " + result.compilationInfo());
158                 return;
159             }
160 
161             Method test_method = null;
162             for (Method m : cf.methods) {
163                 if (m.getName(cf.constant_pool).equals("test")) {
164                     test_method = m;
165                     break;
166                 }
167             }
168 
169             if (test_method == null) {
170                 fail("Method test() not found in class Test" + result.compilationInfo());
171                 return;
172             }
173 
174             Code_attribute code = null;
175             for (Attribute a : test_method.attributes) {
176                 if (a.getName(cf.constant_pool).equals(Attribute.Code)) {
177                     code = (Code_attribute)a;
178                     break;
179                 }
180             }
181 
182             if (code == null) {
183                 fail("Code attribute not found in method test()");
184                 return;
185             }
186 
187             int actualGapsCount = 0;
188             for (int i = 0; i < code.exception_table_length ; i++) {
189                 int catchType = code.exception_table[i].catch_type;
190                 if (catchType == 0) { //any
191                     actualGapsCount++;
192                 }
193             }
194 
195             if (actualGapsCount != gapsCount) {
196                 fail("Bad exception table for test()\n" +
197                             "expected gaps: " + gapsCount + "\n" +
198                             "found gaps: " + actualGapsCount + "\n" +
199                         result.compilationInfo());
200                 return;
201             }
202         } catch (IOException | ConstantPoolException e) {
203             e.printStackTrace();
204             fail("error reading classfile: " + e);
205         }
206 
207     }
208 
209     static final String source_template =
210                 "class Test {\n" +
211                 "   void test() {\n" +
212                 "   try { #{STMT[0]} } #{CATCH} finally { System.out.println(); }\n" +
213                 "   }\n" +
214                 "}\n" +
215                 "class A extends RuntimeException {} \n" +
216                 "class B extends RuntimeException {} \n" +
217                 "class C extends RuntimeException {} \n" +
218                 "class D extends RuntimeException {} \n" +
219                 "class E extends RuntimeException {}";
220 }
221