1/*
2 * Copyright (c) 2013, 2016, 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 MakeMethodNotCompilableTest
26 * @bug 8012322 8006683 8007288 8022832
27 * @summary testing of WB::makeMethodNotCompilable()
28 * @library /test/lib /
29 * @modules java.base/jdk.internal.misc
30 *          java.management
31 * @build sun.hotspot.WhiteBox
32 * @run driver ClassFileInstaller sun.hotspot.WhiteBox
33 *                                sun.hotspot.WhiteBox$WhiteBoxPermission
34 * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
35 *                   -XX:+WhiteBoxAPI -Xmixed -XX:-UseCounterDecay
36 *                   compiler.whitebox.MakeMethodNotCompilableTest
37 */
38
39package compiler.whitebox;
40
41public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest {
42    private int bci;
43    public static void main(String[] args) throws Exception {
44        String directive =
45                "[{ match:\"*SimpleTestCaseHelper.*\", BackgroundCompilation: false }, " +
46                " { match:\"*.*\", inline:\"-*SimpleTestCaseHelper.*\"}]";
47        if (WHITE_BOX.addCompilerDirective(directive) != 2) {
48            throw new RuntimeException("Could not add directive");
49        }
50        try {
51            CompilerWhiteBoxTest.main(MakeMethodNotCompilableTest::new, args);
52        } finally {
53            WHITE_BOX.removeCompilerDirective(2);
54        }
55    }
56
57    private MakeMethodNotCompilableTest(TestCase testCase) {
58        super(testCase);
59        // to prevent inlining of #method
60        WHITE_BOX.testSetDontInlineMethod(method, true);
61    }
62
63    /**
64     * Tests {@code WB::makeMethodNotCompilable()} by calling it before
65     * compilation and checking that method isn't compiled. Also
66     * checks that WB::clearMethodState() clears no-compilable flags. For
67     * tiered, additional checks for all available levels are conducted.
68     *
69     * @throws Exception if one of the checks fails.
70     */
71    @Override
72    protected void test() throws Exception {
73        if (skipXcompOSR()) {
74            return;
75        }
76        checkNotCompiled();
77        if (!isCompilable()) {
78            throw new RuntimeException(method + " must be compilable");
79        }
80
81        bci = getBci();
82
83        if (TIERED_COMPILATION) {
84            final int tierLimit = TIERED_STOP_AT_LEVEL + 1;
85            for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
86                testTier(testedTier);
87            }
88            for (int testedTier = 1; testedTier < tierLimit; ++testedTier) {
89                makeNotCompilable(testedTier);
90                if (isCompilable(testedTier)) {
91                    throw new RuntimeException(method
92                            + " must be not compilable at level" + testedTier);
93                }
94                WHITE_BOX.enqueueMethodForCompilation(method, testedTier, bci);
95                checkNotCompiled();
96
97                if (!isCompilable()) {
98                    System.out.println(method
99                            + " is not compilable after level " + testedTier);
100                }
101            }
102        } else {
103            compile();
104            checkCompiled();
105            int compLevel = getCompLevel();
106            deoptimize();
107            makeNotCompilable(compLevel);
108            if (isCompilable(COMP_LEVEL_ANY)) {
109                throw new RuntimeException(method
110                        + " must be not compilable at CompLevel::CompLevel_any,"
111                        + " after it is not compilable at " + compLevel);
112            }
113
114            WHITE_BOX.clearMethodState(method);
115            if (!isCompilable()) {
116                throw new RuntimeException(method
117                        + " is not compilable after clearMethodState()");
118            }
119
120            // nocompilable at opposite level must make no sense
121            int oppositeLevel;
122            if (isC1Compile(compLevel)) {
123              oppositeLevel = COMP_LEVEL_FULL_OPTIMIZATION;
124            } else {
125              oppositeLevel = COMP_LEVEL_SIMPLE;
126            }
127            makeNotCompilable(oppositeLevel);
128
129            if (!isCompilable(COMP_LEVEL_ANY)) {
130                  throw new RuntimeException(method
131                        + " must be compilable at CompLevel::CompLevel_any,"
132                        + " even it is not compilable at opposite level ["
133                        + compLevel + "]");
134            }
135
136            if (!isCompilable(compLevel)) {
137                  throw new RuntimeException(method
138                        + " must be compilable at level " + compLevel
139                        + ", even it is not compilable at opposite level ["
140                        + compLevel + "]");
141            }
142        }
143
144        // clearing after tiered/non-tiered tests
145        // WB.clearMethodState() must reset no-compilable flags
146        WHITE_BOX.clearMethodState(method);
147        if (!isCompilable()) {
148            throw new RuntimeException(method
149                    + " is not compilable after clearMethodState()");
150        }
151        // Make method not (OSR-)compilable (depending on testCase.isOsr())
152        makeNotCompilable();
153        if (isCompilable()) {
154            throw new RuntimeException(method + " must be not compilable");
155        }
156        // Try to (OSR-)compile method
157        compile();
158        // Method should not be (OSR-)compiled
159        checkNotCompiled(testCase.isOsr());
160        if (isCompilable()) {
161            throw new RuntimeException(method + " must be not compilable");
162        }
163        // WB.clearMethodState() must reset no-compilable flags
164        WHITE_BOX.clearMethodState(method);
165        if (!isCompilable()) {
166            throw new RuntimeException(method
167                    + " is not compilable after clearMethodState()");
168        }
169        compile();
170        checkCompiled();
171    }
172
173    // separately tests each tier
174    private void testTier(int testedTier) {
175        if (!isCompilable(testedTier)) {
176            throw new RuntimeException(method
177                    + " is not compilable on start");
178        }
179        makeNotCompilable(testedTier);
180
181        // tests for all other tiers
182        for (int anotherTier = 1, tierLimit = TIERED_STOP_AT_LEVEL + 1;
183                    anotherTier < tierLimit; ++anotherTier) {
184            boolean isCompilable = isCompilable(anotherTier);
185            if (sameCompile(testedTier, anotherTier)) {
186                if (isCompilable) {
187                    throw new RuntimeException(method
188                            + " must be not compilable at level " + anotherTier
189                            + ", if it is not compilable at " + testedTier);
190                }
191                WHITE_BOX.enqueueMethodForCompilation(method, anotherTier, bci);
192                checkNotCompiled();
193            } else {
194                if (!isCompilable) {
195                    throw new RuntimeException(method
196                            + " must be compilable at level " + anotherTier
197                            + ", even if it is not compilable at "
198                            + testedTier);
199                }
200                WHITE_BOX.enqueueMethodForCompilation(method, anotherTier, bci);
201                checkCompiled();
202                deoptimize();
203            }
204
205            if (!isCompilable(COMP_LEVEL_ANY)) {
206                throw new RuntimeException(method
207                        + " must be compilable at 'CompLevel::CompLevel_any'"
208                        + ", if it is not compilable only at " + testedTier);
209            }
210        }
211
212        // clear state after test
213        WHITE_BOX.clearMethodState(method);
214        if (!isCompilable(testedTier)) {
215            throw new RuntimeException(method
216                    + " is not compilable after clearMethodState()");
217        }
218    }
219
220    private boolean sameCompile(int level1, int level2) {
221        if (level1 == level2) {
222            return true;
223        }
224        if (isC1Compile(level1) && isC1Compile(level2)) {
225            return true;
226        }
227        if (isC2Compile(level1) && isC2Compile(level2)) {
228            return true;
229        }
230        return false;
231    }
232
233    private int getBci() throws Exception {
234        compile();
235        checkCompiled();
236        int result = WHITE_BOX.getMethodEntryBci(method);
237        deoptimize();
238        WHITE_BOX.clearMethodState(method);
239        return result;
240    }
241}
242