1 /* 2 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import sun.hotspot.WhiteBox; 25 import sun.hotspot.code.NMethod; 26 27 import java.lang.reflect.Constructor; 28 import java.lang.reflect.Executable; 29 import java.lang.reflect.Method; 30 import java.util.Objects; 31 import java.util.concurrent.Callable; 32 import java.util.function.Function; 33 34 /** 35 * Abstract class for WhiteBox testing of JIT. 36 * 37 * @author igor.ignatyev@oracle.com 38 */ 39 public abstract class CompilerWhiteBoxTest { 40 /** {@code CompLevel::CompLevel_none} -- Interpreter */ 41 protected static int COMP_LEVEL_NONE = 0; 42 /** {@code CompLevel::CompLevel_any}, {@code CompLevel::CompLevel_all} */ 43 protected static int COMP_LEVEL_ANY = -1; 44 /** {@code CompLevel::CompLevel_simple} -- C1 */ 45 protected static int COMP_LEVEL_SIMPLE = 1; 46 /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ 47 protected static int COMP_LEVEL_LIMITED_PROFILE = 2; 48 /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ 49 protected static int COMP_LEVEL_FULL_PROFILE = 3; 50 /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ 51 protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4; 52 /** Maximal value for CompLevel */ 53 protected static int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; 54 55 /** Instance of WhiteBox */ 56 protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 57 /** Value of {@code -XX:CompileThreshold} */ 58 protected static final int COMPILE_THRESHOLD 59 = Integer.parseInt(getVMOption("CompileThreshold", "10000")); 60 /** Value of {@code -XX:BackgroundCompilation} */ 61 protected static final boolean BACKGROUND_COMPILATION 62 = Boolean.valueOf(getVMOption("BackgroundCompilation", "true")); 63 /** Value of {@code -XX:TieredCompilation} */ 64 protected static final boolean TIERED_COMPILATION 65 = Boolean.valueOf(getVMOption("TieredCompilation", "false")); 66 /** Value of {@code -XX:TieredStopAtLevel} */ 67 protected static final int TIERED_STOP_AT_LEVEL 68 = Integer.parseInt(getVMOption("TieredStopAtLevel", "0")); 69 /** Flag for verbose output, true if {@code -Dverbose} specified */ 70 protected static final boolean IS_VERBOSE 71 = System.getProperty("verbose") != null; 72 /** count of invocation to triger compilation */ 73 protected static final int THRESHOLD; 74 /** count of invocation to triger OSR compilation */ 75 protected static final long BACKEDGE_THRESHOLD; 76 /** Value of {@code java.vm.info} (interpreted|mixed|comp mode) */ 77 protected static final String MODE = System.getProperty("java.vm.info"); 78 79 static { 80 if (TIERED_COMPILATION) { 81 BACKEDGE_THRESHOLD = THRESHOLD = 150000; 82 } else { 83 THRESHOLD = COMPILE_THRESHOLD; 84 BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption( 85 "OnStackReplacePercentage")); 86 } 87 } 88 89 /** 90 * Returns value of VM option. 91 * 92 * @param name option's name 93 * @return value of option or {@code null}, if option doesn't exist 94 * @throws NullPointerException if name is null 95 */ 96 protected static String getVMOption(String name) { 97 Objects.requireNonNull(name); 98 return Objects.toString(WHITE_BOX.getVMFlag(name), null); 99 } 100 101 /** 102 * Returns value of VM option or default value. 103 * 104 * @param name option's name 105 * @param defaultValue default value 106 * @return value of option or {@code defaultValue}, if option doesn't exist 107 * @throws NullPointerException if name is null 108 * @see #getVMOption(String) 109 */ 110 protected static String getVMOption(String name, String defaultValue) { 111 String result = getVMOption(name); 112 return result == null ? defaultValue : result; 113 } 114 115 /** copy of is_c1_compile(int) from utilities/globalDefinitions.hpp */ 116 protected static boolean isC1Compile(int compLevel) { 117 return (compLevel > COMP_LEVEL_NONE) 118 && (compLevel < COMP_LEVEL_FULL_OPTIMIZATION); 119 } 120 121 /** copy of is_c2_compile(int) from utilities/globalDefinitions.hpp */ 122 protected static boolean isC2Compile(int compLevel) { 123 return compLevel == COMP_LEVEL_FULL_OPTIMIZATION; 124 } 125 126 protected static void main( 127 Function<TestCase, CompilerWhiteBoxTest> constructor, 128 String[] args) { 129 if (args.length == 0) { 130 for (TestCase test : SimpleTestCase.values()) { 131 constructor.apply(test).runTest(); 132 } 133 } else { 134 for (String name : args) { 135 constructor.apply(SimpleTestCase.valueOf(name)).runTest(); 136 } 137 } 138 } 139 140 /** tested method */ 141 protected final Executable method; 142 protected final TestCase testCase; 143 144 /** 145 * Constructor. 146 * 147 * @param testCase object, that contains tested method and way to invoke it. 148 */ 149 protected CompilerWhiteBoxTest(TestCase testCase) { 150 Objects.requireNonNull(testCase); 151 System.out.println("TEST CASE:" + testCase.name()); 152 method = testCase.getExecutable(); 153 this.testCase = testCase; 154 } 155 156 /** 157 * Template method for testing. Prints tested method's info before 158 * {@linkplain #test()} and after {@linkplain #test()} or on thrown 159 * exception. 160 * 161 * @throws RuntimeException if method {@linkplain #test()} throws any 162 * exception 163 * @see #test() 164 */ 165 protected final void runTest() { 166 if (CompilerWhiteBoxTest.MODE.startsWith("interpreted ")) { 167 System.err.println( 168 "Warning: test is not applicable in interpreted mode"); 169 return; 170 } 171 System.out.println("at test's start:"); 172 printInfo(); 173 try { 174 test(); 175 } catch (Exception e) { 176 System.out.printf("on exception '%s':", e.getMessage()); 177 printInfo(); 178 e.printStackTrace(); 179 if (e instanceof RuntimeException) { 180 throw (RuntimeException) e; 181 } 182 throw new RuntimeException(e); 183 } 184 System.out.println("at test's end:"); 185 printInfo(); 186 } 187 188 /** 189 * Checks, that {@linkplain #method} is not compiled at the given compilation 190 * level or above. 191 * 192 * @param compLevel 193 * 194 * @throws RuntimeException if {@linkplain #method} is in compiler queue or 195 * is compiled, or if {@linkplain #method} has zero 196 * compilation level. 197 */ 198 199 protected final void checkNotCompiled(int compLevel) { 200 if (WHITE_BOX.isMethodQueuedForCompilation(method)) { 201 throw new RuntimeException(method + " must not be in queue"); 202 } 203 if (WHITE_BOX.getMethodCompilationLevel(method, false) >= compLevel) { 204 throw new RuntimeException(method + " comp_level must be >= maxCompLevel"); 205 } 206 if (WHITE_BOX.getMethodCompilationLevel(method, true) >= compLevel) { 207 throw new RuntimeException(method + " osr_comp_level must be >= maxCompLevel"); 208 } 209 } 210 211 /** 212 * Checks, that {@linkplain #method} is not compiled. 213 * 214 * @throws RuntimeException if {@linkplain #method} is in compiler queue or 215 * is compiled, or if {@linkplain #method} has zero 216 * compilation level. 217 */ 218 protected final void checkNotCompiled() { 219 if (WHITE_BOX.isMethodQueuedForCompilation(method)) { 220 throw new RuntimeException(method + " must not be in queue"); 221 } 222 if (WHITE_BOX.isMethodCompiled(method, false)) { 223 throw new RuntimeException(method + " must be not compiled"); 224 } 225 if (WHITE_BOX.getMethodCompilationLevel(method, false) != 0) { 226 throw new RuntimeException(method + " comp_level must be == 0"); 227 } 228 if (WHITE_BOX.isMethodCompiled(method, true)) { 229 throw new RuntimeException(method + " must be not osr_compiled"); 230 } 231 if (WHITE_BOX.getMethodCompilationLevel(method, true) != 0) { 232 throw new RuntimeException(method + " osr_comp_level must be == 0"); 233 } 234 } 235 236 /** 237 * Checks, that {@linkplain #method} is compiled. 238 * 239 * @throws RuntimeException if {@linkplain #method} isn't in compiler queue 240 * and isn't compiled, or if {@linkplain #method} 241 * has nonzero compilation level 242 */ 243 protected final void checkCompiled() { 244 final long start = System.currentTimeMillis(); 245 waitBackgroundCompilation(); 246 if (WHITE_BOX.isMethodQueuedForCompilation(method)) { 247 System.err.printf("Warning: %s is still in queue after %dms%n", 248 method, System.currentTimeMillis() - start); 249 return; 250 } 251 if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr())) { 252 throw new RuntimeException(method + " must be " 253 + (testCase.isOsr() ? "osr_" : "") + "compiled"); 254 } 255 if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr()) 256 == 0) { 257 throw new RuntimeException(method 258 + (testCase.isOsr() ? " osr_" : " ") 259 + "comp_level must be != 0"); 260 } 261 } 262 263 protected final void deoptimize() { 264 WHITE_BOX.deoptimizeMethod(method, testCase.isOsr()); 265 if (testCase.isOsr()) { 266 WHITE_BOX.deoptimizeMethod(method, false); 267 } 268 } 269 270 protected final int getCompLevel() { 271 NMethod nm = NMethod.get(method, testCase.isOsr()); 272 return nm == null ? COMP_LEVEL_NONE : nm.comp_level; 273 } 274 275 protected final boolean isCompilable() { 276 return WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, 277 testCase.isOsr()); 278 } 279 280 protected final boolean isCompilable(int compLevel) { 281 return WHITE_BOX 282 .isMethodCompilable(method, compLevel, testCase.isOsr()); 283 } 284 285 protected final void makeNotCompilable() { 286 WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY, 287 testCase.isOsr()); 288 } 289 290 protected final void makeNotCompilable(int compLevel) { 291 WHITE_BOX.makeMethodNotCompilable(method, compLevel, testCase.isOsr()); 292 } 293 294 /** 295 * Waits for completion of background compilation of {@linkplain #method}. 296 */ 297 protected final void waitBackgroundCompilation() { 298 if (!BACKGROUND_COMPILATION) { 299 return; 300 } 301 final Object obj = new Object(); 302 for (int i = 0; i < 10 303 && WHITE_BOX.isMethodQueuedForCompilation(method); ++i) { 304 synchronized (obj) { 305 try { 306 obj.wait(1000); 307 } catch (InterruptedException e) { 308 Thread.currentThread().interrupt(); 309 } 310 } 311 } 312 } 313 314 /** 315 * Prints information about {@linkplain #method}. 316 */ 317 protected final void printInfo() { 318 System.out.printf("%n%s:%n", method); 319 System.out.printf("\tcompilable:\t%b%n", 320 WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, false)); 321 System.out.printf("\tcompiled:\t%b%n", 322 WHITE_BOX.isMethodCompiled(method, false)); 323 System.out.printf("\tcomp_level:\t%d%n", 324 WHITE_BOX.getMethodCompilationLevel(method, false)); 325 System.out.printf("\tosr_compilable:\t%b%n", 326 WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, true)); 327 System.out.printf("\tosr_compiled:\t%b%n", 328 WHITE_BOX.isMethodCompiled(method, true)); 329 System.out.printf("\tosr_comp_level:\t%d%n", 330 WHITE_BOX.getMethodCompilationLevel(method, true)); 331 System.out.printf("\tin_queue:\t%b%n", 332 WHITE_BOX.isMethodQueuedForCompilation(method)); 333 System.out.printf("compile_queues_size:\t%d%n%n", 334 WHITE_BOX.getCompileQueuesSize()); 335 } 336 337 /** 338 * Executes testing. 339 */ 340 protected abstract void test() throws Exception; 341 342 /** 343 * Tries to trigger compilation of {@linkplain #method} by call 344 * {@linkplain TestCase#getCallable()} enough times. 345 * 346 * @return accumulated result 347 * @see #compile(int) 348 */ 349 protected final int compile() { 350 if (testCase.isOsr()) { 351 return compile(1); 352 } else { 353 return compile(THRESHOLD); 354 } 355 } 356 357 /** 358 * Tries to trigger compilation of {@linkplain #method} by call 359 * {@linkplain TestCase#getCallable()} specified times. 360 * 361 * @param count invocation count 362 * @return accumulated result 363 */ 364 protected final int compile(int count) { 365 int result = 0; 366 Integer tmp; 367 for (int i = 0; i < count; ++i) { 368 try { 369 tmp = testCase.getCallable().call(); 370 } catch (Exception e) { 371 tmp = null; 372 } 373 result += tmp == null ? 0 : tmp; 374 } 375 if (IS_VERBOSE) { 376 System.out.println("method was invoked " + count + " times"); 377 } 378 return result; 379 } 380 381 /** 382 * Utility interface provides tested method and object to invoke it. 383 */ 384 public interface TestCase { 385 /** the name of test case */ 386 String name(); 387 388 /** tested method */ 389 Executable getExecutable(); 390 391 /** object to invoke {@linkplain #getExecutable()} */ 392 Callable<Integer> getCallable(); 393 394 /** flag for OSR test case */ 395 boolean isOsr(); 396 } 397 398 /** 399 * @return {@code true} if the current test case is OSR and the mode is 400 * Xcomp, otherwise {@code false} 401 */ 402 protected boolean skipXcompOSR() { 403 boolean result = testCase.isOsr() 404 && CompilerWhiteBoxTest.MODE.startsWith("compiled "); 405 if (result && IS_VERBOSE) { 406 System.err.printf("Warning: %s is not applicable in %s%n", 407 testCase.name(), CompilerWhiteBoxTest.MODE); 408 } 409 return result; 410 } 411 } 412 413 enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase { 414 /** constructor test case */ 415 CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false), 416 /** method test case */ 417 METOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), 418 /** static method test case */ 419 STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false), 420 /** OSR constructor test case */ 421 OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, 422 Helper.OSR_CONSTRUCTOR_CALLABLE, true), 423 /** OSR method test case */ 424 OSR_METOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), 425 /** OSR static method test case */ 426 OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); 427 428 private final Executable executable; 429 private final Callable<Integer> callable; 430 private final boolean isOsr; 431 432 private SimpleTestCase(Executable executable, Callable<Integer> callable, 433 boolean isOsr) { 434 this.executable = executable; 435 this.callable = callable; 436 this.isOsr = isOsr; 437 } 438 439 @Override 440 public Executable getExecutable() { 441 return executable; 442 } 443 444 @Override 445 public Callable<Integer> getCallable() { 446 return callable; 447 } 448 449 @Override 450 public boolean isOsr() { 451 return isOsr; 452 } 453 454 private static class Helper { 455 456 private static final Callable<Integer> CONSTRUCTOR_CALLABLE 457 = new Callable<Integer>() { 458 @Override 459 public Integer call() throws Exception { 460 return new Helper(1337).hashCode(); 461 } 462 }; 463 464 private static final Callable<Integer> METHOD_CALLABLE 465 = new Callable<Integer>() { 466 private final Helper helper = new Helper(); 467 468 @Override 469 public Integer call() throws Exception { 470 return helper.method(); 471 } 472 }; 473 474 private static final Callable<Integer> STATIC_CALLABLE 475 = new Callable<Integer>() { 476 @Override 477 public Integer call() throws Exception { 478 return staticMethod(); 479 } 480 }; 481 482 private static final Callable<Integer> OSR_CONSTRUCTOR_CALLABLE 483 = new Callable<Integer>() { 484 @Override 485 public Integer call() throws Exception { 486 return new Helper(null).hashCode(); 487 } 488 }; 489 490 private static final Callable<Integer> OSR_METHOD_CALLABLE 491 = new Callable<Integer>() { 492 private final Helper helper = new Helper(); 493 494 @Override 495 public Integer call() throws Exception { 496 return helper.osrMethod(); 497 } 498 }; 499 500 private static final Callable<Integer> OSR_STATIC_CALLABLE 501 = new Callable<Integer>() { 502 @Override 503 public Integer call() throws Exception { 504 return osrStaticMethod(); 505 } 506 }; 507 508 private static final Constructor CONSTRUCTOR; 509 private static final Constructor OSR_CONSTRUCTOR; 510 private static final Method METHOD; 511 private static final Method STATIC; 512 private static final Method OSR_METHOD; 513 private static final Method OSR_STATIC; 514 515 static { 516 try { 517 CONSTRUCTOR = Helper.class.getDeclaredConstructor(int.class); 518 } catch (NoSuchMethodException | SecurityException e) { 519 throw new RuntimeException( 520 "exception on getting method Helper.<init>(int)", e); 521 } 522 try { 523 OSR_CONSTRUCTOR = Helper.class.getDeclaredConstructor( 524 Object.class); 525 } catch (NoSuchMethodException | SecurityException e) { 526 throw new RuntimeException( 527 "exception on getting method Helper.<init>(Object)", e); 528 } 529 METHOD = getMethod("method"); 530 STATIC = getMethod("staticMethod"); 531 OSR_METHOD = getMethod("osrMethod"); 532 OSR_STATIC = getMethod("osrStaticMethod"); 533 } 534 535 private static Method getMethod(String name) { 536 try { 537 return Helper.class.getDeclaredMethod(name); 538 } catch (NoSuchMethodException | SecurityException e) { 539 throw new RuntimeException( 540 "exception on getting method Helper." + name, e); 541 } 542 543 } 544 545 private static int staticMethod() { 546 return 1138; 547 } 548 549 private int method() { 550 return 42; 551 } 552 553 private static int osrStaticMethod() { 554 int result = 0; 555 for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { 556 result += staticMethod(); 557 } 558 return result; 559 } 560 561 private int osrMethod() { 562 int result = 0; 563 for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { 564 result += method(); 565 } 566 return result; 567 } 568 569 private final int x; 570 571 // for method and OSR method test case 572 public Helper() { 573 x = 0; 574 } 575 576 // for OSR constructor test case 577 private Helper(Object o) { 578 int result = 0; 579 for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { 580 result += method(); 581 } 582 x = result; 583 } 584 585 // for constructor test case 586 private Helper(int x) { 587 this.x = x; 588 } 589 590 @Override 591 public int hashCode() { 592 return x; 593 } 594 } 595 }