jdk-24/test/hotspot/jtreg/compiler/uncommontrap/Decompile.java
2023-11-21 07:18:04 +00:00

172 lines
9.1 KiB
Java

/*
* 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 */);
}
}