1/*
2 * Copyright (c) 2014, 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 DeoptimizeFramesTest
26 * @bug 8028595
27 * @summary testing of WB::deoptimizeFrames()
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 *                   -XX:CompileCommand=compileonly,compiler.whitebox.DeoptimizeFramesTest$TestCaseImpl::method
37 *                   -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot
38 *                   compiler.whitebox.DeoptimizeFramesTest true
39 * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
40 *                   -XX:+WhiteBoxAPI -Xmixed -XX:-UseCounterDecay
41 *                   -XX:CompileCommand=compileonly,compiler.whitebox.DeoptimizeFramesTest$TestCaseImpl::method
42 *                   -XX:+IgnoreUnrecognizedVMOptions -XX:-DeoptimizeRandom -XX:-DeoptimizeALot
43 *                   compiler.whitebox.DeoptimizeFramesTest false
44 */
45
46package compiler.whitebox;
47
48import jdk.test.lib.Asserts;
49import sun.hotspot.code.NMethod;
50
51import java.lang.reflect.Executable;
52import java.util.concurrent.Callable;
53import java.util.concurrent.Phaser;
54
55public class DeoptimizeFramesTest extends CompilerWhiteBoxTest {
56    private final boolean makeNotEntrant;
57    private final Phaser phaser;
58
59    private DeoptimizeFramesTest(boolean makeNotEntrant, Phaser phaser) {
60        super(new TestCaseImpl(phaser));
61        // to prevent inlining of #method
62        WHITE_BOX.testSetDontInlineMethod(method, true);
63        this.makeNotEntrant = makeNotEntrant;
64        this.phaser = phaser;
65        System.out.printf("DeoptimizeFramesTest(makeNotEntrant = %b)%n",
66                makeNotEntrant);
67    }
68
69    public static void main(String[] args) throws Exception {
70        Asserts.assertEQ(args.length, 1,
71                "[TESTBUG] args should contain 1 element");
72        new DeoptimizeFramesTest(Boolean.valueOf(args[0]), new Phaser()).runTest();
73    }
74
75    @Override
76    protected void test() throws Exception {
77        compile();
78        checkCompiled();
79        NMethod nm = NMethod.get(method, testCase.isOsr());
80
81        WHITE_BOX.deoptimizeFrames(makeNotEntrant);
82        // #method should still be compiled, since it didn't have frames on stack
83        checkCompiled();
84        NMethod nm2 = NMethod.get(method, testCase.isOsr());
85        Asserts.assertEQ(nm.compile_id, nm2.compile_id,
86                "should be the same nmethod");
87
88        phaser.register();
89        Thread t = new Thread(() -> compile(1));
90        t.start();
91        // pass 1st phase, #method is on stack
92        int p = phaser.arriveAndAwaitAdvance();
93        WHITE_BOX.deoptimizeFrames(makeNotEntrant);
94        // pass 2nd phase, #method can exit
95        phaser.awaitAdvance(phaser.arriveAndDeregister());
96
97        try {
98            t.join();
99        } catch (InterruptedException e) {
100            throw new Error("method '" + method + "' is still executing", e);
101        }
102
103        // invoke one more time to recompile not entrant if any
104        compile(1);
105
106        nm2 = NMethod.get(method, testCase.isOsr());
107        if (makeNotEntrant) {
108            if (nm2 != null) {
109                Asserts.assertNE(nm.compile_id, nm2.compile_id,
110                        String.format("compilation %d can't be available", nm.compile_id));
111            }
112        } else {
113            Asserts.assertEQ(nm.compile_id, nm2.compile_id, "should be the same nmethod");
114        }
115    }
116
117
118    private static class TestCaseImpl implements TestCase {
119        private static final Executable EXECUTABLE;
120        static {
121            try {
122                EXECUTABLE = TestCaseImpl.class.getDeclaredMethod("method");
123            } catch (NoSuchMethodException e) {
124                throw new Error("[TESTBUG] method not found", e);
125            }
126        }
127
128        private final Phaser phaser;
129
130        public TestCaseImpl(Phaser phaser) {
131            this.phaser = phaser;
132            phaser.register();
133        }
134
135        @Override
136        public String name() {
137            return "2phases";
138        }
139
140        @Override
141        public Executable getExecutable() {
142            return EXECUTABLE;
143        }
144
145        @Override
146        public Callable<Integer> getCallable() {
147            return () -> {
148                return method();
149            };
150        }
151
152        @Override
153        public boolean isOsr() {
154            return false;
155        }
156
157        private int method() {
158            phaser.arriveAndAwaitAdvance();
159            phaser.arriveAndAwaitAdvance();
160            return 0;
161        }
162    }
163}
164