1 /*
   2  * Copyright (c) 2014, 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 DeoptimizeFramesTest
  26  * @bug 8028595
  27  * @summary testing of WB::deoptimizeFrames()
  28  * @library /testlibrary /test/lib /
  29  * @modules java.base/jdk.internal.misc
  30  *          java.management
  31  * @build compiler.whitebox.DeoptimizeFramesTest
  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 
  46 package compiler.whitebox;
  47 
  48 import jdk.test.lib.Asserts;
  49 import sun.hotspot.code.NMethod;
  50 
  51 import java.lang.reflect.Executable;
  52 import java.util.concurrent.Callable;
  53 import java.util.concurrent.Phaser;
  54 
  55 public 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 }