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
41import java.io.IOException;
42import java.io.InputStream;
43
44import com.sun.tools.classfile.Attribute;
45import com.sun.tools.classfile.ClassFile;
46import com.sun.tools.classfile.Code_attribute;
47import com.sun.tools.classfile.ConstantPoolException;
48import com.sun.tools.classfile.Method;
49
50import javax.tools.JavaFileObject;
51
52import combo.ComboInstance;
53import combo.ComboParameter;
54import combo.ComboTask.Result;
55import combo.ComboTestHelper;
56
57public 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
70        StatementKind(String stmt, boolean canInline, boolean empty) {
71            this.stmt = stmt;
72            this.canInline = canInline;
73            this.empty = empty;
74        }
75
76        @Override
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
91        CatchArity(String catchStr) {
92            this.catchStr = catchStr;
93        }
94
95        @Override
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
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
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        verifyBytecode(newCompilationTask()
134                .withSourceFromTemplate(source_template)
135                .generate());
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