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