1 /* 2 * Copyright (c) 2016, 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 // TODO add bugid and summary 25 26 /* 27 * @test 28 * @library /testlibrary /test/lib /compiler/whitebox / 29 * @build compiler.valhalla.valuetypes.ValueTypeTestBench 30 * @run main ClassFileInstaller sun.hotspot.WhiteBox 31 * @run main ClassFileInstaller jdk.test.lib.Platform 32 * @run main/othervm -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 33 * compiler.valhalla.valuetypes.ValueTypeTestBench 34 */ 35 36 package compiler.valhalla.valuetypes; 37 38 import compiler.whitebox.CompilerWhiteBoxTest; 39 import jdk.internal.misc.Unsafe; 40 import jdk.test.lib.Asserts; 41 import jdk.test.lib.Platform; 42 import jdk.test.lib.ProcessTools; 43 import jdk.test.lib.OutputAnalyzer; 44 import jdk.test.lib.Utils; 45 import sun.hotspot.WhiteBox; 46 47 import java.lang.annotation.Retention; 48 import java.lang.annotation.RetentionPolicy; 49 import java.lang.reflect.Method; 50 import java.util.ArrayList; 51 import java.util.Hashtable; 52 import java.util.regex.Matcher; 53 import java.util.regex.Pattern; 54 55 // Test value types 56 __ByValue final class MyValue1 { 57 final int x; 58 final long y; 59 final MyValue2 v1; 60 final MyValue2 v2; 61 final int c; 62 63 private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) { 64 this.x = x; 65 this.y = y; 66 this.v1 = v1; 67 this.v2 = v2; 68 this.c = c; 69 } 70 71 @DontInline 72 public static MyValue1 createDontInline(int x, long y) { 73 return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI); 74 } 75 76 @ForceInline 77 public static MyValue1 createInline(int x, long y) { 78 return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI); 79 } 80 81 @ForceInline 82 public long hash() { 83 return x + y + c + v1.hash() + v2.hash(); 84 } 85 86 @DontCompile 87 public long hashInterpreted() { 88 return x + y + c + v1.hash() + v2.hash(); 89 } 90 } 91 92 __ByValue final class MyValue2 { 93 final int x; 94 final boolean b; 95 final long c; 96 97 private MyValue2(int x, boolean b, long c) { 98 this.x = x; 99 this.b = b; 100 this.c = c; 101 } 102 103 @ForceInline 104 public static MyValue2 createInline(int x, boolean b) { 105 return __Make MyValue2(x, b, ValueTypeTestBench.rL); 106 } 107 108 @ForceInline 109 public long hash() { 110 return x + (b ? 0 : 1) + c; 111 } 112 } 113 114 public class ValueTypeTestBench { 115 // Print ideal graph after execution of each test 116 private static final boolean PRINT_GRAPH = true; 117 118 // ========== Helper methods ========== 119 120 public long hash() { 121 return hash(rI, rL); 122 } 123 124 public long hash(int x, long y) { 125 return MyValue1.createInline(x, y).hash(); 126 } 127 128 // ========== Test definitions ========== 129 130 // Receive value type through call to interpreter 131 @Test(failOn = ALLOC + STORE + TRAP) 132 public long test1() { 133 MyValue1 v = MyValue1.createDontInline(rI, rL); 134 return v.hash(); 135 } 136 137 @DontCompile 138 public void test1_verifier(boolean warmup) { 139 long result = test1(); 140 Asserts.assertEQ(result, hash()); 141 } 142 143 // Receive value type from interpreter via parameter 144 @Test(failOn = ALLOC + STORE + TRAP) 145 public long test2(MyValue1 v) { 146 return v.hash(); 147 } 148 149 @DontCompile 150 public void test2_verifier(boolean warmup) { 151 MyValue1 v = MyValue1.createDontInline(rI, rL); 152 long result = test2(v); 153 Asserts.assertEQ(result, hash()); 154 } 155 156 // Return incoming value type without accessing fields 157 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 158 public MyValue1 test3(MyValue1 v) { 159 return v; 160 } 161 162 @DontCompile 163 public void test3_verifier(boolean warmup) { 164 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 165 MyValue1 v2 = test3(v1); 166 Asserts.assertEQ(v1.x, v2.x); 167 Asserts.assertEQ(v1.y, v2.y); 168 } 169 170 // Create a value type in compiled code and only use fields. 171 // Allocation should go away because value type does not escape. 172 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 173 public long test4() { 174 MyValue1 v = MyValue1.createInline(rI, rL); 175 return v.hash(); 176 } 177 178 @DontCompile 179 public void test4_verifier(boolean warmup) { 180 long result = test4(); 181 Asserts.assertEQ(result, hash()); 182 } 183 184 // Create a value type in compiled code and pass it to 185 // an inlined compiled method via a call. 186 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 187 public long test5() { 188 MyValue1 v = MyValue1.createInline(rI, rL); 189 return test5Inline(v); 190 } 191 192 @ForceInline 193 public long test5Inline(MyValue1 v) { 194 return v.hash(); 195 } 196 197 @DontCompile 198 public void test5_verifier(boolean warmup) { 199 long result = test5(); 200 Asserts.assertEQ(result, hash()); 201 } 202 203 // Create a value type in compiled code and pass it to 204 // the interpreter via a call. 205 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 206 public long test6() { 207 MyValue1 v = MyValue1.createInline(rI, rL); 208 // Pass to interpreter 209 return v.hashInterpreted(); 210 } 211 212 @DontCompile 213 public void test6_verifier(boolean warmup) { 214 long result = test6(); 215 Asserts.assertEQ(result, hash()); 216 } 217 218 // Create a value type in compiled code and pass it to 219 // the interpreter by returning. 220 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 221 public MyValue1 test7(int x, long y) { 222 return MyValue1.createInline(x, y); 223 } 224 225 @DontCompile 226 public void test7_verifier(boolean warmup) { 227 MyValue1 v = test7(rI, rL); 228 Asserts.assertEQ(v.hash(), hash()); 229 } 230 231 // Merge value types created from two branches 232 @Test(failOn = ALLOC + STORE + TRAP) 233 public long test8(boolean b) { 234 MyValue1 v; 235 if (b) { 236 v = MyValue1.createInline(rI, rL); 237 } else { 238 v = MyValue1.createDontInline(rI + 1, rL + 1); 239 } 240 return v.hash(); 241 } 242 243 @DontCompile 244 public void test8_verifier(boolean warmup) { 245 Asserts.assertEQ(test8(true), hash()); 246 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1)); 247 } 248 249 // Merge value types created from two branches 250 @Test(match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP) 251 public MyValue1 test9(boolean b) { 252 MyValue1 v; 253 if (b) { 254 // Value type is not allocated 255 v = MyValue1.createInline(rI, rL); 256 } else { 257 // Value type is allocated by the callee 258 v = MyValue1.createDontInline(rI + 1, rL + 1); 259 } 260 // Need to allocate value type if 'b' is true 261 long sum = v.hashInterpreted(); 262 if (b) { 263 v = MyValue1.createDontInline(rI, sum); 264 } else { 265 v = MyValue1.createDontInline(rI, sum + 1); 266 } 267 // Don't need to allocate value type because both branches allocate 268 return v; 269 } 270 271 @DontCompile 272 public void test9_verifier(boolean warmup) { 273 MyValue1 v = test9(true); 274 Asserts.assertEQ(v.x, rI); 275 Asserts.assertEQ(v.y, hash()); 276 v = test9(false); 277 Asserts.assertEQ(v.x, rI); 278 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1); 279 } 280 281 // Merge value types created in a loop (not inlined) 282 @Test(failOn = ALLOC + STORE + TRAP) 283 public long test10(int x, long y) { 284 MyValue1 v = MyValue1.createDontInline(x, y); 285 for (int i = 0; i < 10; ++i) { 286 v = MyValue1.createDontInline(v.x + 1, v.y + 1); 287 } 288 return v.hash(); 289 } 290 291 @DontCompile 292 public void test10_verifier(boolean warmup) { 293 long result = test10(rI, rL); 294 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 295 } 296 297 // Merge value types created in a loop (inlined) 298 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 299 public long test11(int x, long y) { 300 MyValue1 v = MyValue1.createInline(x, y); 301 for (int i = 0; i < 10; ++i) { 302 v = MyValue1.createInline(v.x + 1, v.y + 1); 303 } 304 return v.hash(); 305 } 306 307 @DontCompile 308 public void test11_verifier(boolean warmup) { 309 long result = test11(rI, rL); 310 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 311 } 312 313 // Test loop with uncommon trap referencing a value type 314 @Test(match = {TRAP, SCOBJ}, matchCount = {1, 1}, failOn = ALLOC + LOAD + STORE) 315 public long test12(boolean b) { 316 MyValue1 v = MyValue1.createInline(rI, rL); 317 long result = 42; 318 for (int i = 0; i < 1000; ++i) { 319 if (b) { 320 result += v.x; 321 } else { 322 // Uncommon trap referencing v. We delegate allocation to the 323 // interpreter by adding a SafePointScalarObjectNode. 324 result = v.hashInterpreted(); 325 } 326 } 327 return result; 328 } 329 330 @DontCompile 331 public void test12_verifier(boolean warmup) { 332 long result = test12(warmup); 333 Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash()); 334 } 335 336 // Test loop with uncommon trap referencing a value type 337 @Test(match = {TRAP, LOAD}, matchCount = {1, 1}, failOn = ALLOC + STORE + SCOBJ) 338 public long test13(boolean b) { 339 MyValue1 v = MyValue1.createDontInline(rI, rL); 340 long result = 42; 341 for (int i = 0; i < 1000; ++i) { 342 if (b) { 343 result += v.x; 344 } else { 345 // Uncommon trap referencing v. Should not allocate 346 // but just pass the existing oop to the uncommon trap. 347 result = v.hashInterpreted(); 348 } 349 } 350 return result; 351 } 352 353 @DontCompile 354 public void test13_verifier(boolean warmup) { 355 long result = test13(warmup); 356 Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash()); 357 } 358 359 // Create a value type in a non-inlined method and then call a 360 // non-inlined method on that value type. 361 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 362 public long test14() { 363 MyValue1 v = MyValue1.createDontInline(rI, rL); 364 return v.hashInterpreted(); 365 } 366 367 @DontCompile 368 public void test14_verifier(boolean b) { 369 long result = test14(); 370 Asserts.assertEQ(result, hash()); 371 } 372 373 // Create a value type in an inlined method and then call a 374 // non-inlined method on that value type. 375 @Test(failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1}) 376 public long test15() { 377 MyValue1 v = MyValue1.createInline(rI, rL); 378 return v.hashInterpreted(); 379 } 380 381 @DontCompile 382 public void test15_verifier(boolean b) { 383 long result = test15(); 384 Asserts.assertEQ(result, hash()); 385 } 386 387 // Create a value type in a non-inlined method and then call an 388 // inlined method on that value type. 389 @Test(failOn = (ALLOC + STORE + TRAP)) 390 public long test16() { 391 MyValue1 v = MyValue1.createDontInline(rI, rL); 392 return v.hash(); 393 } 394 395 @DontCompile 396 public void test16_verifier(boolean b) { 397 long result = test16(); 398 Asserts.assertEQ(result, hash()); 399 } 400 401 // Create a value type in an inlined method and then call an 402 // inlined method on that value type. 403 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 404 public long test17() { 405 MyValue1 v = MyValue1.createInline(rI, rL); 406 return v.hash(); 407 } 408 409 @DontCompile 410 public void test17_verifier(boolean b) { 411 long result = test17(); 412 Asserts.assertEQ(result, hash()); 413 } 414 415 // Create a value type in compiled code and pass it to the 416 // interpreter via a call. The value is live at the first call so 417 // debug info should include a reference to all its fields. 418 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 419 public long test18() { 420 MyValue1 v = MyValue1.createInline(rI, rL); 421 v.hashInterpreted(); 422 return v.hashInterpreted(); 423 } 424 425 @DontCompile 426 public void test18_verifier(boolean warmup) { 427 long result = test18(); 428 Asserts.assertEQ(result, hash()); 429 } 430 431 // Create a value type in compiled code and pass it to the 432 // interpreter via a call. The value type is passed twice but 433 // should only be allocated once. 434 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 435 public long test19() { 436 MyValue1 v = MyValue1.createInline(rI, rL); 437 return sumValue(v, v); 438 } 439 440 @DontCompile 441 public long sumValue(MyValue1 v, MyValue1 dummy) { 442 return v.hash(); 443 } 444 445 @DontCompile 446 public void test19_verifier(boolean warmup) { 447 long result = test19(); 448 Asserts.assertEQ(result, hash()); 449 } 450 451 // Create a value type in compiled code and pass it to the 452 // interpreter via a call. The value type is live at the uncommon 453 // trap: verify that deoptimization causes the value type to be 454 // correctly allocated. 455 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD) 456 public long test20(boolean flag) { 457 MyValue1 v = MyValue1.createInline(rI, rL); 458 if (flag) { 459 // uncommon trap 460 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test16")); 461 } 462 return v.hashInterpreted(); 463 } 464 465 @DontCompile 466 public void test20_verifier(boolean warmup) { 467 long result = test20(false); 468 Asserts.assertEQ(result, hash()); 469 if (!warmup) { 470 result = test20(true); 471 Asserts.assertEQ(result, hash()); 472 } 473 } 474 475 // Value type fields in regular object 476 MyValue1 val1; 477 MyValue2 val2; 478 479 // Test value type fields in objects 480 @Test(failOn = (ALLOC + TRAP)) 481 public long test21(int x, long y) { 482 // Compute hash of value type fields 483 long result = val1.hash() + val2.hash(); 484 // Update fields 485 val1 = MyValue1.createInline(x, y); 486 val2 = MyValue2.createInline(x, true); 487 return result; 488 } 489 490 @DontCompile 491 public void test21_verifier(boolean warmup) { 492 // Check if hash computed by test18 is correct 493 val1 = MyValue1.createInline(rI, rL); 494 val2 = val1.v2; 495 long hash = val1.hash() + val2.hash(); 496 long result = test21(rI + 1, rL + 1); 497 Asserts.assertEQ(result, hash); 498 // Check if value type fields were updated 499 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1)); 500 Asserts.assertEQ(val2.hash(), MyValue2.createInline(rI + 1, true).hash()); 501 } 502 503 504 // ========== Test infrastructure ========== 505 506 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 507 private static final int COMP_LEVEL_ANY = -1; 508 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 509 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 510 private static final int WARMUP = 10; 511 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 512 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 513 514 // Regular expressions used to match nodes in the PrintIdeal output 515 private static final String START = "(\\d+\\t(.*"; 516 private static final String MID = ".*)+\\t===.*"; 517 private static final String END = ")|"; 518 private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END; 519 private static final String LOAD = START + "Load" + MID + "valuetype\\*" + END; 520 private static final String STORE = START + "Store" + MID + "valuetype\\*" + END; 521 private static final String LOOP = START + "Loop" + MID + "" + END; 522 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap" + END; 523 // TODO: match field values of scalar replaced object 524 private static final String SCOBJ = "(.*# ScObj.*" + END; 525 526 // Random test values 527 public static final int rI = Utils.getRandomInstance().nextInt() % 1000; 528 public static final long rL = Utils.getRandomInstance().nextLong() % 1000; 529 530 static { 531 // Gather all test methods and put them in Hashtable 532 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) { 533 if (m.isAnnotationPresent(Test.class)) { 534 tests.put("ValueTypeTestBench::" + m.getName(), m); 535 } 536 } 537 } 538 539 public static void main(String[] args) throws Throwable { 540 if (args.length == 0) { 541 // Run tests in own process and verify output 542 OutputAnalyzer oa = ProcessTools.executeTestJvm("-noverify", 543 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI", 544 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation", "-XX:-UseOnStackReplacement", 545 "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly", 546 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*", 547 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", 548 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*", 549 ValueTypeTestBench.class.getName(), "run"); 550 // If ideal graph printing is enabled/supported, verify output 551 String output = oa.getOutput(); 552 oa.shouldHaveExitValue(0); 553 if (output.contains("PrintIdeal enabled")) { 554 parseOutput(output); 555 } else { 556 System.out.println("WARNING: test methods not compiled or PrintIdeal disabled! Running with -Xint or release build?"); 557 } 558 } else { 559 if (USE_COMPILER && PRINT_IDEAL) { 560 System.out.println("PrintIdeal enabled"); 561 } 562 // Execute tests 563 ValueTypeTestBench bench = new ValueTypeTestBench(); 564 bench.run(); 565 } 566 } 567 568 public static void parseOutput(String output) throws Exception { 569 String split = "b compiler.valhalla.valuetypes."; 570 String[] compilations = output.split(split); 571 // Print header 572 System.out.println(compilations[0]); 573 // Iterate over compilation output 574 for (String graph : compilations) { 575 String[] lines = graph.split("\\n"); 576 String testName = lines[0].split(" ")[0]; 577 Method test = tests.get(testName); 578 if (test == null) { 579 // Skip helper methods 580 continue; 581 } 582 if (PRINT_GRAPH) { 583 System.out.println("\nGraph for " + graph); 584 } 585 // Parse graph using regular expressions to determine if it contains forbidden nodes 586 Test anno = test.getAnnotation(Test.class); 587 String regexFail = anno.failOn(); 588 if (!regexFail.isEmpty()) { 589 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 590 Matcher matcher = pattern.matcher(graph); 591 boolean fail = false; 592 while (matcher.find()) { 593 System.out.println("Graph for '" + testName + "' contains forbidden node:"); 594 System.out.println(matcher.group()); 595 fail = true; 596 } 597 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes"); 598 } 599 String[] regexMatch = anno.match(); 600 int[] matchCount = anno.matchCount(); 601 for (int i = 0; i < regexMatch.length; ++i) { 602 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 603 Matcher matcher = pattern.matcher(graph); 604 int count = 0; 605 String nodes = ""; 606 while (matcher.find()) { 607 count++; 608 nodes += matcher.group() + "\n"; 609 } 610 if (matchCount[i] != count) { 611 System.out.println("Graph for '" + testName + "' contains different number of match nodes:"); 612 System.out.println(nodes); 613 } 614 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes"); 615 } 616 tests.remove(testName); 617 System.out.println(testName + " passed"); 618 } 619 // Check if all tests were compiled 620 if (tests.size() != 0) { 621 for (String name : tests.keySet()) { 622 System.out.println("Test '" + name + "' not compiled!"); 623 } 624 throw new RuntimeException("Not all tests were compiled"); 625 } 626 } 627 628 public void setup(Method[] methods) { 629 for (Method m : methods) { 630 if (m.isAnnotationPresent(Test.class)) { 631 // Don't inline tests 632 WHITE_BOX.testSetDontInlineMethod(m, true); 633 } 634 if (m.isAnnotationPresent(DontCompile.class)) { 635 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 636 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 637 } 638 if (m.isAnnotationPresent(ForceInline.class)) { 639 WHITE_BOX.testSetForceInlineMethod(m, true); 640 } else if (m.isAnnotationPresent(DontInline.class)) { 641 WHITE_BOX.testSetDontInlineMethod(m, true); 642 } 643 } 644 } 645 646 public void run() throws Exception { 647 System.out.format("rI = %d, rL = %d\n", rI, rL); 648 setup(this.getClass().getDeclaredMethods()); 649 setup(MyValue1.class.getDeclaredMethods()); 650 setup(MyValue2.class.getDeclaredMethods()); 651 652 // Execute tests 653 for (Method test : tests.values()) { 654 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class); 655 // Warmup using verifier method 656 for (int i = 0; i < WARMUP; ++i) { 657 verifier.invoke(this, true); 658 } 659 // Trigger compilation 660 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION); 661 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 662 // Check result 663 verifier.invoke(this, false); 664 } 665 } 666 } 667 668 // Mark method as test 669 @Retention(RetentionPolicy.RUNTIME) 670 @interface Test { 671 // Regular expression used to match forbidden IR nodes 672 // in the C2 IR emitted for this test. 673 String failOn() default ""; 674 // Regular expressions used to match and count IR nodes. 675 String[] match() default { }; 676 int[] matchCount() default { }; 677 } 678 679 // Force method inlining during compilation 680 @Retention(RetentionPolicy.RUNTIME) 681 @interface ForceInline { } 682 683 // Prevent method inlining during compilation 684 @Retention(RetentionPolicy.RUNTIME) 685 @interface DontInline { } 686 687 // Prevent method compilation 688 @Retention(RetentionPolicy.RUNTIME) 689 @interface DontCompile { }