| /* |
| * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * @test |
| * @bug 8275908 |
| * @summary Quick test for the new WhiteBox methods of JDK-8275908 |
| * |
| * @requires vm.compiler2.enabled & vm.compMode != "Xcomp" |
| * @requires vm.opt.DeoptimizeALot != true |
| * |
| * @library /test/lib |
| * @build jdk.test.whitebox.WhiteBox |
| * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox |
| * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI |
| * -Xbatch -XX:-UseOnStackReplacement -XX:-TieredCompilation |
| * -XX:+UnlockExperimentalVMOptions -XX:PerMethodTrapLimit=100 -XX:PerBytecodeTrapLimit=4 |
| * -XX:TypeProfileLevel=0 |
| * -XX:+IgnoreUnrecognizedVMOptions -XX:-AlwaysIncrementalInline -XX:-StressIncrementalInlining |
| * -XX:CompileCommand=compileonly,compiler.uncommontrap.Decompile::uncommonTrap |
| * -XX:CompileCommand=inline,compiler.uncommontrap.Decompile*::foo |
| * compiler.uncommontrap.Decompile |
| */ |
| |
| package compiler.uncommontrap; |
| |
| import java.lang.reflect.Method; |
| |
| import jdk.test.lib.Asserts; |
| import jdk.test.whitebox.WhiteBox; |
| |
| public class Decompile { |
| |
| private static final WhiteBox WB = WhiteBox.getWhiteBox(); |
| // The number of deoptimizations after which a method will be made not-entrant |
| private static final int PerBytecodeTrapLimit = WB.getIntxVMFlag("PerBytecodeTrapLimit").intValue(); |
| // The number of interpreter invocations after which a decompiled method will be re-compiled. |
| private static final int Tier0InvokeNotifyFreq = (int)Math.pow(2, WB.getIntxVMFlag("Tier0InvokeNotifyFreqLog")); |
| // VM builds without JVMCI like x86_32 call the bimorphic inlining trap just 'bimorphic' |
| // while all the other builds with JVMCI call it 'bimorphic_or_optimized_type_check'. |
| // Only builds with JVMCI have the "EnableJVMCI" flag. |
| private static final boolean isJVMCISupported = (WB.getBooleanVMFlag("EnableJVMCI") != null); |
| private static final String bimorphicTrapName = isJVMCISupported ? "bimorphic_or_optimized_type_check" : "bimorphic"; |
| |
| static class Base { |
| void foo() {} |
| } |
| static class X extends Base { |
| void foo() {} |
| } |
| static class Y extends Base { |
| void foo() {} |
| } |
| |
| static void uncommonTrap(Base t) { |
| t.foo(); |
| } |
| |
| private static void printCounters(Method uncommonTrap_m, int invocations) { |
| System.out.println("-----------------------------------------------------------------"); |
| System.out.println("invocations=" + invocations + " " + |
| "method compiled=" + WB.isMethodCompiled(uncommonTrap_m) + " " + |
| "decompileCount=" + WB.getMethodDecompileCount(uncommonTrap_m) + "\n" + |
| "trapCount=" + WB.getMethodTrapCount(uncommonTrap_m) + " " + |
| "trapCount(class_check)=" + WB.getMethodTrapCount(uncommonTrap_m, "class_check") + " " + |
| "trapCount(" + bimorphicTrapName + ")=" + |
| WB.getMethodTrapCount(uncommonTrap_m, bimorphicTrapName) + "\n" + |
| "globalDeoptCount=" + WB.getDeoptCount() + " " + |
| "globalDeoptCount(class_check)=" + WB.getDeoptCount("class_check", null) + " " + |
| "globalDeoptCount(" + bimorphicTrapName + ")=" + |
| WB.getDeoptCount(bimorphicTrapName, null)); |
| System.out.println("-----------------------------------------------------------------"); |
| } |
| |
| private static void check(Method uncommonTrap_m, int invocations, boolean isCompiled, int decompileCount, |
| int trapCount, int trapCountClassCheck, int trapCountBimorphic, |
| int deoptCount, int deoptCountClassCheck, int deoptCountBimorphic) { |
| |
| printCounters(uncommonTrap_m, invocations); |
| |
| Asserts.assertEQ(isCompiled, WB.isMethodCompiled(uncommonTrap_m), |
| "Wrong compilation status."); |
| Asserts.assertEQ(decompileCount, WB.getMethodDecompileCount(uncommonTrap_m), |
| "Wrong number of decompilations."); |
| Asserts.assertEQ(trapCount, WB.getMethodTrapCount(uncommonTrap_m), |
| "Wrong number of traps."); |
| Asserts.assertEQ(trapCountClassCheck, WB.getMethodTrapCount(uncommonTrap_m, "class_check"), |
| "Wrong number of traps."); |
| Asserts.assertEQ(trapCountBimorphic, WB.getMethodTrapCount(uncommonTrap_m, bimorphicTrapName), |
| "Wrong number of traps."); |
| Asserts.assertEQ(deoptCount, WB.getDeoptCount(), |
| "Wrong number of deoptimizations."); |
| Asserts.assertEQ(deoptCountClassCheck, WB.getDeoptCount("class_check", null), |
| "Wrong number of class_check deoptimizations."); |
| Asserts.assertEQ(deoptCountBimorphic, WB.getDeoptCount(bimorphicTrapName, null), |
| "Wrong number of " + bimorphicTrapName + "deoptimizations."); |
| } |
| public static void main(String[] args) throws Exception { |
| |
| // Get a handle of the test method for usage with the WhiteBox API. |
| Method uncommonTrap_m = Decompile.class |
| .getDeclaredMethod("uncommonTrap", new Class[] { Base.class }); |
| |
| int invocations = 0; |
| Base b = new Base(); |
| // This is a little tricky :) We have to define 'x' already here otherwise |
| // the class 'X' won't be loaded and 'uncommonTrap()' will be compiled without |
| // a class check but a CHA dependency that class 'B' has no subtypes. |
| X x = new X(); |
| Y y = new Y(); |
| |
| // Warmup and compile with an object of type 'Base' as receiver, but don't invoke compiled code. |
| while(!WB.isMethodCompiled(uncommonTrap_m)) { |
| invocations++; |
| uncommonTrap(b); |
| } |
| check(uncommonTrap_m, invocations, true /* is_compiled */, 0 /* decompileCount */, |
| 0 /* trapCount */, 0 /* trapCountClassCheck */, 0 /* trapCountBimorphic */, |
| 0 /* deoptCount */, 0 /* deoptCountClassCheck */, 0 /* deoptCountBimorphic */); |
| |
| // Invoke compiled code 'PerBytecodeTrapLimit' times with an receiver object of type 'X'. |
| // This should deoptimize 'PerBytecodeTrapLimit' times and finally decompile the method. |
| for (int i = 0; i < PerBytecodeTrapLimit; i++) { |
| invocations++; |
| uncommonTrap(x); |
| } |
| check(uncommonTrap_m, invocations, false /* is_compiled */, 1 /* decompileCount */, |
| PerBytecodeTrapLimit /* trapCount */, PerBytecodeTrapLimit /* trapCountClassCheck */, 0 /* trapCountBimorphic */, |
| PerBytecodeTrapLimit /* deoptCount */, PerBytecodeTrapLimit /* deoptCountClassCheck */, 0 /* deoptCountBimorphic */); |
| |
| // Invoke the method 'Tier0InvokeNotifyFreq' more times with an receiver object of type 'X'. |
| // This should re-compile the method again with bimorphic inlining for receiver types 'Base' and 'X'. |
| for (int i = 0; i < Tier0InvokeNotifyFreq; i++) { |
| invocations++; |
| uncommonTrap(x); |
| } |
| check(uncommonTrap_m, invocations, true /* is_compiled */, 1 /* decompileCount */, |
| PerBytecodeTrapLimit /* trapCount */, PerBytecodeTrapLimit /* trapCountClassCheck */, 0 /* trapCountBimorphic */, |
| PerBytecodeTrapLimit /* deoptCount */, PerBytecodeTrapLimit /* deoptCountClassCheck */, 0 /* deoptCountBimorphic */); |
| |
| // Invoke compiled code 'PerBytecodeTrapLimit' times with an receiver object of type 'Y'. |
| // This should deoptimize 'PerBytecodeTrapLimit' times and finally decompile the method. |
| for (int i = 0; i < PerBytecodeTrapLimit; i++) { |
| invocations++; |
| uncommonTrap(y); |
| } |
| check(uncommonTrap_m, invocations, false /* is_compiled */, 2 /* decompileCount */, |
| 2*PerBytecodeTrapLimit /* trapCount */, PerBytecodeTrapLimit /* trapCountClassCheck */, PerBytecodeTrapLimit /* trapCountBimorphic */, |
| 2*PerBytecodeTrapLimit /* deoptCount */, PerBytecodeTrapLimit /* deoptCountClassCheck */, PerBytecodeTrapLimit /* deoptCountBimorphic */); |
| } |
| } |