1 /* 2 * Copyright (c) 2016, 2017, 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 -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 33 * -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten 34 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench 35 * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 36 * -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten 37 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench 38 */ 39 40 package compiler.valhalla.valuetypes; 41 42 import compiler.whitebox.CompilerWhiteBoxTest; 43 import jdk.internal.misc.Unsafe; 44 import jdk.test.lib.Asserts; 45 import jdk.test.lib.Platform; 46 import jdk.test.lib.ProcessTools; 47 import jdk.test.lib.OutputAnalyzer; 48 import jdk.test.lib.Utils; 49 import sun.hotspot.WhiteBox; 50 51 import java.lang.annotation.Retention; 52 import java.lang.annotation.RetentionPolicy; 53 import java.lang.annotation.Repeatable; 54 import java.lang.invoke.*; 55 import java.lang.reflect.Method; 56 import java.util.ArrayList; 57 import java.util.Arrays; 58 import java.util.Hashtable; 59 import java.util.List; 60 import java.util.regex.Matcher; 61 import java.util.regex.Pattern; 62 import jdk.experimental.value.*; 63 64 // Test value types 65 __ByValue final class MyValue1 { 66 static int s; 67 static final long sf = ValueTypeTestBench.rL; 68 final int x; 69 final long y; 70 final MyValue2 v1; 71 final MyValue2 v2; 72 static final MyValue2 v3 = MyValue2.createInline(ValueTypeTestBench.rI, true); 73 final int c; 74 75 private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) { 76 s = x; 77 this.x = x; 78 this.y = y; 79 this.v1 = v1; 80 this.v2 = v2; 81 this.c = c; 82 } 83 84 @DontInline 85 public static MyValue1 createDontInline(int x, long y) { 86 return __Make MyValue1(x, y, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI); 87 } 88 89 @ForceInline 90 public static MyValue1 createInline(int x, long y) { 91 return __Make MyValue1(x, y, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI); 92 } 93 94 @ForceInline 95 public long hash() { 96 return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash(); 97 } 98 99 @DontCompile 100 public long hashInterpreted() { 101 return s + sf + x + y + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted(); 102 } 103 104 @ForceInline 105 public void print() { 106 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", v1["); 107 v1.print(); 108 System.out.print("], v2["); 109 v2.print(); 110 System.out.print("], v3["); 111 v3.print(); 112 System.out.print("], c=" + c); 113 } 114 } 115 116 __ByValue final class MyValue2 { 117 final int x; 118 final boolean b; 119 final long c; 120 121 private MyValue2(int x, boolean b, long c) { 122 this.x = x; 123 this.b = b; 124 this.c = c; 125 } 126 127 @ForceInline 128 public static MyValue2 createInline(int x, boolean b) { 129 return __Make MyValue2(x, b, ValueTypeTestBench.rL); 130 } 131 132 @ForceInline 133 public long hash() { 134 return x + (b ? 0 : 1) + c; 135 } 136 137 @DontInline 138 public long hashInterpreted() { 139 return x + (b ? 0 : 1) + c; 140 } 141 142 @ForceInline 143 public void print() { 144 System.out.print("x=" + x + ", b=" + b + ", c=" + c); 145 } 146 } 147 148 public class ValueTypeTestBench { 149 // Print ideal graph after execution of each test 150 private static final boolean PRINT_GRAPH = true; 151 152 // Random test values 153 public static final int rI = Utils.getRandomInstance().nextInt() % 1000; 154 public static final long rL = Utils.getRandomInstance().nextLong() % 1000; 155 156 public ValueTypeTestBench() { 157 val3 = MyValue1.createInline(rI, rL); 158 } 159 160 // MethodHandles and value-capable class instance needed for testing vbox/vunbox 161 private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH(); 162 private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH(); 163 private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH(); 164 private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH(); 165 166 private static final ValueCapableClass1 vcc = ValueCapableClass1.create(rL, rI, (short)rI, (short)rI); 167 168 // ========== Helper methods ========== 169 170 public long hash() { 171 return hash(rI, rL); 172 } 173 174 public long hash(int x, long y) { 175 return MyValue1.createInline(x, y).hash(); 176 } 177 178 // ========== Test definitions ========== 179 180 // Receive value type through call to interpreter 181 @Test(failOn = ALLOC + STORE + TRAP) 182 public long test1() { 183 MyValue1 v = MyValue1.createDontInline(rI, rL); 184 return v.hash(); 185 } 186 187 @DontCompile 188 public void test1_verifier(boolean warmup) { 189 long result = test1(); 190 Asserts.assertEQ(result, hash()); 191 } 192 193 // Receive value type from interpreter via parameter 194 @Test(failOn = ALLOC + STORE + TRAP) 195 public long test2(MyValue1 v) { 196 return v.hash(); 197 } 198 199 @DontCompile 200 public void test2_verifier(boolean warmup) { 201 MyValue1 v = MyValue1.createDontInline(rI, rL); 202 long result = test2(v); 203 Asserts.assertEQ(result, hash()); 204 } 205 206 // Return incoming value type without accessing fields 207 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP) 208 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP) 209 public MyValue1 test3(MyValue1 v) { 210 return v; 211 } 212 213 @DontCompile 214 public void test3_verifier(boolean warmup) { 215 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 216 MyValue1 v2 = test3(v1); 217 Asserts.assertEQ(v1.x, v2.x); 218 Asserts.assertEQ(v1.y, v2.y); 219 } 220 221 // Create a value type in compiled code and only use fields. 222 // Allocation should go away because value type does not escape. 223 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 224 public long test4() { 225 MyValue1 v = MyValue1.createInline(rI, rL); 226 return v.hash(); 227 } 228 229 @DontCompile 230 public void test4_verifier(boolean warmup) { 231 long result = test4(); 232 Asserts.assertEQ(result, hash()); 233 } 234 235 // Create a value type in compiled code and pass it to 236 // an inlined compiled method via a call. 237 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 238 public long test5() { 239 MyValue1 v = MyValue1.createInline(rI, rL); 240 return test5Inline(v); 241 } 242 243 @ForceInline 244 public long test5Inline(MyValue1 v) { 245 return v.hash(); 246 } 247 248 @DontCompile 249 public void test5_verifier(boolean warmup) { 250 long result = test5(); 251 Asserts.assertEQ(result, hash()); 252 } 253 254 // Create a value type in compiled code and pass it to 255 // the interpreter via a call. 256 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC) 257 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 258 public long test6() { 259 MyValue1 v = MyValue1.createInline(rI, rL); 260 // Pass to interpreter 261 return v.hashInterpreted(); 262 } 263 264 @DontCompile 265 public void test6_verifier(boolean warmup) { 266 long result = test6(); 267 Asserts.assertEQ(result, hash()); 268 } 269 270 // Create a value type in compiled code and pass it to 271 // the interpreter by returning. 272 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 273 public MyValue1 test7(int x, long y) { 274 return MyValue1.createInline(x, y); 275 } 276 277 @DontCompile 278 public void test7_verifier(boolean warmup) { 279 MyValue1 v = test7(rI, rL); 280 Asserts.assertEQ(v.hash(), hash()); 281 } 282 283 // Merge value types created from two branches 284 @Test(failOn = ALLOC + STORE + TRAP) 285 public long test8(boolean b) { 286 MyValue1 v; 287 if (b) { 288 v = MyValue1.createInline(rI, rL); 289 } else { 290 v = MyValue1.createDontInline(rI + 1, rL + 1); 291 } 292 return v.hash(); 293 } 294 295 @DontCompile 296 public void test8_verifier(boolean warmup) { 297 Asserts.assertEQ(test8(true), hash()); 298 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1)); 299 } 300 301 // Merge value types created from two branches 302 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {7}, failOn = TRAP + ALLOC + STORE) 303 // FIXME 304 //@Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP) 305 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP) 306 public MyValue1 test9(boolean b) { 307 MyValue1 v; 308 if (b) { 309 // Value type is not allocated 310 v = MyValue1.createInline(rI, rL); 311 } else { 312 // Value type is allocated by the callee 313 v = MyValue1.createDontInline(rI + 1, rL + 1); 314 } 315 // Need to allocate value type if 'b' is true 316 long sum = v.hashInterpreted(); 317 if (b) { 318 v = MyValue1.createDontInline(rI, sum); 319 } else { 320 v = MyValue1.createDontInline(rI, sum + 1); 321 } 322 // Don't need to allocate value type because both branches allocate 323 return v; 324 } 325 326 @DontCompile 327 public void test9_verifier(boolean warmup) { 328 MyValue1 v = test9(true); 329 Asserts.assertEQ(v.x, rI); 330 Asserts.assertEQ(v.y, hash()); 331 v = test9(false); 332 Asserts.assertEQ(v.x, rI); 333 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1); 334 } 335 336 // Merge value types created in a loop (not inlined) 337 @Test(failOn = ALLOC + STORE + TRAP) 338 public long test10(int x, long y) { 339 MyValue1 v = MyValue1.createDontInline(x, y); 340 for (int i = 0; i < 10; ++i) { 341 v = MyValue1.createDontInline(v.x + 1, v.y + 1); 342 } 343 return v.hash(); 344 } 345 346 @DontCompile 347 public void test10_verifier(boolean warmup) { 348 long result = test10(rI, rL); 349 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 350 } 351 352 // Merge value types created in a loop (inlined) 353 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 354 public long test11(int x, long y) { 355 MyValue1 v = MyValue1.createInline(x, y); 356 for (int i = 0; i < 10; ++i) { 357 v = MyValue1.createInline(v.x + 1, v.y + 1); 358 } 359 return v.hash(); 360 } 361 362 @DontCompile 363 public void test11_verifier(boolean warmup) { 364 long result = test11(rI, rL); 365 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 366 } 367 368 // Test loop with uncommon trap referencing a value type 369 @Test(match = {TRAP, SCOBJ}, matchCount = {1, 1}, failOn = ALLOC + LOAD + STORE) 370 public long test12(boolean b) { 371 MyValue1 v = MyValue1.createInline(rI, rL); 372 long result = 42; 373 for (int i = 0; i < 1000; ++i) { 374 if (b) { 375 result += v.x; 376 } else { 377 // Uncommon trap referencing v. We delegate allocation to the 378 // interpreter by adding a SafePointScalarObjectNode. 379 result = v.hashInterpreted(); 380 } 381 } 382 return result; 383 } 384 385 @DontCompile 386 public void test12_verifier(boolean warmup) { 387 long result = test12(warmup); 388 Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash()); 389 } 390 391 // Test loop with uncommon trap referencing a value type 392 @Test(match = {TRAP, LOAD}, matchCount = {1, 1}, failOn = ALLOC + STORE + SCOBJ) 393 public long test13(boolean b) { 394 MyValue1 v = MyValue1.createDontInline(rI, rL); 395 long result = 42; 396 for (int i = 0; i < 1000; ++i) { 397 if (b) { 398 result += v.x; 399 } else { 400 // Uncommon trap referencing v. Should not allocate 401 // but just pass the existing oop to the uncommon trap. 402 result = v.hashInterpreted(); 403 } 404 } 405 return result; 406 } 407 408 @DontCompile 409 public void test13_verifier(boolean warmup) { 410 long result = test13(warmup); 411 Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash()); 412 } 413 414 // Create a value type in a non-inlined method and then call a 415 // non-inlined method on that value type. 416 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {7}) 417 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP)) 418 public long test14() { 419 MyValue1 v = MyValue1.createDontInline(rI, rL); 420 return v.hashInterpreted(); 421 } 422 423 @DontCompile 424 public void test14_verifier(boolean b) { 425 long result = test14(); 426 Asserts.assertEQ(result, hash()); 427 } 428 429 // Create a value type in an inlined method and then call a 430 // non-inlined method on that value type. 431 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC)) 432 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1}) 433 public long test15() { 434 MyValue1 v = MyValue1.createInline(rI, rL); 435 return v.hashInterpreted(); 436 } 437 438 @DontCompile 439 public void test15_verifier(boolean b) { 440 long result = test15(); 441 Asserts.assertEQ(result, hash()); 442 } 443 444 // Create a value type in a non-inlined method and then call an 445 // inlined method on that value type. 446 @Test(failOn = (ALLOC + STORE + TRAP)) 447 public long test16() { 448 MyValue1 v = MyValue1.createDontInline(rI, rL); 449 return v.hash(); 450 } 451 452 @DontCompile 453 public void test16_verifier(boolean b) { 454 long result = test16(); 455 Asserts.assertEQ(result, hash()); 456 } 457 458 // Create a value type in an inlined method and then call an 459 // inlined method on that value type. 460 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 461 public long test17() { 462 MyValue1 v = MyValue1.createInline(rI, rL); 463 return v.hash(); 464 } 465 466 @DontCompile 467 public void test17_verifier(boolean b) { 468 long result = test17(); 469 Asserts.assertEQ(result, hash()); 470 } 471 472 // Create a value type in compiled code and pass it to the 473 // interpreter via a call. The value is live at the first call so 474 // debug info should include a reference to all its fields. 475 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 476 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 477 public long test18() { 478 MyValue1 v = MyValue1.createInline(rI, rL); 479 v.hashInterpreted(); 480 return v.hashInterpreted(); 481 } 482 483 @DontCompile 484 public void test18_verifier(boolean warmup) { 485 long result = test18(); 486 Asserts.assertEQ(result, hash()); 487 } 488 489 // Create a value type in compiled code and pass it to the 490 // interpreter via a call. The value type is passed twice but 491 // should only be allocated once. 492 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 493 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 494 public long test19() { 495 MyValue1 v = MyValue1.createInline(rI, rL); 496 return sumValue(v, v); 497 } 498 499 @DontCompile 500 public long sumValue(MyValue1 v, MyValue1 dummy) { 501 return v.hash(); 502 } 503 504 @DontCompile 505 public void test19_verifier(boolean warmup) { 506 long result = test19(); 507 Asserts.assertEQ(result, hash()); 508 } 509 510 // Create a value type (array) in compiled code and pass it to the 511 // interpreter via a call. The value type is live at the uncommon 512 // trap: verify that deoptimization causes the value type to be 513 // correctly allocated. 514 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE) 515 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD) 516 public long test20(boolean flag) { 517 MyValue1 v = MyValue1.createInline(rI, rL); 518 // TODO add value type array testcase 519 // MyValue1[] va = new MyValue1[42]; 520 if (flag) { 521 // uncommon trap 522 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20")); 523 } 524 return v.hashInterpreted(); // + va[0].hashInterpreted(); 525 } 526 527 @DontCompile 528 public void test20_verifier(boolean warmup) { 529 MyValue1[] va = new MyValue1[42]; 530 long result = test20(false); 531 Asserts.assertEQ(result, hash() /* + va[0].hash() */); 532 if (!warmup) { 533 result = test20(true); 534 Asserts.assertEQ(result, hash() /* + va[0].hash() */); 535 } 536 } 537 538 // Value type fields in regular object 539 MyValue1 val1; 540 MyValue2 val2; 541 final MyValue1 val3; 542 static MyValue1 val4; 543 static final MyValue1 val5 = MyValue1.createInline(rI, rL); 544 545 // Test value type fields in objects 546 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP)) 547 public long test21(int x, long y) { 548 // Compute hash of value type fields 549 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 550 // Update fields 551 val1 = MyValue1.createInline(x, y); 552 val2 = MyValue2.createInline(x, true); 553 val4 = MyValue1.createInline(x, y); 554 return result; 555 } 556 557 @DontCompile 558 public void test21_verifier(boolean warmup) { 559 // Check if hash computed by test18 is correct 560 val1 = MyValue1.createInline(rI, rL); 561 val2 = val1.v2; 562 // val3 is initialized in the constructor 563 val4 = val1; 564 // val5 is initialized in the static initializer 565 long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 566 long result = test21(rI + 1, rL + 1); 567 Asserts.assertEQ(result, hash); 568 // Check if value type fields were updated 569 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1)); 570 Asserts.assertEQ(val2.hash(), MyValue2.createInline(rI + 1, true).hash()); 571 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1)); 572 } 573 574 // Test folding of constant value type fields 575 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 576 public long test22() { 577 // This should be constant folded 578 return val5.hash() + val5.v3.hash(); 579 } 580 581 @DontCompile 582 public void test22_verifier(boolean warmup) { 583 long result = test22(); 584 Asserts.assertEQ(result, val5.hash() + val5.v3.hash()); 585 } 586 587 // Test OSR compilation 588 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 589 public long test23() { 590 MyValue1 v = MyValue1.createInline(rI, rL); 591 // TODO add OSR testcase for value type arrays 592 //MyValue1[] va = new MyValue1[10]; 593 long result = 0; 594 // Long loop to trigger OSR compilation 595 for (int i = 0 ; i < 100_000 ; ++i) { 596 // Reference local value type in interpreter state 597 result = v.hash(); // + va[0].hash(); 598 } 599 return result; 600 } 601 602 @DontCompile 603 public void test23_verifier(boolean warmup) { 604 //MyValue1[] va = new MyValue1[10]; 605 long result = test23(); 606 Asserts.assertEQ(result, hash() /* + va[0].hash() */); 607 } 608 609 // Test interpreter to compiled code with various signatures 610 @Test(failOn = ALLOC + STORE + TRAP) 611 public long test24(MyValue2 v) { 612 return v.hash(); 613 } 614 615 @DontCompile 616 public void test24_verifier(boolean warmup) { 617 MyValue2 v = MyValue2.createInline(rI, true); 618 long result = test24(v); 619 Asserts.assertEQ(result, v.hashInterpreted()); 620 } 621 622 @Test(failOn = ALLOC + STORE + TRAP) 623 public long test25(int i1, MyValue2 v, int i2) { 624 return v.hash() + i1 - i2; 625 } 626 627 @DontCompile 628 public void test25_verifier(boolean warmup) { 629 MyValue2 v = MyValue2.createInline(rI, true); 630 long result = test25(rI, v, 2*rI); 631 Asserts.assertEQ(result, v.hashInterpreted() - rI); 632 } 633 634 @Test(failOn = ALLOC + STORE + TRAP) 635 public long test26(long l1, MyValue2 v, long l2) { 636 return v.hash() + l1 - l2; 637 } 638 639 @DontCompile 640 public void test26_verifier(boolean warmup) { 641 MyValue2 v = MyValue2.createInline(rI, true); 642 long result = test26(rL, v, 2*rL); 643 Asserts.assertEQ(result, v.hashInterpreted() - rL); 644 } 645 646 @Test(failOn = ALLOC + STORE + TRAP) 647 public long test27(int i, MyValue2 v, long l) { 648 return v.hash() + i + l; 649 } 650 651 @DontCompile 652 public void test27_verifier(boolean warmup) { 653 MyValue2 v = MyValue2.createInline(rI, true); 654 long result = test27(rI, v, rL); 655 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 656 } 657 658 @Test(failOn = ALLOC + STORE + TRAP) 659 public long test28(long l, MyValue2 v, int i) { 660 return v.hash() + i + l; 661 } 662 663 @DontCompile 664 public void test28_verifier(boolean warmup) { 665 MyValue2 v = MyValue2.createInline(rI, true); 666 long result = test28(rL, v, rI); 667 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 668 } 669 670 @Test(failOn = ALLOC + STORE + TRAP) 671 public long test29(long l, MyValue1 v1, int i, MyValue2 v2) { 672 return v1.hash() + i + l + v2.hash(); 673 } 674 675 @DontCompile 676 public void test29_verifier(boolean warmup) { 677 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 678 MyValue2 v2 = MyValue2.createInline(rI, true); 679 long result = test29(rL, v1, rI, v2); 680 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 681 } 682 683 // Test compiled code to interpreter with various signatures 684 @DontCompile 685 public long test30_interp(MyValue2 v) { 686 return v.hash(); 687 } 688 689 @Test(failOn = ALLOC + STORE + TRAP) 690 public long test30(MyValue2 v) { 691 return test30_interp(v); 692 } 693 694 @DontCompile 695 public void test30_verifier(boolean warmup) { 696 MyValue2 v = MyValue2.createInline(rI, true); 697 long result = test30(v); 698 Asserts.assertEQ(result, v.hashInterpreted()); 699 } 700 701 @DontCompile 702 public long test31_interp(int i1, MyValue2 v, int i2) { 703 return v.hash() + i1 - i2; 704 } 705 706 @Test(failOn = ALLOC + STORE + TRAP) 707 public long test31(int i1, MyValue2 v, int i2) { 708 return test31_interp(i1, v, i2); 709 } 710 711 @DontCompile 712 public void test31_verifier(boolean warmup) { 713 MyValue2 v = MyValue2.createInline(rI, true); 714 long result = test31(rI, v, 2*rI); 715 Asserts.assertEQ(result, v.hashInterpreted() - rI); 716 } 717 718 @DontCompile 719 public long test32_interp(long l1, MyValue2 v, long l2) { 720 return v.hash() + l1 - l2; 721 } 722 723 @Test(failOn = ALLOC + STORE + TRAP) 724 public long test32(long l1, MyValue2 v, long l2) { 725 return test32_interp(l1, v, l2); 726 } 727 728 @DontCompile 729 public void test32_verifier(boolean warmup) { 730 MyValue2 v = MyValue2.createInline(rI, true); 731 long result = test32(rL, v, 2*rL); 732 Asserts.assertEQ(result, v.hashInterpreted() - rL); 733 } 734 735 @DontCompile 736 public long test33_interp(int i, MyValue2 v, long l) { 737 return v.hash() + i + l; 738 } 739 740 @Test(failOn = ALLOC + STORE + TRAP) 741 public long test33(int i, MyValue2 v, long l) { 742 return test33_interp(i, v, l); 743 } 744 745 @DontCompile 746 public void test33_verifier(boolean warmup) { 747 MyValue2 v = MyValue2.createInline(rI, true); 748 long result = test33(rI, v, rL); 749 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 750 } 751 752 @DontCompile 753 public long test34_interp(long l, MyValue2 v, int i) { 754 return v.hash() + i + l; 755 } 756 757 @Test(failOn = ALLOC + STORE + TRAP) 758 public long test34(long l, MyValue2 v, int i) { 759 return test34_interp(l, v, i); 760 } 761 762 @DontCompile 763 public void test34_verifier(boolean warmup) { 764 MyValue2 v = MyValue2.createInline(rI, true); 765 long result = test34(rL, v, rI); 766 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 767 } 768 769 @DontCompile 770 public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 771 return v1.hash() + i + l + v2.hash(); 772 } 773 774 @Test(failOn = ALLOC + STORE + TRAP) 775 public long test35(long l, MyValue1 v1, int i, MyValue2 v2) { 776 return test35_interp(l, v1, i, v2); 777 } 778 779 @DontCompile 780 public void test35_verifier(boolean warmup) { 781 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 782 MyValue2 v2 = MyValue2.createInline(rI, true); 783 long result = test35(rL, v1, rI, v2); 784 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 785 } 786 787 // test that debug info at a call is correct 788 @DontCompile 789 public long test36_interp(MyValue2 v, boolean flag) { 790 if (flag) { 791 // uncommon trap 792 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36")); 793 } 794 return v.hash(); 795 } 796 797 @Test(failOn = ALLOC + STORE + TRAP) 798 public long test36(MyValue2 v, boolean flag, long l) { 799 return test36_interp(v, flag) + l; 800 } 801 802 @DontCompile 803 public void test36_verifier(boolean warmup) { 804 MyValue2 v = MyValue2.createInline(rI, true); 805 long result = test36(v, false, rL); 806 Asserts.assertEQ(result, v.hashInterpreted() + rL); 807 if (!warmup) { 808 result = test36(v, true, rL); 809 Asserts.assertEQ(result, v.hashInterpreted() + rL); 810 } 811 } 812 813 // Test vbox and vunbox 814 @Test 815 public long test37() throws Throwable { 816 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 817 } 818 819 @DontCompile 820 public void test37_verifier(boolean warmup) { 821 try { 822 long result = test37(); 823 Asserts.assertEQ(vcc.t, result, "Field t of input and result must be equal."); 824 } catch (Throwable t) { 825 throw new RuntimeException("test 37 failed", t); 826 } 827 } 828 829 // Generate a MethodHandle that obtains field t of the 830 // derived value type 831 private static MethodHandle generateVCCUnboxLoadLongMH() { 832 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 833 "vccUnboxLoadLong", 834 MethodType.methodType(long.class, ValueCapableClass1.class), 835 CODE -> { 836 CODE. 837 aload_0(). 838 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 839 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 840 lreturn(); 841 } 842 ); 843 } 844 845 @Test 846 public int test38() throws Throwable { 847 return (int)vccUnboxLoadIntMH.invokeExact(vcc); 848 } 849 850 @DontCompile 851 public void test38_verifier(boolean warmup) { 852 try { 853 int result = test38(); 854 Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal."); 855 } catch (Throwable t) { 856 throw new RuntimeException("test 38 failed", t); 857 } 858 } 859 860 // Generate a MethodHandle that obtains field x of the 861 // derived value type 862 private static MethodHandle generateVCCUnboxLoadIntMH() { 863 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 864 "vccUnboxLoadInt", 865 MethodType.methodType(int.class, ValueCapableClass1.class), 866 CODE -> { 867 CODE. 868 aload_0(). 869 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 870 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "x", "I"). 871 ireturn(); 872 } 873 ); 874 } 875 876 @Test 877 public ValueCapableClass1 test39() throws Throwable { 878 return (ValueCapableClass1)vccUnboxBoxMH.invokeExact(vcc); 879 } 880 881 @DontCompile 882 public void test39_verifier(boolean warmup) { 883 try { 884 ValueCapableClass1 result = test39(); 885 Asserts.assertEQ(vcc.value(), result.value(), "Value of VCC and returned VCC must be equal"); 886 } catch (Throwable t) { 887 throw new RuntimeException("test 39 failed", t); 888 } 889 } 890 891 // Generate a MethodHandle that takes a value-capable class, 892 // unboxes it, then boxes it again and returns it. 893 private static MethodHandle generateVCCUnboxBoxMH() { 894 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 895 "vccUnboxBox", 896 MethodType.methodType(ValueCapableClass1.class, ValueCapableClass1.class), 897 CODE -> { 898 CODE. 899 aload_0(). 900 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 901 vbox(ValueCapableClass1.class). 902 areturn(); 903 } 904 ); 905 } 906 907 @Test 908 public int test40() throws Throwable { 909 return (int)vccUnboxBoxLoadIntMH.invokeExact(vcc); 910 } 911 912 @DontCompile 913 public void test40_verifier(boolean warmup) { 914 try { 915 int result = test40(); 916 Asserts.assertEQ(vcc.x, result, "Field x of VCC and result must be equal"); 917 } catch (Throwable t) { 918 throw new RuntimeException("Test failed in the interpeter", t); 919 } 920 } 921 922 // Generate a MethodHandle that takes a value-capable class, 923 // unboxes it, boxes it, reads a field from it, and returns the 924 // field. 925 private static MethodHandle generateVCCUnboxBoxLoadIntMH() { 926 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 927 "vccUnboxBoxLoadInt", 928 MethodType.methodType(int.class, ValueCapableClass1.class), 929 CODE -> { 930 CODE. 931 aload_0(). 932 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 933 vbox(ValueCapableClass1.class). 934 getfield(ValueCapableClass1.class, "x", "I"). 935 ireturn(); 936 } 937 ); 938 939 } 940 941 // Test value type array creation and initialization 942 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD)) 943 @Test(valid = ValueTypeArrayFlattenOn) 944 public MyValue1[] test41(int len) { 945 MyValue1[] va = new MyValue1[len]; 946 for (int i = 0; i < len; ++i) { 947 va[i] = MyValue1.createDontInline(rI, rL); 948 } 949 return va; 950 } 951 952 @DontCompile 953 public void test41_verifier(boolean warmup) { 954 int len = Math.abs(rI % 10); 955 MyValue1[] va = test41(len); 956 for (int i = 0; i < len; ++i) { 957 Asserts.assertEQ(va[i].hash(), hash()); 958 } 959 } 960 961 // Test creation of a value type array and element access 962 @Test(failOn = (LOOP + LOAD + TRAP)) 963 public long test42() { 964 MyValue1[] va = new MyValue1[1]; 965 va[0] = MyValue1.createInline(rI, rL); 966 return va[0].hash(); 967 } 968 969 @DontCompile 970 public void test42_verifier(boolean warmup) { 971 long result = test42(); 972 Asserts.assertEQ(result, hash()); 973 } 974 975 // Test receiving a value type array from the interpreter, 976 // updating its elements in a loop and computing a hash. 977 @Test(failOn = (ALLOCA)) 978 public long test43(MyValue1[] va) { 979 long result = 0; 980 for (int i = 0; i < 10; ++i) { 981 result += va[i].hash(); 982 va[i] = MyValue1.createInline(rI + 1, rL + 1); 983 } 984 return result; 985 } 986 987 @DontCompile 988 public void test43_verifier(boolean warmup) { 989 MyValue1[] va = new MyValue1[10]; 990 long expected = 0; 991 for (int i = 0; i < 10; ++i) { 992 va[i] = MyValue1.createDontInline(rI + i, rL + i); 993 expected += va[i].hash(); 994 } 995 long result = test43(va); 996 Asserts.assertEQ(expected, result); 997 for (int i = 0; i < 10; ++i) { 998 if (va[i].hash() != hash(rI + 1, rL + 1)) { 999 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1)); 1000 } 1001 } 1002 } 1003 1004 // Test returning a value type array received from the interpreter 1005 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP) 1006 public MyValue1[] test44(MyValue1[] va) { 1007 return va; 1008 } 1009 1010 @DontCompile 1011 public void test44_verifier(boolean warmup) { 1012 MyValue1[] va = new MyValue1[10]; 1013 for (int i = 0; i < 10; ++i) { 1014 va[i] = MyValue1.createDontInline(rI + i, rL + i); 1015 } 1016 va = test44(va); 1017 for (int i = 0; i < 10; ++i) { 1018 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1019 } 1020 } 1021 1022 // TODO add match rules 1023 @Test() 1024 public MyValue1[] test45(boolean b) { 1025 MyValue1[] va; 1026 if (b) { 1027 va = new MyValue1[5]; 1028 for (int i = 0; i < 5; ++i) { 1029 va[i] = MyValue1.createInline(rI, rL); 1030 } 1031 } else { 1032 va = new MyValue1[10]; 1033 for (int i = 0; i < 10; ++i) { 1034 va[i] = MyValue1.createInline(rI + i, rL + i); 1035 } 1036 } 1037 long sum = va[0].hashInterpreted(); 1038 if (b) { 1039 va[0] = MyValue1.createDontInline(rI, sum); 1040 } else { 1041 va[0] = MyValue1.createDontInline(rI + 1, sum + 1); 1042 } 1043 return va; 1044 } 1045 1046 @DontCompile 1047 public void test45_verifier(boolean warmup) { 1048 MyValue1[] va = test45(true); 1049 Asserts.assertEQ(va.length, 5); 1050 Asserts.assertEQ(va[0].hash(), hash(rI, hash())); 1051 for (int i = 1; i < 5; ++i) { 1052 Asserts.assertEQ(va[i].hash(), hash()); 1053 } 1054 va = test45(false); 1055 Asserts.assertEQ(va.length, 10); 1056 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1)); 1057 for (int i = 1; i < 10; ++i) { 1058 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1059 } 1060 } 1061 1062 // Test creation of value type array with single element 1063 @Test(failOn = LOOP + TRAP) 1064 public MyValue1 test46() { 1065 MyValue1[] va = new MyValue1[1]; 1066 return va[0]; 1067 } 1068 1069 @DontCompile 1070 public void test46_verifier(boolean warmup) { 1071 MyValue1[] va = new MyValue1[1]; 1072 MyValue1 v = test46(); 1073 Asserts.assertEQ(v.hash(), va[0].hash()); 1074 } 1075 1076 // Test default initialization of value type arrays 1077 @Test(failOn = LOAD) 1078 public MyValue1[] test47(int len) { 1079 return new MyValue1[len]; 1080 } 1081 1082 @DontCompile 1083 public void test47_verifier(boolean warmup) { 1084 int len = Math.abs(rI % 10); 1085 MyValue1[] va = new MyValue1[len]; 1086 MyValue1[] var = test47(len); 1087 for (int i = 0; i < len; ++i) { 1088 Asserts.assertEQ(va[i].hash(), var[i].hash()); 1089 } 1090 } 1091 1092 // Test creation of value type array with zero length 1093 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 1094 public MyValue1[] test48() { 1095 return new MyValue1[0]; 1096 } 1097 1098 @DontCompile 1099 public void test48_verifier(boolean warmup) { 1100 MyValue1[] va = test48(); 1101 Asserts.assertEQ(va.length, 0); 1102 } 1103 1104 // ========== Test infrastructure ========== 1105 1106 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 1107 private static final int ValueTypePassFieldsAsArgsOn = 0x1; 1108 private static final int ValueTypePassFieldsAsArgsOff = 0x2; 1109 private static final int ValueTypeArrayFlattenOn = 0x4; 1110 private static final int ValueTypeArrayFlattenOff = 0x8; 1111 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff; 1112 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 1113 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten"); 1114 private static final int COMP_LEVEL_ANY = -1; 1115 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 1116 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 1117 private static final int WARMUP = 250; 1118 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 1119 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 1120 // TODO use Platform.isComp() after merge with JDK 9 1121 private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled "); 1122 1123 // Regular expressions used to match nodes in the PrintIdeal output 1124 private static final String START = "(\\d+\\t(.*"; 1125 private static final String MID = ".*)+\\t===.*"; 1126 private static final String END = ")|"; 1127 private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END; 1128 private static final String ALLOCA = START + "CallStaticJava" + MID + "_new_array_Java" + END; 1129 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1130 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END; 1131 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1132 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END; 1133 private static final String LOOP = START + "Loop" + MID + "" + END; 1134 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap" + END; 1135 // TODO: match field values of scalar replaced object 1136 private static final String SCOBJ = "(.*# ScObj.*" + END; 1137 1138 static { 1139 // Gather all test methods and put them in Hashtable 1140 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) { 1141 Test[] annos = m.getAnnotationsByType(Test.class); 1142 if (annos.length != 0) { 1143 tests.put("ValueTypeTestBench::" + m.getName(), m); 1144 } 1145 } 1146 } 1147 1148 private static void execute_vm(String... extra_args) throws Throwable { 1149 ArrayList<String> all_args = new ArrayList(List.of( 1150 "-noverify", 1151 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI", 1152 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation", 1153 "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly", 1154 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*", 1155 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", 1156 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*" 1157 )); 1158 all_args.addAll(List.of(extra_args)); 1159 // Run tests in own process and verify output 1160 all_args.add(ValueTypeTestBench.class.getName()); 1161 all_args.add("run"); 1162 OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0])); 1163 // If ideal graph printing is enabled/supported, verify output 1164 String output = oa.getOutput(); 1165 oa.shouldHaveExitValue(0); 1166 if (output.contains("PrintIdeal enabled")) { 1167 parseOutput(output); 1168 } else { 1169 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); 1170 } 1171 } 1172 1173 public static void main(String[] args) throws Throwable { 1174 if (args.length == 0) { 1175 String field_as_args; 1176 String array_flatten; 1177 if (ValueTypePassFieldsAsArgs) { 1178 field_as_args = "-XX:+ValueTypePassFieldsAsArgs"; 1179 } else { 1180 field_as_args = "-XX:-ValueTypePassFieldsAsArgs"; 1181 } 1182 if (ValueTypeArrayFlatten) { 1183 array_flatten = "-XX:+ValueArrayFlatten"; 1184 } else { 1185 array_flatten = "-XX:-ValueArrayFlatten"; 1186 } 1187 execute_vm("-XX:+UnlockExperimentalVMOptions", field_as_args, array_flatten); 1188 execute_vm("-XX:+AlwaysIncrementalInline", "-XX:+UnlockExperimentalVMOptions", field_as_args, array_flatten); 1189 } else { 1190 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 1191 System.out.println("PrintIdeal enabled"); 1192 } 1193 // Execute tests 1194 ValueTypeTestBench bench = new ValueTypeTestBench(); 1195 bench.run(); 1196 } 1197 } 1198 1199 public static void parseOutput(String output) throws Exception { 1200 String split = "b compiler.valhalla.valuetypes."; 1201 String[] compilations = output.split(split); 1202 // Print header 1203 System.out.println(compilations[0]); 1204 // Iterate over compilation output 1205 for (String graph : compilations) { 1206 String[] lines = graph.split("\\n"); 1207 if (lines[0].contains("@")) { 1208 continue; // Ignore OSR compilations 1209 } 1210 String testName = lines[0].split(" ")[0]; 1211 Method test = tests.get(testName); 1212 if (test == null) { 1213 // Skip helper methods 1214 continue; 1215 } 1216 if (PRINT_GRAPH) { 1217 System.out.println("\nGraph for " + graph); 1218 } 1219 // Parse graph using regular expressions to determine if it contains forbidden nodes 1220 Test[] annos = test.getAnnotationsByType(Test.class); 1221 Test anno = null; 1222 for (Test a : annos) { 1223 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 1224 assert anno == null; 1225 anno = a; 1226 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 1227 assert anno == null; 1228 anno = a; 1229 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 1230 assert anno == null; 1231 anno = a; 1232 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 1233 assert anno == null; 1234 anno = a; 1235 } 1236 } 1237 assert anno != null; 1238 String regexFail = anno.failOn(); 1239 if (!regexFail.isEmpty()) { 1240 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 1241 Matcher matcher = pattern.matcher(graph); 1242 boolean found = matcher.find(); 1243 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 1244 } 1245 String[] regexMatch = anno.match(); 1246 int[] matchCount = anno.matchCount(); 1247 for (int i = 0; i < regexMatch.length; ++i) { 1248 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 1249 Matcher matcher = pattern.matcher(graph); 1250 int count = 0; 1251 String nodes = ""; 1252 while (matcher.find()) { 1253 count++; 1254 nodes += matcher.group() + "\n"; 1255 } 1256 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 1257 } 1258 tests.remove(testName); 1259 System.out.println(testName + " passed"); 1260 } 1261 // Check if all tests were compiled 1262 if (tests.size() != 0) { 1263 for (String name : tests.keySet()) { 1264 System.out.println("Test '" + name + "' not compiled!"); 1265 } 1266 throw new RuntimeException("Not all tests were compiled"); 1267 } 1268 } 1269 1270 public void setup(Method[] methods) { 1271 for (Method m : methods) { 1272 if (m.isAnnotationPresent(Test.class)) { 1273 // Don't inline tests 1274 WHITE_BOX.testSetDontInlineMethod(m, true); 1275 } 1276 if (m.isAnnotationPresent(DontCompile.class)) { 1277 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 1278 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 1279 } 1280 if (m.isAnnotationPresent(ForceInline.class)) { 1281 WHITE_BOX.testSetForceInlineMethod(m, true); 1282 } else if (m.isAnnotationPresent(DontInline.class)) { 1283 WHITE_BOX.testSetDontInlineMethod(m, true); 1284 } 1285 } 1286 } 1287 1288 public void run() throws Exception { 1289 System.out.format("rI = %d, rL = %d\n", rI, rL); 1290 setup(this.getClass().getDeclaredMethods()); 1291 setup(MyValue1.class.getDeclaredMethods()); 1292 setup(MyValue2.class.getDeclaredMethods()); 1293 1294 // TODO enable this after JDK 9 merge and verify that it's compiled 1295 //WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION); 1296 1297 // Execute tests 1298 for (Method test : tests.values()) { 1299 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class); 1300 // Warmup using verifier method 1301 for (int i = 0; i < WARMUP; ++i) { 1302 verifier.invoke(this, true); 1303 } 1304 // Trigger compilation 1305 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION); 1306 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 1307 // Check result 1308 verifier.invoke(this, false); 1309 } 1310 } 1311 } 1312 1313 // Mark method as test 1314 @Retention(RetentionPolicy.RUNTIME) 1315 @Repeatable(Tests.class) 1316 @interface Test { 1317 // Regular expression used to match forbidden IR nodes 1318 // in the C2 IR emitted for this test. 1319 String failOn() default ""; 1320 // Regular expressions used to match and count IR nodes. 1321 String[] match() default { }; 1322 int[] matchCount() default { }; 1323 int valid() default ValueTypeTestBench.AllFlags; 1324 } 1325 1326 @Retention(RetentionPolicy.RUNTIME) 1327 @interface Tests { 1328 Test[] value(); 1329 } 1330 1331 // Force method inlining during compilation 1332 @Retention(RetentionPolicy.RUNTIME) 1333 @interface ForceInline { } 1334 1335 // Prevent method inlining during compilation 1336 @Retention(RetentionPolicy.RUNTIME) 1337 @interface DontInline { } 1338 1339 // Prevent method compilation 1340 @Retention(RetentionPolicy.RUNTIME) 1341 @interface DontCompile { } --- EOF ---