303757b3a0
Reviewed-by: kvn, roland
172 lines
9.1 KiB
Java
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 */);
|
|
}
|
|
}
|