|  | /* | 
|  | * Copyright (c) 2013, 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 com.sun.management.HotSpotDiagnosticMXBean; | 
|  | import com.sun.management.VMOption; | 
|  | import sun.hotspot.WhiteBox; | 
|  | import sun.hotspot.code.NMethod; | 
|  | import sun.management.ManagementFactoryHelper; | 
|  |  | 
|  | import java.lang.reflect.Constructor; | 
|  | import java.lang.reflect.Executable; | 
|  | import java.lang.reflect.Method; | 
|  | import java.util.Objects; | 
|  | import java.util.concurrent.Callable; | 
|  | import java.util.function.Function; | 
|  |  | 
|  | /** | 
|  | * Abstract class for WhiteBox testing of JIT. | 
|  | * | 
|  | * @author igor.ignatyev@oracle.com | 
|  | */ | 
|  | public abstract class CompilerWhiteBoxTest { | 
|  | /** {@code CompLevel::CompLevel_none} -- Interpreter */ | 
|  | protected static int COMP_LEVEL_NONE = 0; | 
|  | /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ | 
|  | protected static int COMP_LEVEL_ANY = -1; | 
|  | /** {@code CompLevel::CompLevel_simple} -- C1 */ | 
|  | protected static int COMP_LEVEL_SIMPLE = 1; | 
|  | /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ | 
|  | protected static int COMP_LEVEL_LIMITED_PROFILE = 2; | 
|  | /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ | 
|  | protected static int COMP_LEVEL_FULL_PROFILE = 3; | 
|  | /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ | 
|  | protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4; | 
|  | /** Maximal value for CompLevel */ | 
|  | protected static int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; | 
|  |  | 
|  | /** Instance of WhiteBox */ | 
|  | protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); | 
|  | /** Value of {@code -XX:CompileThreshold} */ | 
|  | protected static final int COMPILE_THRESHOLD | 
|  | = Integer.parseInt(getVMOption("CompileThreshold", "10000")); | 
|  | /** Value of {@code -XX:BackgroundCompilation} */ | 
|  | protected static final boolean BACKGROUND_COMPILATION | 
|  | = Boolean.valueOf(getVMOption("BackgroundCompilation", "true")); | 
|  | /** Value of {@code -XX:TieredCompilation} */ | 
|  | protected static final boolean TIERED_COMPILATION | 
|  | = Boolean.valueOf(getVMOption("TieredCompilation", "false")); | 
|  | /** Value of {@code -XX:TieredStopAtLevel} */ | 
|  | protected static final int TIERED_STOP_AT_LEVEL | 
|  | = Integer.parseInt(getVMOption("TieredStopAtLevel", "0")); | 
|  | /** Flag for verbose output, true if {@code -Dverbose} specified */ | 
|  | protected static final boolean IS_VERBOSE | 
|  | = System.getProperty("verbose") != null; | 
|  | /** invocation count to trigger compilation */ | 
|  | protected static final int THRESHOLD; | 
|  | /** invocation count to trigger OSR compilation */ | 
|  | protected static final long BACKEDGE_THRESHOLD; | 
|  | /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */ | 
|  | protected static final String MODE = System.getProperty("java.vm.info"); | 
|  |  | 
|  | static { | 
|  | if (TIERED_COMPILATION) { | 
|  | BACKEDGE_THRESHOLD = THRESHOLD = 150000; | 
|  | } else { | 
|  | THRESHOLD = COMPILE_THRESHOLD; | 
|  | BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption( | 
|  | "OnStackReplacePercentage")); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns value of VM option. | 
|  | * | 
|  | * @param name option's name | 
|  | * @return value of option or {@code null}, if option doesn't exist | 
|  | * @throws NullPointerException if name is null | 
|  | */ | 
|  | protected static String getVMOption(String name) { | 
|  | Objects.requireNonNull(name); | 
|  | HotSpotDiagnosticMXBean diagnostic | 
|  | = ManagementFactoryHelper.getDiagnosticMXBean(); | 
|  | VMOption tmp; | 
|  | try { | 
|  | tmp = diagnostic.getVMOption(name); | 
|  | } catch (IllegalArgumentException e) { | 
|  | tmp = null; | 
|  | } | 
|  | return (tmp == null ? null : tmp.getValue()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns value of VM option or default value. | 
|  | * | 
|  | * @param name         option's name | 
|  | * @param defaultValue default value | 
|  | * @return value of option or {@code defaultValue}, if option doesn't exist | 
|  | * @throws NullPointerException if name is null | 
|  | * @see #getVMOption(String) | 
|  | */ | 
|  | protected static String getVMOption(String name, String defaultValue) { | 
|  | String result = getVMOption(name); | 
|  | return result == null ? defaultValue : result; | 
|  | } | 
|  |  | 
|  | /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */ | 
|  | protected static boolean isC1Compile(int compLevel) { | 
|  | return (compLevel > COMP_LEVEL_NONE) | 
|  | && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION); | 
|  | } | 
|  |  | 
|  | /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */ | 
|  | protected static boolean isC2Compile(int compLevel) { | 
|  | return compLevel == COMP_LEVEL_FULL_OPTIMIZATION; | 
|  | } | 
|  |  | 
|  | protected static void main( | 
|  | Function<TestCase, CompilerWhiteBoxTest> constructor, | 
|  | String[] args) { | 
|  | if (args.length == 0) { | 
|  | for (TestCase test : SimpleTestCase.values()) { | 
|  | constructor.apply(test).runTest(); | 
|  | } | 
|  | } else { | 
|  | for (String name : args) { | 
|  | constructor.apply(SimpleTestCase.valueOf(name)).runTest(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** tested method */ | 
|  | protected final Executable method; | 
|  | protected final TestCase testCase; | 
|  |  | 
|  | /** | 
|  | * Constructor. | 
|  | * | 
|  | * @param testCase object, that contains tested method and way to invoke it. | 
|  | */ | 
|  | protected CompilerWhiteBoxTest(TestCase testCase) { | 
|  | Objects.requireNonNull(testCase); | 
|  | System.out.println("TEST CASE:" + testCase.name()); | 
|  | method = testCase.getExecutable(); | 
|  | this.testCase = testCase; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Template method for testing. Prints tested method's info before | 
|  | * {@linkplain #test()} and after {@linkplain #test()} or on thrown | 
|  | * exception. | 
|  | * | 
|  | * @throws RuntimeException if method {@linkplain #test()} throws any | 
|  | *                          exception | 
|  | * @see #test() | 
|  | */ | 
|  | protected final void runTest() { | 
|  | if (ManagementFactoryHelper.getCompilationMXBean() == null) { | 
|  | System.err.println( | 
|  | "Warning: test is not applicable in interpreted mode"); | 
|  | return; | 
|  | } | 
|  | System.out.println("at test's start:"); | 
|  | printInfo(); | 
|  | try { | 
|  | test(); | 
|  | } catch (Exception e) { | 
|  | System.out.printf("on exception '%s':", e.getMessage()); | 
|  | printInfo(); | 
|  | e.printStackTrace(); | 
|  | if (e instanceof RuntimeException) { | 
|  | throw (RuntimeException) e; | 
|  | } | 
|  | throw new RuntimeException(e); | 
|  | } | 
|  | System.out.println("at test's end:"); | 
|  | printInfo(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks, that {@linkplain #method} is not compiled at the given compilation | 
|  | * level or above. | 
|  | * | 
|  | * @param compLevel | 
|  | * | 
|  | * @throws RuntimeException if {@linkplain #method} is in compiler queue or | 
|  | *                          is compiled, or if {@linkplain #method} has zero | 
|  | *                          compilation level. | 
|  | */ | 
|  | protected final void checkNotCompiled(int compLevel) { | 
|  | if (WHITE_BOX.isMethodQueuedForCompilation(method)) { | 
|  | throw new RuntimeException(method + " must not be in queue"); | 
|  | } | 
|  | if (WHITE_BOX.getMethodCompilationLevel(method, false) >= compLevel) { | 
|  | throw new RuntimeException(method + " comp_level must be >= maxCompLevel"); | 
|  | } | 
|  | if (WHITE_BOX.getMethodCompilationLevel(method, true) >= compLevel) { | 
|  | throw new RuntimeException(method + " osr_comp_level must be >= maxCompLevel"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks, that {@linkplain #method} is not compiled. | 
|  | * | 
|  | * @throws RuntimeException if {@linkplain #method} is in compiler queue or | 
|  | *                          is compiled, or if {@linkplain #method} has zero | 
|  | *                          compilation level. | 
|  | */ | 
|  | protected final void checkNotCompiled() { | 
|  | checkNotCompiled(true); | 
|  | checkNotCompiled(false); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks, that {@linkplain #method} is not (OSR-)compiled. | 
|  | * | 
|  | * @param isOsr Check for OSR compilation if true | 
|  | * @throws RuntimeException if {@linkplain #method} is in compiler queue or | 
|  | *                          is compiled, or if {@linkplain #method} has zero | 
|  | *                          compilation level. | 
|  | */ | 
|  | protected final void checkNotCompiled(boolean isOsr) { | 
|  | waitBackgroundCompilation(); | 
|  | if (WHITE_BOX.isMethodQueuedForCompilation(method)) { | 
|  | throw new RuntimeException(method + " must not be in queue"); | 
|  | } | 
|  | if (WHITE_BOX.isMethodCompiled(method, isOsr)) { | 
|  | throw new RuntimeException(method + " must not be " + | 
|  | (isOsr ? "osr_" : "") + "compiled"); | 
|  | } | 
|  | if (WHITE_BOX.getMethodCompilationLevel(method, isOsr) != 0) { | 
|  | throw new RuntimeException(method + (isOsr ? " osr_" : " ") + | 
|  | "comp_level must be == 0"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Checks, that {@linkplain #method} is compiled. | 
|  | * | 
|  | * @throws RuntimeException if {@linkplain #method} isn't in compiler queue | 
|  | *                          and isn't compiled, or if {@linkplain #method} | 
|  | *                          has nonzero compilation level | 
|  | */ | 
|  | protected final void checkCompiled() { | 
|  | final long start = System.currentTimeMillis(); | 
|  | waitBackgroundCompilation(); | 
|  | if (WHITE_BOX.isMethodQueuedForCompilation(method)) { | 
|  | System.err.printf("Warning: %s is still in queue after %dms%n", | 
|  | method, System.currentTimeMillis() - start); | 
|  | return; | 
|  | } | 
|  | if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { | 
|  | throw new RuntimeException(method + " must be " | 
|  | + (testCase.isOsr() ? "osr_" : "") + "compiled"); | 
|  | } | 
|  | if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()) | 
|  | == 0) { | 
|  | throw new RuntimeException(method | 
|  | + (testCase.isOsr() ? " osr_" : " ") | 
|  | + "comp_level must be != 0"); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected final void deoptimize() { | 
|  | WHITE_BOX.deoptimizeMethod(method, testCase.isOsr()); | 
|  | if (testCase.isOsr()) { | 
|  | WHITE_BOX.deoptimizeMethod(method, false); | 
|  | } | 
|  | } | 
|  |  | 
|  | protected final int getCompLevel() { | 
|  | NMethod nm = NMethod.get(method, testCase.isOsr()); | 
|  | return nm == null ? COMP_LEVEL_NONE : nm.comp_level; | 
|  | } | 
|  |  | 
|  | protected final boolean isCompilable() { | 
|  | return WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, | 
|  | testCase.isOsr()); | 
|  | } | 
|  |  | 
|  | protected final boolean isCompilable(int compLevel) { | 
|  | return WHITE_BOX | 
|  | .isMethodCompilable(method, compLevel, testCase.isOsr()); | 
|  | } | 
|  |  | 
|  | protected final void makeNotCompilable() { | 
|  | WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY, | 
|  | testCase.isOsr()); | 
|  | } | 
|  |  | 
|  | protected final void makeNotCompilable(int compLevel) { | 
|  | WHITE_BOX.makeMethodNotCompilable(method, compLevel, testCase.isOsr()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Waits for completion of background compilation of {@linkplain #method}. | 
|  | */ | 
|  | protected final void waitBackgroundCompilation() { | 
|  | waitBackgroundCompilation(method); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Waits for completion of background compilation of the given executable. | 
|  | * | 
|  | * @param executable Executable | 
|  | */ | 
|  | protected static final void waitBackgroundCompilation(Executable executable) { | 
|  | if (!BACKGROUND_COMPILATION) { | 
|  | return; | 
|  | } | 
|  | final Object obj = new Object(); | 
|  | for (int i = 0; i < 10 | 
|  | && WHITE_BOX.isMethodQueuedForCompilation(executable); ++i) { | 
|  | synchronized (obj) { | 
|  | try { | 
|  | obj.wait(1000); | 
|  | } catch (InterruptedException e) { | 
|  | Thread.currentThread().interrupt(); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Prints information about {@linkplain #method}. | 
|  | */ | 
|  | protected final void printInfo() { | 
|  | 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)); | 
|  | 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)); | 
|  | System.out.printf("\tosr_comp_level:\t%d%n", | 
|  | WHITE_BOX.getMethodCompilationLevel(method, true)); | 
|  | System.out.printf("\tin_queue:\t%b%n", | 
|  | WHITE_BOX.isMethodQueuedForCompilation(method)); | 
|  | System.out.printf("compile_queues_size:\t%d%n%n", | 
|  | WHITE_BOX.getCompileQueuesSize()); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Executes testing. | 
|  | */ | 
|  | protected abstract void test() throws Exception; | 
|  |  | 
|  | /** | 
|  | * Tries to trigger compilation of {@linkplain #method} by call | 
|  | * {@linkplain TestCase#getCallable()} enough times. | 
|  | * | 
|  | * @return accumulated result | 
|  | * @see #compile(int) | 
|  | */ | 
|  | protected final int compile() { | 
|  | if (testCase.isOsr()) { | 
|  | return compile(1); | 
|  | } else { | 
|  | return compile(THRESHOLD); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Tries to trigger compilation of {@linkplain #method} by call | 
|  | * {@linkplain TestCase#getCallable()} specified times. | 
|  | * | 
|  | * @param count invocation count | 
|  | * @return accumulated result | 
|  | */ | 
|  | protected final int compile(int count) { | 
|  | int result = 0; | 
|  | Integer tmp; | 
|  | for (int i = 0; i < count; ++i) { | 
|  | try { | 
|  | tmp = testCase.getCallable().call(); | 
|  | } catch (Exception e) { | 
|  | tmp = null; | 
|  | } | 
|  | result += tmp == null ? 0 : tmp; | 
|  | } | 
|  | if (IS_VERBOSE) { | 
|  | System.out.println("method was invoked " + count + " times"); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Utility interface provides tested method and object to invoke it. | 
|  | */ | 
|  | public interface TestCase { | 
|  | /** the name of test case */ | 
|  | String name(); | 
|  |  | 
|  | /** tested method */ | 
|  | Executable getExecutable(); | 
|  |  | 
|  | /** object to invoke {@linkplain #getExecutable()} */ | 
|  | Callable<Integer> getCallable(); | 
|  |  | 
|  | /** flag for OSR test case */ | 
|  | boolean isOsr(); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * @return {@code true} if the current test case is OSR and the mode is | 
|  | *          Xcomp, otherwise {@code false} | 
|  | */ | 
|  | protected boolean skipXcompOSR() { | 
|  | boolean result =  testCase.isOsr() | 
|  | && CompilerWhiteBoxTest.MODE.startsWith("compiled "); | 
|  | if (result && IS_VERBOSE) { | 
|  | System.err.printf("Warning: %s is not applicable in %s%n", | 
|  | testCase.name(), CompilerWhiteBoxTest.MODE); | 
|  | } | 
|  | return result; | 
|  | } | 
|  | } | 
|  |  | 
|  | enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase { | 
|  | /** constructor test case */ | 
|  | CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false), | 
|  | /** method test case */ | 
|  | METHOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), | 
|  | /** static method test case */ | 
|  | STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false), | 
|  | /** OSR constructor test case */ | 
|  | OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, | 
|  | Helper.OSR_CONSTRUCTOR_CALLABLE, true), | 
|  | /** OSR method test case */ | 
|  | OSR_METHOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), | 
|  | /** OSR static method test case */ | 
|  | OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); | 
|  |  | 
|  | private final Executable executable; | 
|  | private final Callable<Integer> callable; | 
|  | private final boolean isOsr; | 
|  |  | 
|  | private SimpleTestCase(Executable executable, Callable<Integer> callable, | 
|  | boolean isOsr) { | 
|  | this.executable = executable; | 
|  | this.callable = callable; | 
|  | this.isOsr = isOsr; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public Executable getExecutable() { | 
|  | return executable; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public Callable<Integer> getCallable() { | 
|  | return callable; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean isOsr() { | 
|  | return isOsr; | 
|  | } | 
|  |  | 
|  | private static class Helper { | 
|  |  | 
|  | private static final Callable<Integer> CONSTRUCTOR_CALLABLE | 
|  | = new Callable<Integer>() { | 
|  | @Override | 
|  | public Integer call() throws Exception { | 
|  | return new Helper(1337).hashCode(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | private static final Callable<Integer> METHOD_CALLABLE | 
|  | = new Callable<Integer>() { | 
|  | private final Helper helper = new Helper(); | 
|  |  | 
|  | @Override | 
|  | public Integer call() throws Exception { | 
|  | return helper.method(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | private static final Callable<Integer> STATIC_CALLABLE | 
|  | = new Callable<Integer>() { | 
|  | @Override | 
|  | public Integer call() throws Exception { | 
|  | return staticMethod(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | private static final Callable<Integer> OSR_CONSTRUCTOR_CALLABLE | 
|  | = new Callable<Integer>() { | 
|  | @Override | 
|  | public Integer call() throws Exception { | 
|  | return new Helper(null, CompilerWhiteBoxTest.BACKEDGE_THRESHOLD).hashCode(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | private static final Callable<Integer> OSR_METHOD_CALLABLE | 
|  | = new Callable<Integer>() { | 
|  | private final Helper helper = new Helper(); | 
|  |  | 
|  | @Override | 
|  | public Integer call() throws Exception { | 
|  | return helper.osrMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); | 
|  | } | 
|  | }; | 
|  |  | 
|  | private static final Callable<Integer> OSR_STATIC_CALLABLE | 
|  | = new Callable<Integer>() { | 
|  | @Override | 
|  | public Integer call() throws Exception { | 
|  | return osrStaticMethod(CompilerWhiteBoxTest.BACKEDGE_THRESHOLD); | 
|  | } | 
|  | }; | 
|  |  | 
|  | private static final Constructor CONSTRUCTOR; | 
|  | private static final Constructor OSR_CONSTRUCTOR; | 
|  | private static final Method METHOD; | 
|  | private static final Method STATIC; | 
|  | private static final Method OSR_METHOD; | 
|  | private static final Method OSR_STATIC; | 
|  |  | 
|  | static { | 
|  | try { | 
|  | CONSTRUCTOR = Helper.class.getDeclaredConstructor(int.class); | 
|  | } catch (NoSuchMethodException | SecurityException e) { | 
|  | throw new RuntimeException( | 
|  | "exception on getting method Helper.<init>(int)", e); | 
|  | } | 
|  | try { | 
|  | OSR_CONSTRUCTOR = Helper.class.getDeclaredConstructor( | 
|  | Object.class, long.class); | 
|  | } catch (NoSuchMethodException | SecurityException e) { | 
|  | throw new RuntimeException( | 
|  | "exception on getting method Helper.<init>(Object, long)", e); | 
|  | } | 
|  | METHOD = getMethod("method"); | 
|  | STATIC = getMethod("staticMethod"); | 
|  | OSR_METHOD = getMethod("osrMethod", long.class); | 
|  | OSR_STATIC = getMethod("osrStaticMethod", long.class); | 
|  | } | 
|  |  | 
|  | private static Method getMethod(String name, Class<?>... parameterTypes) { | 
|  | try { | 
|  | return Helper.class.getDeclaredMethod(name, parameterTypes); | 
|  | } catch (NoSuchMethodException | SecurityException e) { | 
|  | throw new RuntimeException( | 
|  | "exception on getting method Helper." + name, e); | 
|  | } | 
|  | } | 
|  |  | 
|  | private static int staticMethod() { | 
|  | return 1138; | 
|  | } | 
|  |  | 
|  | private int method() { | 
|  | return 42; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Deoptimizes all non-osr versions of the given executable after | 
|  | * compilation finished. | 
|  | * | 
|  | * @param e Executable | 
|  | * @throws Exception | 
|  | */ | 
|  | private static void waitAndDeoptimize(Executable e) { | 
|  | CompilerWhiteBoxTest.waitBackgroundCompilation(e); | 
|  | if (WhiteBox.getWhiteBox().isMethodQueuedForCompilation(e)) { | 
|  | throw new RuntimeException(e + " must not be in queue"); | 
|  | } | 
|  | // Deoptimize non-osr versions of executable | 
|  | WhiteBox.getWhiteBox().deoptimizeMethod(e, false); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Executes the method multiple times to make sure we have | 
|  | * enough profiling information before triggering an OSR | 
|  | * compilation. Otherwise the C2 compiler may add uncommon traps. | 
|  | * | 
|  | * @param m Method to be executed | 
|  | * @return Number of times the method was executed | 
|  | * @throws Exception | 
|  | */ | 
|  | private static int warmup(Method m) throws Exception { | 
|  | waitAndDeoptimize(m); | 
|  | Helper helper = new Helper(); | 
|  | int result = 0; | 
|  | for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { | 
|  | result += (int)m.invoke(helper, 1); | 
|  | } | 
|  | // Wait to make sure OSR compilation is not blocked by | 
|  | // non-OSR compilation in the compile queue | 
|  | CompilerWhiteBoxTest.waitBackgroundCompilation(m); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Executes the constructor multiple times to make sure we | 
|  | * have enough profiling information before triggering an OSR | 
|  | * compilation. Otherwise the C2 compiler may add uncommon traps. | 
|  | * | 
|  | * @param c Constructor to be executed | 
|  | * @return Number of times the constructor was executed | 
|  | * @throws Exception | 
|  | */ | 
|  | private static int warmup(Constructor c) throws Exception { | 
|  | waitAndDeoptimize(c); | 
|  | int result = 0; | 
|  | for (long i = 0; i < CompilerWhiteBoxTest.THRESHOLD; ++i) { | 
|  | result += c.newInstance(null, 1).hashCode(); | 
|  | } | 
|  | // Wait to make sure OSR compilation is not blocked by | 
|  | // non-OSR compilation in the compile queue | 
|  | CompilerWhiteBoxTest.waitBackgroundCompilation(c); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | private static int osrStaticMethod(long limit) throws Exception { | 
|  | int result = 0; | 
|  | if (limit != 1) { | 
|  | result = warmup(OSR_STATIC); | 
|  | } | 
|  | // Trigger osr compilation | 
|  | for (long i = 0; i < limit; ++i) { | 
|  | result += staticMethod(); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | private int osrMethod(long limit) throws Exception { | 
|  | int result = 0; | 
|  | if (limit != 1) { | 
|  | result = warmup(OSR_METHOD); | 
|  | } | 
|  | // Trigger osr compilation | 
|  | for (long i = 0; i < limit; ++i) { | 
|  | result += method(); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | private final int x; | 
|  |  | 
|  | // for method and OSR method test case | 
|  | public Helper() { | 
|  | x = 0; | 
|  | } | 
|  |  | 
|  | // for OSR constructor test case | 
|  | private Helper(Object o, long limit) throws Exception { | 
|  | int result = 0; | 
|  | if (limit != 1) { | 
|  | result = warmup(OSR_CONSTRUCTOR); | 
|  | } | 
|  | // Trigger osr compilation | 
|  | for (long i = 0; i < limit; ++i) { | 
|  | result += method(); | 
|  | } | 
|  | x = result; | 
|  | } | 
|  |  | 
|  | // for constructor test case | 
|  | private Helper(int x) { | 
|  | this.x = x; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | return x; | 
|  | } | 
|  | } | 
|  | } |