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