--- old/test/compiler/tiered/NonTieredLevelsTest.java 2014-11-28 14:54:40.205474747 +0300 +++ new/test/compiler/tiered/NonTieredLevelsTest.java 2014-11-28 14:54:40.145474746 +0300 @@ -55,9 +55,7 @@ } public static void main(String[] args) throws Exception { - if (TIERED_COMPILATION) { - System.err.println("Test isn't applicable w/ enabled " - + "TieredCompilation. Skip test."); + if (CompilerWhiteBoxTest.skipOnTieredCompilation(true)) { return; } CompilerWhiteBoxTest.main(NonTieredLevelsTest::new, args); --- old/test/compiler/tiered/TieredLevelsTest.java 2014-11-28 14:54:40.797474755 +0300 +++ new/test/compiler/tiered/TieredLevelsTest.java 2014-11-28 14:54:40.729474754 +0300 @@ -36,15 +36,13 @@ */ public class TieredLevelsTest extends CompLevelsTest { public static void main(String[] args) throws Exception { - if (!TIERED_COMPILATION) { - System.err.println("Test isn't applicable w/ disabled " - + "TieredCompilation. Skip test."); + if (CompilerWhiteBoxTest.skipOnTieredCompilation(false)) { return; } CompilerWhiteBoxTest.main(TieredLevelsTest::new, args); } - private TieredLevelsTest(TestCase testCase) { + protected TieredLevelsTest(TestCase testCase) { super(testCase); // to prevent inlining of #method WHITE_BOX.testSetDontInlineMethod(method, true); @@ -77,14 +75,18 @@ } } - @Override protected void checkLevel(int expected, int actual) { if (expected == COMP_LEVEL_FULL_PROFILE && actual == COMP_LEVEL_LIMITED_PROFILE) { // for simple method full_profile may be replaced by limited_profile + if (IS_VERBOSE) { + System.out.printf("Level check: full profiling was replaced " + + "by limited profiling. Expected: %d, actual:%d", + expected, actual); + } return; } super.checkLevel(expected, actual); - } + } } --- old/test/compiler/whitebox/CompilerWhiteBoxTest.java 2014-11-28 14:54:41.093474759 +0300 +++ new/test/compiler/whitebox/CompilerWhiteBoxTest.java 2014-11-28 14:54:41.025474758 +0300 @@ -38,19 +38,19 @@ */ public abstract class CompilerWhiteBoxTest { /** {@code CompLevel::CompLevel_none} -- Interpreter */ - protected static int COMP_LEVEL_NONE = 0; + protected static final int COMP_LEVEL_NONE = 0; /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ - protected static int COMP_LEVEL_ANY = -1; + protected static final int COMP_LEVEL_ANY = -1; /** {@code CompLevel::CompLevel_simple} -- C1 */ - protected static int COMP_LEVEL_SIMPLE = 1; + protected static final int COMP_LEVEL_SIMPLE = 1; /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ - protected static int COMP_LEVEL_LIMITED_PROFILE = 2; + protected static final int COMP_LEVEL_LIMITED_PROFILE = 2; /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ - protected static int COMP_LEVEL_FULL_PROFILE = 3; + protected static final int COMP_LEVEL_FULL_PROFILE = 3; /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ - protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4; + protected static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; /** Maximal value for CompLevel */ - protected static int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; + protected static final int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; /** Instance of WhiteBox */ protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -336,14 +336,22 @@ System.out.printf("%n%s:%n", method); System.out.printf("\tcompilable:\t%b%n", WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, false)); - System.out.printf("\tcompiled:\t%b%n", - WHITE_BOX.isMethodCompiled(method, false)); + boolean isCompiled = WHITE_BOX.isMethodCompiled(method, false); + System.out.printf("\tcompiled:\t%b%n", isCompiled); + if (isCompiled) { + System.out.printf("\tcompile_id:\t%d%n", + NMethod.get(method, false).compile_id); + } System.out.printf("\tcomp_level:\t%d%n", WHITE_BOX.getMethodCompilationLevel(method, false)); System.out.printf("\tosr_compilable:\t%b%n", WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, true)); - System.out.printf("\tosr_compiled:\t%b%n", - WHITE_BOX.isMethodCompiled(method, true)); + isCompiled = WHITE_BOX.isMethodCompiled(method, true); + System.out.printf("\tosr_compiled:\t%b%n", isCompiled); + if (isCompiled) { + System.out.printf("\tosr_compile_id:\t%d%n", + NMethod.get(method, true).compile_id); + } System.out.printf("\tosr_comp_level:\t%d%n", WHITE_BOX.getMethodCompilationLevel(method, true)); System.out.printf("\tin_queue:\t%b%n", @@ -426,6 +434,22 @@ } return result; } + + /** + * Skip the test for the specified value of Tiered Compilation + * @param value of TieredCompilation the test should not run with + * @return {@code true} if the test should be skipped, + * {@code false} otherwise + */ + protected static boolean skipOnTieredCompilation(boolean value) { + if (value == CompilerWhiteBoxTest.TIERED_COMPILATION) { + System.err.println("Test isn't applicable w/ " + + (value ? "enabled" : "disabled") + + "TieredCompilation. Skip test."); + return true; + } + return false; + } } enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase { --- /dev/null 2014-10-07 15:00:54.062567032 +0400 +++ new/test/compiler/tiered/ConstantGettersTransitions.java 2014-11-28 14:54:41.301474762 +0300 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2014, Oracle and/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. + */ + +import java.lang.reflect.Executable; +import java.util.concurrent.Callable; + +/** + * @test ConstantGettersTransitions + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build ConstantGettersTransitions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,ConstantGettersTestCase$TrivialMethods::* + * -XX:+TieredCompilation -XX:CompilationPolicyChoice=2 + * ConstantGettersTransitions + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,ConstantGettersTestCase$TrivialMethods::* + * -XX:+TieredCompilation -XX:CompilationPolicyChoice=3 + * ConstantGettersTransitions + * @summary Test the correctness of compilation level transitions for constant getters methods + */ +public class ConstantGettersTransitions extends LevelTransitionTest { + public static void main(String[] args) { + if (CompilerWhiteBoxTest.skipOnTieredCompilation(false)) { + return; + } + + // run test cases + for (TestCase testCase : ConstantGettersTestCase.values()) { + new ConstantGettersTransitions(testCase).runTest(); + } + } + + @Override + protected boolean isTrivial() { + return true; + } + + private ConstantGettersTransitions(TestCase testCase) { + super(testCase); + } +} + +enum ConstantGettersTestCase implements CompilerWhiteBoxTest.TestCase { + ICONST_M1, + ICONST_0, + ICONST_1, + ICONST_2, + ICONST_3, + ICONST_4, + ICONST_5, + LCONST_0, + LCONST_1, + FCONST_0, + FCONST_1, + FCONST_2, + DCONST_0, + DCONST_1, + DCONST_W, + BYTE, + SHORT, + CHAR; + + private final Executable executable; + private final Callable callable; + + @Override + public Executable getExecutable() { + return executable; + } + + @Override + public Callable getCallable() { + return callable; + } + + @Override + public boolean isOsr() { + return false; + } + + private ConstantGettersTestCase() { + String name = "make" + this.name(); + this.executable = LevelTransitionTest.Helper.getMethod(TrivialMethods.class, name); + this.callable = LevelTransitionTest.Helper.getCallable(new TrivialMethods(), name); + } + + /** + * Contains methods that load constants with certain types of bytecodes + * See JVMS 2.11.2. Load and Store Instructions + * Note that it doesn't have a method for ldc_w instruction + */ + private static class TrivialMethods { + public static int makeICONST_M1() { + return -1; + } + + public static int makeICONST_0() { + return 0; + } + + public static int makeICONST_1() { + return 1; + } + + public static int makeICONST_2() { + return 2; + } + + public static int makeICONST_3() { + return 3; + } + + public static int makeICONST_4() { + return 4; + } + + public static int makeICONST_5() { + return 5; + } + + public static long makeLCONST_0() { + return 0L; + } + + public static long makeLCONST_1() { + return 1L; + } + + public static float makeFCONST_0() { + return 0F; + } + + public static float makeFCONST_1() { + return 1F; + } + + public static float makeFCONST_2() { + return 2F; + } + + public static double makeDCONST_0() { + return 0D; + } + + public static double makeDCONST_1() { + return 1D; + } + + public static double makeDCONST_W() { + // ldc2_w + return Double.MAX_VALUE; + } + + public static Object makeOBJECT() { + // aconst_null + return null; + } + + public static byte makeBYTE() { + // bipush + return (byte) 0x7F; + } + + public static short makeSHORT() { + // sipush + return (short) 0x7FFF; + } + + public static char makeCHAR() { + // ldc + return (char) 0xFFFF; + } + + public static boolean makeBOOLEAN() { + return true; + } + } +} --- /dev/null 2014-10-07 15:00:54.062567032 +0400 +++ new/test/compiler/tiered/LevelTransitionTest.java 2014-11-28 14:54:41.533474765 +0300 @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014, Oracle and/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. + */ + +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.Objects; +import java.util.concurrent.Callable; + +/** + * @test LevelTransitionTest + * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * @build LevelTransitionTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* + * -XX:CompileCommand=compileonly,ExtendedTestCase$CompileMethodHolder::* + * -XX:+TieredCompilation -XX:CompilationPolicyChoice=2 + * LevelTransitionTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* + * -XX:CompileCommand=compileonly,ExtendedTestCase$CompileMethodHolder::* + * -XX:+TieredCompilation -XX:CompilationPolicyChoice=3 + * LevelTransitionTest + * @summary Test the correctness of compilation level transitions for different methods + */ +public class LevelTransitionTest extends TieredLevelsTest { + /** Shows if method was profiled by being executed on levels 2 or 3 */ + protected boolean isMethodProfiled; + private int transitionCount; + + public static void main(String[] args) { + if (CompilerWhiteBoxTest.skipOnTieredCompilation(false)) { + return; + } + if (CompilerWhiteBoxTest.MODE.startsWith("compiled ")) { + System.err.printf("Warning: test is not applicable in %s%n", CompilerWhiteBoxTest.MODE); + return; + } + CompilerWhiteBoxTest.main(LevelTransitionTest::new, args); + + // run extended test cases + for (TestCase testCase : ExtendedTestCase.values()) { + new LevelTransitionTest(testCase).runTest(); + } + } + + protected LevelTransitionTest(TestCase testCase) { + super(testCase); + isMethodProfiled = testCase.isOsr(); // OSR methods were already profiled by warmup + transitionCount = 0; + } + + @Override + protected void test() throws Exception { + checkTransitions(); + deoptimize(); + printInfo(); + if (testCase.isOsr()) { + // needs reprofiling + isMethodProfiled = false; + } + checkTransitions(); + } + + /** + * Makes and verifies transitions between compilation levels + */ + protected void checkTransitions() { + checkNotCompiled(); + boolean finish = false; + while (!finish) { + System.out.printf("Level transition #%d%n", ++transitionCount); + int newLevel; + int current = getCompLevel(); + int expected = getNextLevel(current); + if (current == expected) { + // if we are on expected level, just execute it more + // to ensure that the level won't change + System.out.printf("Method %s is already on expected level %d%n", method, expected); + compile(); + newLevel = getCompLevel(); + finish = true; + } else { + newLevel = changeCompLevel(); + finish = false; + } + System.out.printf("Method %s is compiled on level %d. Expected level is %d%n", method, newLevel, expected); + checkLevel(expected, newLevel); + printInfo(); + }; + } + + /** + * Gets next expected level for the test case on each transition. + * + * @param currentLevel a level the test case is compiled on + * @return expected compilation level + */ + protected int getNextLevel(int currentLevel) { + int nextLevel = currentLevel; + switch (currentLevel) { + case CompilerWhiteBoxTest.COMP_LEVEL_NONE: + nextLevel = isMethodProfiled ? CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION + : CompilerWhiteBoxTest.COMP_LEVEL_FULL_PROFILE; + break; + case CompilerWhiteBoxTest.COMP_LEVEL_LIMITED_PROFILE: + case CompilerWhiteBoxTest.COMP_LEVEL_FULL_PROFILE: + nextLevel = CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION; + isMethodProfiled = true; + break; + } + nextLevel = isTrivial() ? CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE : nextLevel; + return Math.min(nextLevel, CompilerWhiteBoxTest.TIERED_STOP_AT_LEVEL); + } + + /** + * Determines if tested method should be handled as trivial + * + * @return {@code true} for trivial methods, {@code false} otherwise + */ + protected boolean isTrivial() { + return testCase == ExtendedTestCase.ACCESSOR_TEST + || testCase == SimpleTestCase.METHOD_TEST + || testCase == SimpleTestCase.STATIC_TEST + || (testCase == ExtendedTestCase.TRIVIAL_CODE_TEST && isMethodProfiled); + } + + /** + * Invokes {@linkplain #method} until its compilation level is changed. + * Note that if the level won't change, it will be an endless loop + * + * @return compilation level the {@linkplain #method} was compiled on + */ + protected int changeCompLevel() { + int currentLevel = getCompLevel(); + int newLevel = currentLevel; + int result = 0; + while (currentLevel == newLevel) { + result = compile(1); + if (WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { + newLevel = getCompLevel(); + } + } + return newLevel; + } + + protected static class Helper { + /** + * Gets method from a specified class using its name + * + * @param aClass type method belongs to + * @param name the name of the method + * @return {@link Method} that represents corresponding class method + */ + public static Method getMethod(Class aClass, String name) { + Method method; + try { + method = aClass.getDeclaredMethod(name); + } catch (NoSuchMethodException e) { + throw new Error("TESTBUG: Unable to get method " + name, e); + } + return method; + } + + /** + * Gets {@link Callable} that invokes given method from the given object + * + * @param object the object the specified method is invoked from + * @param name the name of the method + */ + public static Callable getCallable(Object object, String name) { + Method method = getMethod(object.getClass(), name); + return () -> { + try { + return Objects.hashCode(method.invoke(object)); + } catch (ReflectiveOperationException e) { + throw new Error("TESTBUG: Invocation failure", e); + } + }; + } + } +} + +enum ExtendedTestCase implements CompilerWhiteBoxTest.TestCase { + ACCESSOR_TEST("accessor"), + NONTRIVIAL_METHOD_TEST("nonTrivialMethod"), + TRIVIAL_CODE_TEST("trivialCode"); + + private final Executable executable; + private final Callable callable; + + @Override + public Executable getExecutable() { + return executable; + } + + @Override + public Callable getCallable() { + return callable; + } + + @Override + public boolean isOsr() { + return false; + } + + private ExtendedTestCase(String methodName) { + this.executable = LevelTransitionTest.Helper.getMethod(CompileMethodHolder.class, methodName); + this.callable = LevelTransitionTest.Helper.getCallable(new CompileMethodHolder(), methodName); + } + + private static class CompileMethodHolder { + private final int iter = 10; + private int field = 42; + + /** Non-trivial method for threshold policy: contains loops */ + public int nonTrivialMethod() { + int acc = 0; + for (int i = 0; i < iter; i++) { + acc += i; + } + return acc; + } + + /** Field accessor method */ + public int accessor() { + return field; + } + + /** Method considered as trivial by amount of code */ + public int trivialCode() { + int var = 0xBAAD_C0DE; + var *= field; + return var; + } + } +}