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