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 * @requires os.simpleArch == "x64" 30 * @build compiler.valhalla.valuetypes.ValueTypeTestBench 31 * @run main ClassFileInstaller sun.hotspot.WhiteBox 32 * @run main ClassFileInstaller jdk.test.lib.Platform 33 * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 34 * -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten -XX:+VerifyAdapterSharing 35 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench 36 * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 37 * -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten 38 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench 39 * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 40 * -XX:+UnlockExperimentalVMOptions -XX:+AlwaysIncrementalInline -XX:+ValueArrayFlatten 41 * -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench 42 */ 43 44 package compiler.valhalla.valuetypes; 45 46 import compiler.whitebox.CompilerWhiteBoxTest; 47 import jdk.internal.misc.Unsafe; 48 import jdk.test.lib.Asserts; 49 import jdk.test.lib.Platform; 50 import jdk.test.lib.ProcessTools; 51 import jdk.test.lib.OutputAnalyzer; 52 import jdk.test.lib.Utils; 53 import sun.hotspot.WhiteBox; 54 55 import java.lang.annotation.Retention; 56 import java.lang.annotation.RetentionPolicy; 57 import java.lang.annotation.Repeatable; 58 import java.lang.invoke.*; 59 import java.lang.reflect.Method; 60 import java.util.ArrayList; 61 import java.util.Arrays; 62 import java.util.Hashtable; 63 import java.util.List; 64 import java.util.regex.Matcher; 65 import java.util.regex.Pattern; 66 import jdk.experimental.value.*; 67 68 // Test value types 69 __ByValue final class MyValue1 { 70 static int s; 71 static final long sf = ValueTypeTestBench.rL; 72 final int x; 73 final long y; 74 final short z; 75 final MyValue2 v1; 76 final MyValue2 v2; 77 static final MyValue2 v3 = MyValue2.createInline(ValueTypeTestBench.rI, true); 78 final int c; 79 80 private MyValue1(int x, long y, short z, MyValue2 v1, MyValue2 v2, int c) { 81 s = x; 82 this.x = x; 83 this.y = y; 84 this.z = z; 85 this.v1 = v1; 86 this.v2 = v2; 87 this.c = c; 88 } 89 90 private MyValue1() { 91 s = 0; 92 this.x = 0; 93 this.y = 0; 94 this.z = 0; 95 this.v1 = MyValue2.createDefaultInline(); 96 this.v2 = MyValue2.createDefaultInline(); 97 this.c = 0; 98 } 99 100 @DontInline 101 public static MyValue1 createDontInline(int x, long y) { 102 return __Make MyValue1(x, y, (short)x, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI); 103 } 104 105 @ForceInline 106 public static MyValue1 createInline(int x, long y) { 107 return __Make MyValue1(x, y, (short)x, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI); 108 } 109 110 @DontInline 111 __ValueFactory static MyValue1 createDefaultDontInline() { 112 return __MakeDefault MyValue1(); 113 } 114 115 @ForceInline 116 __ValueFactory static MyValue1 createDefaultInline() { 117 return __MakeDefault MyValue1(); 118 } 119 120 @DontInline 121 static MyValue1 createWithFieldsDontInline(int x, long y) { 122 MyValue1 v = createDefaultInline(); 123 v = setX(v, x); 124 v = setY(v, y); 125 v = setZ(v, (short)x); 126 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y)); 127 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y)); 128 v = setC(v, ValueTypeTestBench.rI); 129 return v; 130 } 131 132 @ForceInline 133 static MyValue1 createWithFieldsInline(int x, long y) { 134 MyValue1 v = createDefaultInline(); 135 v = setX(v, x); 136 v = setY(v, y); 137 v = setZ(v, (short)x); 138 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y)); 139 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y)); 140 v = setC(v, ValueTypeTestBench.rI); 141 return v; 142 } 143 144 @ForceInline 145 public long hash() { 146 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash(); 147 } 148 149 @DontCompile 150 public long hashInterpreted() { 151 return s + sf + x + y + z + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted(); 152 } 153 154 @ForceInline 155 public void print() { 156 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", v1["); 157 v1.print(); 158 System.out.print("], v2["); 159 v2.print(); 160 System.out.print("], v3["); 161 v3.print(); 162 System.out.print("], c=" + c); 163 } 164 165 @ForceInline 166 __ValueFactory static MyValue1 setX(MyValue1 v, int x) { 167 v.x = x; 168 return v; 169 } 170 171 @ForceInline 172 __ValueFactory static MyValue1 setY(MyValue1 v, long y) { 173 v.y = y; 174 return v; 175 } 176 177 @ForceInline 178 __ValueFactory static MyValue1 setZ(MyValue1 v, short z) { 179 v.z = z; 180 return v; 181 } 182 183 @ForceInline 184 __ValueFactory static MyValue1 setC(MyValue1 v, int c) { 185 v.c = c; 186 return v; 187 } 188 189 @ForceInline 190 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) { 191 v.v1 = v1; 192 return v; 193 } 194 195 @ForceInline 196 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) { 197 v.v2 = v2; 198 return v; 199 } 200 } 201 202 __ByValue final class MyValue2 { 203 final int x; 204 final byte y; 205 final boolean b; 206 final long c; 207 208 private MyValue2(int x, byte y, boolean b, long c) { 209 this.x = x; 210 this.y = y; 211 this.b = b; 212 this.c = c; 213 } 214 215 private MyValue2() { 216 this.x = 0; 217 this.y = 0; 218 this.b = false; 219 this.c = 0; 220 } 221 222 @ForceInline 223 public static MyValue2 createInline(int x, boolean b) { 224 return __Make MyValue2(x, (byte)x, b, ValueTypeTestBench.rL); 225 } 226 227 @ForceInline 228 __ValueFactory public static MyValue2 createDefaultInline() { 229 return __MakeDefault MyValue2(); 230 } 231 232 @ForceInline 233 public static MyValue2 createWithFieldsInline(int x, boolean b) { 234 MyValue2 v = createDefaultInline(); 235 v = setX(v, x); 236 v = setY(v, (byte)x); 237 v = setB(v, b); 238 v = setC(v, ValueTypeTestBench.rL); 239 return v; 240 } 241 242 @ForceInline 243 public long hash() { 244 return x + y + (b ? 0 : 1) + c; 245 } 246 247 @DontInline 248 public long hashInterpreted() { 249 return x + y + (b ? 0 : 1) + c; 250 } 251 252 @ForceInline 253 public void print() { 254 System.out.print("x=" + x + "y=" + y + ", b=" + b + ", c=" + c); 255 } 256 257 @ForceInline 258 __ValueFactory static MyValue2 setX(MyValue2 v, int x) { 259 v.x = x; 260 return v; 261 } 262 263 @ForceInline 264 __ValueFactory static MyValue2 setY(MyValue2 v, byte y) { 265 v.y = y; 266 return v; 267 } 268 269 @ForceInline 270 __ValueFactory static MyValue2 setC(MyValue2 v, long c) { 271 v.c = c; 272 return v; 273 } 274 275 @ForceInline 276 __ValueFactory static MyValue2 setB(MyValue2 v, boolean b) { 277 v.b = b; 278 return v; 279 } 280 } 281 282 public class ValueTypeTestBench { 283 // Print ideal graph after execution of each test 284 private static final boolean PRINT_GRAPH = true; 285 286 // Random test values 287 public static final int rI = Utils.getRandomInstance().nextInt() % 1000; 288 public static final long rL = Utils.getRandomInstance().nextLong() % 1000; 289 290 public ValueTypeTestBench() { 291 val3 = MyValue1.createInline(rI, rL); 292 } 293 294 // MethodHandles and value-capable class instance needed for testing vbox/vunbox 295 private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH(); 296 private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH(); 297 private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH(); 298 private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH(); 299 private static final MethodHandle nullvccUnboxLoadLongMH = generateNullVCCUnboxLoadLongMH(); 300 private static final MethodHandle objectUnboxLoadLongMH = generateObjectUnboxLoadLongMH(); 301 private static final MethodHandle objectBoxMH = generateObjectBoxMH(); 302 private static final MethodHandle checkedvccUnboxLoadLongMH = generateCheckedVCCUnboxLoadLongMH(); 303 304 private static final ValueCapableClass1 vcc = ValueCapableClass1.create(rL, rI, (short)rI, (short)rI); 305 private static final ValueCapableClass2 vcc2 = ValueCapableClass2.create(rL + 1); 306 307 // ========== Helper methods ========== 308 309 public long hash() { 310 return hash(rI, rL); 311 } 312 313 public long hash(int x, long y) { 314 return MyValue1.createInline(x, y).hash(); 315 } 316 317 // ========== Test definitions ========== 318 319 // Receive value type through call to interpreter 320 @Test(failOn = ALLOC + STORE + TRAP) 321 public long test1() { 322 MyValue1 v = MyValue1.createDontInline(rI, rL); 323 return v.hash(); 324 } 325 326 @DontCompile 327 public void test1_verifier(boolean warmup) { 328 long result = test1(); 329 Asserts.assertEQ(result, hash()); 330 } 331 332 // Receive value type from interpreter via parameter 333 @Test(failOn = ALLOC + STORE + TRAP) 334 public long test2(MyValue1 v) { 335 return v.hash(); 336 } 337 338 @DontCompile 339 public void test2_verifier(boolean warmup) { 340 MyValue1 v = MyValue1.createDontInline(rI, rL); 341 long result = test2(v); 342 Asserts.assertEQ(result, hash()); 343 } 344 345 // Return incoming value type without accessing fields 346 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 11}, failOn = LOAD + TRAP) 347 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP) 348 public MyValue1 test3(MyValue1 v) { 349 return v; 350 } 351 352 @DontCompile 353 public void test3_verifier(boolean warmup) { 354 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 355 MyValue1 v2 = test3(v1); 356 Asserts.assertEQ(v1.x, v2.x); 357 Asserts.assertEQ(v1.y, v2.y); 358 } 359 360 // Create a value type in compiled code and only use fields. 361 // Allocation should go away because value type does not escape. 362 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 363 public long test4() { 364 MyValue1 v = MyValue1.createInline(rI, rL); 365 return v.hash(); 366 } 367 368 @DontCompile 369 public void test4_verifier(boolean warmup) { 370 long result = test4(); 371 Asserts.assertEQ(result, hash()); 372 } 373 374 // Create a value type in compiled code and pass it to 375 // an inlined compiled method via a call. 376 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 377 public long test5() { 378 MyValue1 v = MyValue1.createInline(rI, rL); 379 return test5Inline(v); 380 } 381 382 @ForceInline 383 public long test5Inline(MyValue1 v) { 384 return v.hash(); 385 } 386 387 @DontCompile 388 public void test5_verifier(boolean warmup) { 389 long result = test5(); 390 Asserts.assertEQ(result, hash()); 391 } 392 393 // Create a value type in compiled code and pass it to 394 // the interpreter via a call. 395 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC) 396 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 397 public long test6() { 398 MyValue1 v = MyValue1.createInline(rI, rL); 399 // Pass to interpreter 400 return v.hashInterpreted(); 401 } 402 403 @DontCompile 404 public void test6_verifier(boolean warmup) { 405 long result = test6(); 406 Asserts.assertEQ(result, hash()); 407 } 408 409 // Create a value type in compiled code and pass it to 410 // the interpreter by returning. 411 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 412 public MyValue1 test7(int x, long y) { 413 return MyValue1.createInline(x, y); 414 } 415 416 @DontCompile 417 public void test7_verifier(boolean warmup) { 418 MyValue1 v = test7(rI, rL); 419 Asserts.assertEQ(v.hash(), hash()); 420 } 421 422 // Merge value types created from two branches 423 @Test(failOn = ALLOC + STORE + TRAP) 424 public long test8(boolean b) { 425 MyValue1 v; 426 if (b) { 427 v = MyValue1.createInline(rI, rL); 428 } else { 429 v = MyValue1.createDontInline(rI + 1, rL + 1); 430 } 431 return v.hash(); 432 } 433 434 @DontCompile 435 public void test8_verifier(boolean warmup) { 436 Asserts.assertEQ(test8(true), hash()); 437 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1)); 438 } 439 440 // Merge value types created from two branches 441 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {10}, failOn = TRAP + ALLOC + STORE) 442 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP) 443 public MyValue1 test9(boolean b) { 444 MyValue1 v; 445 if (b) { 446 // Value type is not allocated 447 v = MyValue1.createInline(rI, rL); 448 } else { 449 // Value type is allocated by the callee 450 v = MyValue1.createDontInline(rI + 1, rL + 1); 451 } 452 // Need to allocate value type if 'b' is true 453 long sum = v.hashInterpreted(); 454 if (b) { 455 v = MyValue1.createDontInline(rI, sum); 456 } else { 457 v = MyValue1.createDontInline(rI, sum + 1); 458 } 459 // Don't need to allocate value type because both branches allocate 460 return v; 461 } 462 463 @DontCompile 464 public void test9_verifier(boolean warmup) { 465 MyValue1 v = test9(true); 466 Asserts.assertEQ(v.x, rI); 467 Asserts.assertEQ(v.y, hash()); 468 v = test9(false); 469 Asserts.assertEQ(v.x, rI); 470 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1); 471 } 472 473 // Merge value types created in a loop (not inlined) 474 @Test(failOn = ALLOC + STORE + TRAP) 475 public long test10(int x, long y) { 476 MyValue1 v = MyValue1.createDontInline(x, y); 477 for (int i = 0; i < 10; ++i) { 478 v = MyValue1.createDontInline(v.x + 1, v.y + 1); 479 } 480 return v.hash(); 481 } 482 483 @DontCompile 484 public void test10_verifier(boolean warmup) { 485 long result = test10(rI, rL); 486 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 487 } 488 489 // Merge value types created in a loop (inlined) 490 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 491 public long test11(int x, long y) { 492 MyValue1 v = MyValue1.createInline(x, y); 493 for (int i = 0; i < 10; ++i) { 494 v = MyValue1.createInline(v.x + 1, v.y + 1); 495 } 496 return v.hash(); 497 } 498 499 @DontCompile 500 public void test11_verifier(boolean warmup) { 501 long result = test11(rI, rL); 502 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 503 } 504 505 // Test loop with uncommon trap referencing a value type 506 @Test(match = {TRAP, SCOBJ}, matchCount = {1, -1 /* at least 1 */}, failOn = LOAD) 507 public long test12(boolean b) { 508 MyValue1 v = MyValue1.createInline(rI, rL); 509 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 510 for (int i = 0; i < va.length; ++i) { 511 va[i] = MyValue1.createInline(rI, rL); 512 } 513 long result = rL; 514 for (int i = 0; i < 1000; ++i) { 515 if (b) { 516 result += v.x; 517 } else { 518 // Uncommon trap referencing v. We delegate allocation to the 519 // interpreter by adding a SafePointScalarObjectNode. 520 result = v.hashInterpreted(); 521 for (int j = 0; j < va.length; ++j) { 522 result += va[j].hash(); 523 } 524 } 525 } 526 return result; 527 } 528 529 @DontCompile 530 public void test12_verifier(boolean warmup) { 531 long result = test12(warmup); 532 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 533 } 534 535 // Test loop with uncommon trap referencing a value type 536 @Test(match = {TRAP}, matchCount = {1}) 537 public long test13(boolean b) { 538 MyValue1 v = MyValue1.createDontInline(rI, rL); 539 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 540 for (int i = 0; i < va.length; ++i) { 541 va[i] = MyValue1.createDontInline(rI, rL); 542 } 543 long result = rL; 544 for (int i = 0; i < 1000; ++i) { 545 if (b) { 546 result += v.x; 547 } else { 548 // Uncommon trap referencing v. Should not allocate 549 // but just pass the existing oop to the uncommon trap. 550 result = v.hashInterpreted(); 551 for (int j = 0; j < va.length; ++j) { 552 result += va[j].hashInterpreted(); 553 } 554 } 555 } 556 return result; 557 } 558 559 @DontCompile 560 public void test13_verifier(boolean warmup) { 561 long result = test13(warmup); 562 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 563 } 564 565 // Create a value type in a non-inlined method and then call a 566 // non-inlined method on that value type. 567 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {10}) 568 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP)) 569 public long test14() { 570 MyValue1 v = MyValue1.createDontInline(rI, rL); 571 return v.hashInterpreted(); 572 } 573 574 @DontCompile 575 public void test14_verifier(boolean b) { 576 long result = test14(); 577 Asserts.assertEQ(result, hash()); 578 } 579 580 // Create a value type in an inlined method and then call a 581 // non-inlined method on that value type. 582 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC)) 583 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1}) 584 public long test15() { 585 MyValue1 v = MyValue1.createInline(rI, rL); 586 return v.hashInterpreted(); 587 } 588 589 @DontCompile 590 public void test15_verifier(boolean b) { 591 long result = test15(); 592 Asserts.assertEQ(result, hash()); 593 } 594 595 // Create a value type in a non-inlined method and then call an 596 // inlined method on that value type. 597 @Test(failOn = (ALLOC + STORE + TRAP)) 598 public long test16() { 599 MyValue1 v = MyValue1.createDontInline(rI, rL); 600 return v.hash(); 601 } 602 603 @DontCompile 604 public void test16_verifier(boolean b) { 605 long result = test16(); 606 Asserts.assertEQ(result, hash()); 607 } 608 609 // Create a value type in an inlined method and then call an 610 // inlined method on that value type. 611 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 612 public long test17() { 613 MyValue1 v = MyValue1.createInline(rI, rL); 614 return v.hash(); 615 } 616 617 @DontCompile 618 public void test17_verifier(boolean b) { 619 long result = test17(); 620 Asserts.assertEQ(result, hash()); 621 } 622 623 // Create a value type in compiled code and pass it to the 624 // interpreter via a call. The value is live at the first call so 625 // debug info should include a reference to all its fields. 626 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 627 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 628 public long test18() { 629 MyValue1 v = MyValue1.createInline(rI, rL); 630 v.hashInterpreted(); 631 return v.hashInterpreted(); 632 } 633 634 @DontCompile 635 public void test18_verifier(boolean warmup) { 636 long result = test18(); 637 Asserts.assertEQ(result, hash()); 638 } 639 640 // Create a value type in compiled code and pass it to the 641 // interpreter via a call. The value type is passed twice but 642 // should only be allocated once. 643 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 644 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 645 public long test19() { 646 MyValue1 v = MyValue1.createInline(rI, rL); 647 return sumValue(v, v); 648 } 649 650 @DontCompile 651 public long sumValue(MyValue1 v, MyValue1 dummy) { 652 return v.hash(); 653 } 654 655 @DontCompile 656 public void test19_verifier(boolean warmup) { 657 long result = test19(); 658 Asserts.assertEQ(result, hash()); 659 } 660 661 // Create a value type (array) in compiled code and pass it to the 662 // interpreter via a call. The value type is live at the uncommon 663 // trap: verify that deoptimization causes the value type to be 664 // correctly allocated. 665 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE) 666 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {2}, failOn = LOAD) 667 public long test20(boolean deopt) { 668 MyValue1 v = MyValue1.createInline(rI, rL); 669 MyValue1[] va = new MyValue1[3]; 670 if (deopt) { 671 // uncommon trap 672 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20")); 673 } 674 return v.hashInterpreted() + va[0].hashInterpreted() + 675 va[1].hashInterpreted() + va[2].hashInterpreted(); 676 } 677 678 @DontCompile 679 public void test20_verifier(boolean warmup) { 680 MyValue1[] va = new MyValue1[42]; 681 long result = test20(!warmup); 682 Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash()); 683 } 684 685 // Value type fields in regular object 686 MyValue1 val1; 687 MyValue2 val2; 688 final MyValue1 val3; 689 static MyValue1 val4; 690 static final MyValue1 val5 = MyValue1.createInline(rI, rL); 691 692 // Test value type fields in objects 693 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP)) 694 public long test21(int x, long y) { 695 // Compute hash of value type fields 696 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 697 // Update fields 698 val1 = MyValue1.createInline(x, y); 699 val2 = MyValue2.createInline(x, true); 700 val4 = MyValue1.createInline(x, y); 701 return result; 702 } 703 704 @DontCompile 705 public void test21_verifier(boolean warmup) { 706 // Check if hash computed by test18 is correct 707 val1 = MyValue1.createInline(rI, rL); 708 val2 = val1.v2; 709 // val3 is initialized in the constructor 710 val4 = val1; 711 // val5 is initialized in the static initializer 712 long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 713 long result = test21(rI + 1, rL + 1); 714 Asserts.assertEQ(result, hash); 715 // Check if value type fields were updated 716 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1)); 717 Asserts.assertEQ(val2.hash(), MyValue2.createInline(rI + 1, true).hash()); 718 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1)); 719 } 720 721 // Test folding of constant value type fields 722 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 723 public long test22() { 724 // This should be constant folded 725 return val5.hash() + val5.v3.hash(); 726 } 727 728 @DontCompile 729 public void test22_verifier(boolean warmup) { 730 long result = test22(); 731 Asserts.assertEQ(result, val5.hash() + val5.v3.hash()); 732 } 733 734 // Test OSR compilation 735 @Test() 736 public long test23() { 737 MyValue1 v = MyValue1.createInline(rI, rL); 738 MyValue1[] va = new MyValue1[Math.abs(rI) % 3]; 739 for (int i = 0; i < va.length; ++i) { 740 va[i] = MyValue1.createInline(rI, rL); 741 } 742 long result = 0; 743 // Long loop to trigger OSR compilation 744 for (int i = 0 ; i < 100_000; ++i) { 745 // Reference local value type in interpreter state 746 result = v.hash(); 747 for (int j = 0; j < va.length; ++j) { 748 result += va[j].hash(); 749 } 750 } 751 return result; 752 } 753 754 @DontCompile 755 public void test23_verifier(boolean warmup) { 756 long result = test23(); 757 Asserts.assertEQ(result, ((Math.abs(rI) % 3) + 1) * hash()); 758 } 759 760 // Test interpreter to compiled code with various signatures 761 @Test(failOn = ALLOC + STORE + TRAP) 762 public long test24(MyValue2 v) { 763 return v.hash(); 764 } 765 766 @DontCompile 767 public void test24_verifier(boolean warmup) { 768 MyValue2 v = MyValue2.createInline(rI, true); 769 long result = test24(v); 770 Asserts.assertEQ(result, v.hashInterpreted()); 771 } 772 773 @Test(failOn = ALLOC + STORE + TRAP) 774 public long test25(int i1, MyValue2 v, int i2) { 775 return v.hash() + i1 - i2; 776 } 777 778 @DontCompile 779 public void test25_verifier(boolean warmup) { 780 MyValue2 v = MyValue2.createInline(rI, true); 781 long result = test25(rI, v, 2*rI); 782 Asserts.assertEQ(result, v.hashInterpreted() - rI); 783 } 784 785 @Test(failOn = ALLOC + STORE + TRAP) 786 public long test26(long l1, MyValue2 v, long l2) { 787 return v.hash() + l1 - l2; 788 } 789 790 @DontCompile 791 public void test26_verifier(boolean warmup) { 792 MyValue2 v = MyValue2.createInline(rI, true); 793 long result = test26(rL, v, 2*rL); 794 Asserts.assertEQ(result, v.hashInterpreted() - rL); 795 } 796 797 @Test(failOn = ALLOC + STORE + TRAP) 798 public long test27(int i, MyValue2 v, long l) { 799 return v.hash() + i + l; 800 } 801 802 @DontCompile 803 public void test27_verifier(boolean warmup) { 804 MyValue2 v = MyValue2.createInline(rI, true); 805 long result = test27(rI, v, rL); 806 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 807 } 808 809 @Test(failOn = ALLOC + STORE + TRAP) 810 public long test28(long l, MyValue2 v, int i) { 811 return v.hash() + i + l; 812 } 813 814 @DontCompile 815 public void test28_verifier(boolean warmup) { 816 MyValue2 v = MyValue2.createInline(rI, true); 817 long result = test28(rL, v, rI); 818 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 819 } 820 821 @Test(failOn = ALLOC + STORE + TRAP) 822 public long test29(long l, MyValue1 v1, int i, MyValue2 v2) { 823 return v1.hash() + i + l + v2.hash(); 824 } 825 826 @DontCompile 827 public void test29_verifier(boolean warmup) { 828 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 829 MyValue2 v2 = MyValue2.createInline(rI, true); 830 long result = test29(rL, v1, rI, v2); 831 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 832 } 833 834 // Test compiled code to interpreter with various signatures 835 @DontCompile 836 public long test30_interp(MyValue2 v) { 837 return v.hash(); 838 } 839 840 @Test(failOn = ALLOC + STORE + TRAP) 841 public long test30(MyValue2 v) { 842 return test30_interp(v); 843 } 844 845 @DontCompile 846 public void test30_verifier(boolean warmup) { 847 MyValue2 v = MyValue2.createInline(rI, true); 848 long result = test30(v); 849 Asserts.assertEQ(result, v.hashInterpreted()); 850 } 851 852 @DontCompile 853 public long test31_interp(int i1, MyValue2 v, int i2) { 854 return v.hash() + i1 - i2; 855 } 856 857 @Test(failOn = ALLOC + STORE + TRAP) 858 public long test31(int i1, MyValue2 v, int i2) { 859 return test31_interp(i1, v, i2); 860 } 861 862 @DontCompile 863 public void test31_verifier(boolean warmup) { 864 MyValue2 v = MyValue2.createInline(rI, true); 865 long result = test31(rI, v, 2*rI); 866 Asserts.assertEQ(result, v.hashInterpreted() - rI); 867 } 868 869 @DontCompile 870 public long test32_interp(long l1, MyValue2 v, long l2) { 871 return v.hash() + l1 - l2; 872 } 873 874 @Test(failOn = ALLOC + STORE + TRAP) 875 public long test32(long l1, MyValue2 v, long l2) { 876 return test32_interp(l1, v, l2); 877 } 878 879 @DontCompile 880 public void test32_verifier(boolean warmup) { 881 MyValue2 v = MyValue2.createInline(rI, true); 882 long result = test32(rL, v, 2*rL); 883 Asserts.assertEQ(result, v.hashInterpreted() - rL); 884 } 885 886 @DontCompile 887 public long test33_interp(int i, MyValue2 v, long l) { 888 return v.hash() + i + l; 889 } 890 891 @Test(failOn = ALLOC + STORE + TRAP) 892 public long test33(int i, MyValue2 v, long l) { 893 return test33_interp(i, v, l); 894 } 895 896 @DontCompile 897 public void test33_verifier(boolean warmup) { 898 MyValue2 v = MyValue2.createInline(rI, true); 899 long result = test33(rI, v, rL); 900 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 901 } 902 903 @DontCompile 904 public long test34_interp(long l, MyValue2 v, int i) { 905 return v.hash() + i + l; 906 } 907 908 @Test(failOn = ALLOC + STORE + TRAP) 909 public long test34(long l, MyValue2 v, int i) { 910 return test34_interp(l, v, i); 911 } 912 913 @DontCompile 914 public void test34_verifier(boolean warmup) { 915 MyValue2 v = MyValue2.createInline(rI, true); 916 long result = test34(rL, v, rI); 917 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 918 } 919 920 @DontCompile 921 public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 922 return v1.hash() + i + l + v2.hash(); 923 } 924 925 @Test(failOn = ALLOC + STORE + TRAP) 926 public long test35(long l, MyValue1 v1, int i, MyValue2 v2) { 927 return test35_interp(l, v1, i, v2); 928 } 929 930 @DontCompile 931 public void test35_verifier(boolean warmup) { 932 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 933 MyValue2 v2 = MyValue2.createInline(rI, true); 934 long result = test35(rL, v1, rI, v2); 935 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 936 } 937 938 // test that debug info at a call is correct 939 @DontCompile 940 public long test36_interp(MyValue2 v, MyValue1[] va, boolean deopt) { 941 if (deopt) { 942 // uncommon trap 943 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36")); 944 } 945 return v.hash() + va[0].hash() + va[1].hash(); 946 } 947 948 @Test(failOn = ALLOC + STORE + TRAP) 949 public long test36(MyValue2 v, MyValue1[] va, boolean flag, long l) { 950 return test36_interp(v, va, flag) + l; 951 } 952 953 @DontCompile 954 public void test36_verifier(boolean warmup) { 955 MyValue2 v = MyValue2.createInline(rI, true); 956 MyValue1[] va = new MyValue1[2]; 957 va[0] = MyValue1.createDontInline(rI, rL); 958 va[1] = MyValue1.createDontInline(rI, rL); 959 long result = test36(v, va, !warmup, rL); 960 Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL); 961 } 962 963 // Test vbox and vunbox 964 @Test 965 public long test37() throws Throwable { 966 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 967 } 968 969 @DontCompile 970 public void test37_verifier(boolean warmup) { 971 try { 972 long result = test37(); 973 Asserts.assertEQ(vcc.t, result, "Field t of input and result must be equal."); 974 } catch (Throwable t) { 975 throw new RuntimeException("test 37 failed", t); 976 } 977 } 978 979 // Generate a MethodHandle that obtains field t of the 980 // derived value type 981 private static MethodHandle generateVCCUnboxLoadLongMH() { 982 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 983 "vccUnboxLoadLong", 984 MethodType.methodType(long.class, ValueCapableClass1.class), 985 CODE -> { 986 CODE. 987 aload_0(). 988 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 989 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 990 lreturn(); 991 } 992 ); 993 } 994 995 @Test 996 public int test38() throws Throwable { 997 return (int)vccUnboxLoadIntMH.invokeExact(vcc); 998 } 999 1000 @DontCompile 1001 public void test38_verifier(boolean warmup) { 1002 try { 1003 int result = test38(); 1004 Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal."); 1005 } catch (Throwable t) { 1006 throw new RuntimeException("test 38 failed", t); 1007 } 1008 } 1009 1010 // Generate a MethodHandle that obtains field x of the 1011 // derived value type 1012 private static MethodHandle generateVCCUnboxLoadIntMH() { 1013 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1014 "vccUnboxLoadInt", 1015 MethodType.methodType(int.class, ValueCapableClass1.class), 1016 CODE -> { 1017 CODE. 1018 aload_0(). 1019 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1020 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "x", "I"). 1021 ireturn(); 1022 } 1023 ); 1024 } 1025 1026 @Test 1027 public ValueCapableClass1 test39() throws Throwable { 1028 return (ValueCapableClass1)vccUnboxBoxMH.invokeExact(vcc); 1029 } 1030 1031 @DontCompile 1032 public void test39_verifier(boolean warmup) { 1033 try { 1034 ValueCapableClass1 result = test39(); 1035 Asserts.assertEQ(vcc.value(), result.value(), "Value of VCC and returned VCC must be equal"); 1036 } catch (Throwable t) { 1037 throw new RuntimeException("test 39 failed", t); 1038 } 1039 } 1040 1041 // Generate a MethodHandle that takes a value-capable class, 1042 // unboxes it, then boxes it again and returns it. 1043 private static MethodHandle generateVCCUnboxBoxMH() { 1044 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1045 "vccUnboxBox", 1046 MethodType.methodType(ValueCapableClass1.class, ValueCapableClass1.class), 1047 CODE -> { 1048 CODE. 1049 aload_0(). 1050 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1051 vbox(ValueCapableClass1.class). 1052 areturn(); 1053 } 1054 ); 1055 } 1056 1057 @Test 1058 public int test40() throws Throwable { 1059 return (int)vccUnboxBoxLoadIntMH.invokeExact(vcc); 1060 } 1061 1062 @DontCompile 1063 public void test40_verifier(boolean warmup) { 1064 try { 1065 int result = test40(); 1066 Asserts.assertEQ(vcc.x, result, "Field x of VCC and result must be equal"); 1067 } catch (Throwable t) { 1068 throw new RuntimeException("Test failed in the interpeter", t); 1069 } 1070 } 1071 1072 // Generate a MethodHandle that takes a value-capable class, 1073 // unboxes it, boxes it, reads a field from it, and returns the 1074 // field. 1075 private static MethodHandle generateVCCUnboxBoxLoadIntMH() { 1076 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1077 "vccUnboxBoxLoadInt", 1078 MethodType.methodType(int.class, ValueCapableClass1.class), 1079 CODE -> { 1080 CODE. 1081 aload_0(). 1082 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1083 vbox(ValueCapableClass1.class). 1084 getfield(ValueCapableClass1.class, "x", "I"). 1085 ireturn(); 1086 } 1087 ); 1088 1089 } 1090 1091 // Test value type array creation and initialization 1092 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD)) 1093 @Test(valid = ValueTypeArrayFlattenOn) 1094 public MyValue1[] test41(int len) { 1095 MyValue1[] va = new MyValue1[len]; 1096 for (int i = 0; i < len; ++i) { 1097 va[i] = MyValue1.createDontInline(rI, rL); 1098 } 1099 return va; 1100 } 1101 1102 @DontCompile 1103 public void test41_verifier(boolean warmup) { 1104 int len = Math.abs(rI % 10); 1105 MyValue1[] va = test41(len); 1106 for (int i = 0; i < len; ++i) { 1107 Asserts.assertEQ(va[i].hash(), hash()); 1108 } 1109 } 1110 1111 // Test creation of a value type array and element access 1112 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOOP + LOAD + TRAP)) 1113 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOC + ALLOCA + LOOP + LOAD + LOADP + STORE + TRAP)) 1114 public long test42() { 1115 MyValue1[] va = new MyValue1[1]; 1116 va[0] = MyValue1.createInline(rI, rL); 1117 return va[0].hash(); 1118 } 1119 1120 @DontCompile 1121 public void test42_verifier(boolean warmup) { 1122 long result = test42(); 1123 Asserts.assertEQ(result, hash()); 1124 } 1125 1126 // Test receiving a value type array from the interpreter, 1127 // updating its elements in a loop and computing a hash. 1128 @Test(failOn = (ALLOCA)) 1129 public long test43(MyValue1[] va) { 1130 long result = 0; 1131 for (int i = 0; i < 10; ++i) { 1132 result += va[i].hash(); 1133 va[i] = MyValue1.createInline(rI + 1, rL + 1); 1134 } 1135 return result; 1136 } 1137 1138 @DontCompile 1139 public void test43_verifier(boolean warmup) { 1140 MyValue1[] va = new MyValue1[10]; 1141 long expected = 0; 1142 for (int i = 0; i < 10; ++i) { 1143 va[i] = MyValue1.createDontInline(rI + i, rL + i); 1144 expected += va[i].hash(); 1145 } 1146 long result = test43(va); 1147 Asserts.assertEQ(expected, result); 1148 for (int i = 0; i < 10; ++i) { 1149 if (va[i].hash() != hash(rI + 1, rL + 1)) { 1150 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1)); 1151 } 1152 } 1153 } 1154 1155 // Test returning a value type array received from the interpreter 1156 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP) 1157 public MyValue1[] test44(MyValue1[] va) { 1158 return va; 1159 } 1160 1161 @DontCompile 1162 public void test44_verifier(boolean warmup) { 1163 MyValue1[] va = new MyValue1[10]; 1164 for (int i = 0; i < 10; ++i) { 1165 va[i] = MyValue1.createDontInline(rI + i, rL + i); 1166 } 1167 va = test44(va); 1168 for (int i = 0; i < 10; ++i) { 1169 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1170 } 1171 } 1172 1173 @Test(failOn = (TRAP)) 1174 public MyValue1[] test45(boolean b) { 1175 MyValue1[] va; 1176 if (b) { 1177 va = new MyValue1[5]; 1178 for (int i = 0; i < 5; ++i) { 1179 va[i] = MyValue1.createInline(rI, rL); 1180 } 1181 } else { 1182 va = new MyValue1[10]; 1183 for (int i = 0; i < 10; ++i) { 1184 va[i] = MyValue1.createInline(rI + i, rL + i); 1185 } 1186 } 1187 long sum = va[0].hashInterpreted(); 1188 if (b) { 1189 va[0] = MyValue1.createDontInline(rI, sum); 1190 } else { 1191 va[0] = MyValue1.createDontInline(rI + 1, sum + 1); 1192 } 1193 return va; 1194 } 1195 1196 @DontCompile 1197 public void test45_verifier(boolean warmup) { 1198 MyValue1[] va = test45(true); 1199 Asserts.assertEQ(va.length, 5); 1200 Asserts.assertEQ(va[0].hash(), hash(rI, hash())); 1201 for (int i = 1; i < 5; ++i) { 1202 Asserts.assertEQ(va[i].hash(), hash()); 1203 } 1204 va = test45(false); 1205 Asserts.assertEQ(va.length, 10); 1206 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1)); 1207 for (int i = 1; i < 10; ++i) { 1208 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1209 } 1210 } 1211 1212 // Test creation of value type array with single element 1213 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP)) 1214 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP)) 1215 public MyValue1 test46() { 1216 MyValue1[] va = new MyValue1[1]; 1217 return va[0]; 1218 } 1219 1220 @DontCompile 1221 public void test46_verifier(boolean warmup) { 1222 MyValue1[] va = new MyValue1[1]; 1223 MyValue1 v = test46(); 1224 Asserts.assertEQ(v.hash(), va[0].hash()); 1225 } 1226 1227 // Test default initialization of value type arrays 1228 @Test(failOn = LOAD) 1229 public MyValue1[] test47(int len) { 1230 return new MyValue1[len]; 1231 } 1232 1233 @DontCompile 1234 public void test47_verifier(boolean warmup) { 1235 int len = Math.abs(rI % 10); 1236 MyValue1[] va = new MyValue1[len]; 1237 MyValue1[] var = test47(len); 1238 for (int i = 0; i < len; ++i) { 1239 Asserts.assertEQ(va[i].hash(), var[i].hash()); 1240 } 1241 } 1242 1243 // Test creation of value type array with zero length 1244 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 1245 public MyValue1[] test48() { 1246 return new MyValue1[0]; 1247 } 1248 1249 @DontCompile 1250 public void test48_verifier(boolean warmup) { 1251 MyValue1[] va = test48(); 1252 Asserts.assertEQ(va.length, 0); 1253 } 1254 1255 static MyValue1[] test49_va; 1256 1257 // Test that value type array loaded from field has correct type 1258 @Test(failOn = (LOOP)) 1259 public long test49() { 1260 return test49_va[0].hash(); 1261 } 1262 1263 @DontCompile 1264 public void test49_verifier(boolean warmup) { 1265 test49_va = new MyValue1[1]; 1266 test49_va[0] = MyValue1.createInline(rI, rL); 1267 long result = test49(); 1268 Asserts.assertEQ(result, hash()); 1269 } 1270 1271 // test vdefault 1272 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1273 public long test50() { 1274 MyValue2 v = MyValue2.createDefaultInline(); 1275 return v.hash(); 1276 } 1277 1278 @DontCompile 1279 public void test50_verifier(boolean warmup) { 1280 long result = test50(); 1281 Asserts.assertEQ(result, MyValue2.createDefaultInline().hash()); 1282 } 1283 1284 // test vdefault 1285 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1286 public long test51() { 1287 MyValue1 v1 = MyValue1.createDefaultInline(); 1288 MyValue1 v2 = MyValue1.createDefaultDontInline(); 1289 return v1.hash() + v2.hash(); 1290 } 1291 1292 @DontCompile 1293 public void test51_verifier(boolean warmup) { 1294 long result = test51(); 1295 Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hash()); 1296 } 1297 1298 // test vwithfield 1299 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1300 public long test52() { 1301 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1302 return v.hash(); 1303 } 1304 1305 @DontCompile 1306 public void test52_verifier(boolean warmup) { 1307 long result = test52(); 1308 Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash()); 1309 } 1310 1311 // test vwithfield 1312 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1313 public long test53() { 1314 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL); 1315 MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL); 1316 return v1.hash() + v2.hash(); 1317 } 1318 1319 @DontCompile 1320 public void test53_verifier(boolean warmup) { 1321 long result = test53(); 1322 Asserts.assertEQ(result, 2 * hash()); 1323 } 1324 1325 // multi-dimensional arrays 1326 @Test 1327 public MyValue1[][][] test54(int len1, int len2, int len3) { 1328 MyValue1[][][] arr = new MyValue1[len1][len2][len3]; 1329 for (int i = 0; i < len1; i++) { 1330 for (int j = 0; j < len2; j++) { 1331 for (int k = 0; k < len3; k++) { 1332 arr[i][j][k] = MyValue1.createDontInline(rI + i , rL + j + k); 1333 } 1334 } 1335 } 1336 return arr; 1337 } 1338 1339 @DontCompile 1340 public void test54_verifier(boolean warmup) { 1341 MyValue1[][][] arr = test54(2, 3, 4); 1342 for (int i = 0; i < 2; i++) { 1343 for (int j = 0; j < 3; j++) { 1344 for (int k = 0; k < 4; k++) { 1345 Asserts.assertEQ(arr[i][j][k].hash(), MyValue1.createDontInline(rI + i , rL + j + k).hash()); 1346 } 1347 } 1348 } 1349 } 1350 1351 @Test 1352 public void test55(MyValue1[][][] arr, long[] res) { 1353 int l = 0; 1354 for (int i = 0; i < arr.length; i++) { 1355 for (int j = 0; j < arr[i].length; j++) { 1356 for (int k = 0; k < arr[i][j].length; k++) { 1357 res[l] = arr[i][j][k].hash(); 1358 l++; 1359 } 1360 } 1361 } 1362 } 1363 1364 @DontCompile 1365 public void test55_verifier(boolean warmup) { 1366 MyValue1[][][] arr = new MyValue1[2][3][4]; 1367 long[] res = new long[2*3*4]; 1368 long[] verif = new long[2*3*4]; 1369 int l = 0; 1370 for (int i = 0; i < 2; i++) { 1371 for (int j = 0; j < 3; j++) { 1372 for (int k = 0; k < 4; k++) { 1373 arr[i][j][k] = MyValue1.createDontInline(rI + i, rL + j + k); 1374 verif[l] = arr[i][j][k].hash(); 1375 l++; 1376 } 1377 } 1378 } 1379 test55(arr, res); 1380 for (int i = 0; i < verif.length; i++) { 1381 Asserts.assertEQ(res[i], verif[i]); 1382 } 1383 } 1384 1385 class TestClass56 { 1386 public MyValue1 v; 1387 } 1388 1389 // Test allocation elimination of unused object with initialized value type field 1390 @Test(failOn = ALLOC + LOAD + STORE + LOOP) 1391 public void test56(boolean deopt) { 1392 TestClass56 unused = new TestClass56(); 1393 MyValue1 v = MyValue1.createInline(rI, rL); 1394 unused.v = v; 1395 if (deopt) { 1396 // uncommon trap 1397 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test56")); 1398 } 1399 } 1400 1401 @DontCompile 1402 public void test56_verifier(boolean warmup) { 1403 test56(!warmup); 1404 } 1405 1406 // Test loop peeling 1407 @Test(failOn = ALLOC + LOAD + STORE) 1408 public void test57() { 1409 MyValue1 v = MyValue1.createInline(0, 1); 1410 // Trigger OSR compilation and loop peeling 1411 for (int i = 0; i < 100_000; ++i) { 1412 if (v.x != i || v.y != i + 1) { 1413 // Uncommon trap 1414 throw new RuntimeException("test57 failed"); 1415 } 1416 v = MyValue1.createInline(i + 1, i + 2); 1417 } 1418 } 1419 1420 @DontCompile 1421 public void test57_verifier(boolean warmup) { 1422 test57(); 1423 } 1424 1425 // Test loop peeling and unrolling 1426 @Test() 1427 public void test58() { 1428 MyValue1 v1 = MyValue1.createInline(0, 0); 1429 MyValue1 v2 = MyValue1.createInline(1, 1); 1430 // Trigger OSR compilation and loop peeling 1431 for (int i = 0; i < 100_000; ++i) { 1432 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) { 1433 // Uncommon trap 1434 throw new RuntimeException("test58 failed"); 1435 } 1436 v1 = MyValue1.createInline(2*(i+1), 0); 1437 v2 = MyValue1.createInline(i+2, i+2); 1438 } 1439 } 1440 1441 @DontCompile 1442 public void test58_verifier(boolean warmup) { 1443 test58(); 1444 } 1445 1446 // When calling a method on __Value, passing fields as arguments is impossible 1447 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount={1, 0}) 1448 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = STORE + LOAD) 1449 public String test59(MyValue1 v) { 1450 return v.toString(); 1451 } 1452 1453 @DontCompile 1454 public void test59_verifier(boolean warmup) { 1455 boolean failed = false; 1456 try { 1457 test59(val1); 1458 failed = true; 1459 } catch (UnsupportedOperationException uoe) { 1460 } 1461 Asserts.assertFalse(failed); 1462 } 1463 1464 // Same as above, but the method on __Value is inlined 1465 // hashCode allocates an exception so can't really check the graph shape 1466 @Test() 1467 public int test60(MyValue1 v) { 1468 return v.hashCode(); 1469 } 1470 1471 @DontCompile 1472 public void test60_verifier(boolean warmup) { 1473 boolean failed = false; 1474 try { 1475 test60(val1); 1476 failed = true; 1477 } catch (UnsupportedOperationException uoe) { 1478 } 1479 Asserts.assertFalse(failed); 1480 } 1481 1482 /* The compiler is supposed to determine that the value to be 1483 * unboxed in nullcvvUnboxLoadLong is always null. Therefore, the 1484 * compiler generates only the path leading to the corresponding 1485 * uncommon trap. */ 1486 @Test(valid = AlwaysIncrementalInlineOff, failOn = RETURN) 1487 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1488 public long test61() throws Throwable { 1489 return (long)nullvccUnboxLoadLongMH.invokeExact(); 1490 } 1491 1492 @DontCompile 1493 public void test61_verifier(boolean warmup) throws Throwable { 1494 try { 1495 long result = test61(); 1496 throw new RuntimeException("Test failed because no exception was thrown"); 1497 } catch (NullPointerException e) { 1498 } 1499 } 1500 1501 public static MethodHandle generateNullVCCUnboxLoadLongMH() { 1502 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1503 "nullvccUnboxLoadLong", 1504 MethodType.methodType(long.class), 1505 CODE -> { 1506 CODE. 1507 aconst_null(). 1508 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1509 getfield(ValueCapableClass1.class, "t", "J"). 1510 lreturn(); 1511 } 1512 ); 1513 } 1514 1515 /* The compiler is supposed to determine that the allocated 1516 * ValueCapableClass1 instance is never null (and therefore not 1517 * generate a null check). Also, the source and target type match 1518 * (known at compile time), so no type check is needed either.*/ 1519 @Test(valid = AlwaysIncrementalInlineOff, failOn = NPE) 1520 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1521 public long test62() throws Throwable { 1522 return (long)checkedvccUnboxLoadLongMH.invokeExact(); 1523 } 1524 1525 @DontCompile 1526 public void test62_verifier(boolean warmup) throws Throwable { 1527 long result = test62(); 1528 Asserts.assertEQ(result, 17L); 1529 } 1530 1531 public static MethodHandle generateCheckedVCCUnboxLoadLongMH() { 1532 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1533 "checkedVCCUnboxLoadLongMH", 1534 MethodType.methodType(long.class), 1535 CODE -> { 1536 CODE. 1537 invokestatic(ValueCapableClass1.class, "createInline", "()Lcompiler/valhalla/valuetypes/ValueCapableClass1;", false). 1538 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1539 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1540 lreturn(); 1541 } 1542 ); 1543 } 1544 1545 /* The compiler is supposed to emit a runtime null check because 1546 * it does not have enough information to determine that the value 1547 * to be unboxed is not null (and either that it is null). The 1548 * declared type of the */ 1549 @Test(valid = AlwaysIncrementalInlineOff, match = {NPE}, matchCount = {1}) 1550 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1551 public long test63(ValueCapableClass1 vcc) throws Throwable { 1552 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 1553 } 1554 1555 @DontCompile 1556 public void test63_verifier(boolean warmup) throws Throwable { 1557 try { 1558 long result = test63(null); 1559 throw new RuntimeException("Test failed because no exception was thrown"); 1560 } catch (NullPointerException e) { 1561 } 1562 } 1563 1564 /* Attempt to unbox an object that is not a subclass of the 1565 * value-capable class derived from the value type specified in 1566 * the vunbox bytecode. */ 1567 @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {1,1}) 1568 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1569 public long test64(Object vcc) throws Throwable { 1570 return (long)objectUnboxLoadLongMH.invokeExact(vcc); 1571 } 1572 1573 @DontCompile 1574 public void test64_verifier(boolean warmup) throws Throwable { 1575 try { 1576 long result = test64(new Object()); 1577 throw new RuntimeException("Test failed because no exception was thrown"); 1578 } catch (ClassCastException e) { 1579 } 1580 1581 try { 1582 long result = test64(vcc2); 1583 throw new RuntimeException("Test failed because no exception was thrown"); 1584 } catch (ClassCastException e) { 1585 } 1586 1587 Asserts.assertEQ(test64(vcc), rL); 1588 } 1589 1590 private static MethodHandle generateObjectUnboxLoadLongMH() { 1591 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1592 "ObjectUnboxLoadLong", 1593 MethodType.methodType(long.class, Object.class), 1594 CODE -> { 1595 CODE. 1596 aload_0(). 1597 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1598 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1599 lreturn(); 1600 } 1601 ); 1602 } 1603 1604 /* Generate an if-then-else construct with one path that contains 1605 * an invalid boxing operation (boxing of a value-type to a 1606 * non-matching value-capable class).*/ 1607 @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {2,3}) 1608 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1609 public long test65(Object obj, boolean warmup) throws Throwable { 1610 return (long)objectBoxMH.invokeExact(obj, warmup); 1611 } 1612 1613 @DontCompile 1614 public void test65_verifier(boolean warmup) throws Throwable { 1615 try { 1616 long result = test65(vcc2, true); 1617 throw new RuntimeException("Test failed because no exception was thrown"); 1618 } catch (ClassCastException e) { 1619 } 1620 1621 Asserts.assertEQ(test65(vcc, true), rL); 1622 1623 try { 1624 long result = test65(vcc2, false); 1625 throw new RuntimeException("Test failed because no exception was thrown"); 1626 } catch (ClassCastException e) { 1627 } 1628 1629 try { 1630 long result = test65(vcc, false); 1631 throw new RuntimeException("Test failed because no exception was thrown"); 1632 } catch (ClassCastException e) { 1633 } 1634 } 1635 1636 private static MethodHandle generateObjectBoxMH() { 1637 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1638 "ObjectBox", 1639 MethodType.methodType(long.class, Object.class, boolean.class), 1640 CODE -> { 1641 CODE. 1642 iload_1(). 1643 iconst_1(). 1644 if_icmpne((short)14). 1645 aload_0(). 1646 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1647 vbox(ValueCapableClass1.class). 1648 getfield(ValueCapableClass1.class, "t", "J"). 1649 lreturn(). 1650 aload_0(). 1651 vunbox(ValueType.forClass(ValueCapableClass2.class).valueClass()). 1652 vbox(ValueCapableClass1.class). 1653 getfield(ValueCapableClass1.class, "t", "J"). 1654 lreturn(); 1655 } 1656 ); 1657 } 1658 1659 // ========== Test infrastructure ========== 1660 1661 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 1662 private static final int ValueTypePassFieldsAsArgsOn = 0x1; 1663 private static final int ValueTypePassFieldsAsArgsOff = 0x2; 1664 private static final int ValueTypeArrayFlattenOn = 0x4; 1665 private static final int ValueTypeArrayFlattenOff = 0x8; 1666 private static final int AlwaysIncrementalInlineOff = 0x10; 1667 private static final int AlwaysIncrementalInlineOn = 0x20; 1668 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | AlwaysIncrementalInlineOff | AlwaysIncrementalInlineOn; 1669 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 1670 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten"); 1671 private static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline"); 1672 private static final int COMP_LEVEL_ANY = -1; 1673 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 1674 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 1675 private static final int WARMUP = 251; 1676 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 1677 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 1678 // TODO use Platform.isComp() after merge with JDK 9 1679 private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled "); 1680 1681 // Regular expressions used to match nodes in the PrintIdeal output 1682 private static final String START = "(\\d+\\t(.*"; 1683 private static final String MID = ".*)+\\t===.*"; 1684 private static final String END = ")|"; 1685 private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END; 1686 private static final String ALLOCA = START + "CallStaticJava" + MID + "_new_array_Java" + END; 1687 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1688 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END; 1689 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1690 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END; 1691 private static final String LOOP = START + "Loop" + MID + "" + END; 1692 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap" + END; 1693 private static final String RETURN = START + "Return" + MID + "returns" + END; 1694 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END; 1695 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END; 1696 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END; 1697 // TODO: match field values of scalar replaced object 1698 private static final String SCOBJ = "(.*# ScObj.*" + END; 1699 1700 static { 1701 // Gather all test methods and put them in Hashtable 1702 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) { 1703 Test[] annos = m.getAnnotationsByType(Test.class); 1704 if (annos.length != 0) { 1705 tests.put("ValueTypeTestBench::" + m.getName(), m); 1706 } 1707 } 1708 } 1709 1710 private static void execute_vm(String... args) throws Throwable { 1711 Asserts.assertFalse(tests.isEmpty(), "no tests to execute"); 1712 ArrayList<String> all_args = new ArrayList(List.of(args)); 1713 // Run tests in own process and verify output 1714 all_args.add(ValueTypeTestBench.class.getName()); 1715 all_args.add("run"); 1716 // Spawn process with default JVM options from the test's run command 1717 OutputAnalyzer oa = ProcessTools.executeTestJvmAllArgs(all_args.toArray(new String[all_args.size()])); 1718 // If ideal graph printing is enabled/supported, verify output 1719 String output = oa.getOutput(); 1720 oa.shouldHaveExitValue(0); 1721 boolean verifyIR = output.contains("PrintIdeal enabled") && 1722 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform"); 1723 if (verifyIR) { 1724 parseOutput(output); 1725 } else { 1726 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); 1727 } 1728 } 1729 1730 public static void main(String[] args) throws Throwable { 1731 //tests.values().removeIf(p -> !p.getName().equals("test64")); // Run single test 1732 if (args.length == 0) { 1733 execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation", 1734 "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly", 1735 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*", 1736 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", 1737 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*", 1738 "-XX:CompileCommand=compileonly,java.lang.Object::<init>", 1739 "-XX:CompileCommand=inline,java.lang.__Value::hashCode"); 1740 } else { 1741 // Execute tests 1742 ValueTypeTestBench bench = new ValueTypeTestBench(); 1743 bench.run(); 1744 } 1745 } 1746 1747 public static void parseOutput(String output) throws Exception { 1748 String split = "b compiler.valhalla.valuetypes."; 1749 String[] compilations = output.split(split); 1750 // Print header 1751 System.out.println(compilations[0]); 1752 // Iterate over compilation output 1753 for (String graph : compilations) { 1754 String[] lines = graph.split("\\n"); 1755 if (lines[0].contains("@")) { 1756 continue; // Ignore OSR compilations 1757 } 1758 String testName = lines[0].split(" ")[0]; 1759 Method test = tests.get(testName); 1760 if (test == null) { 1761 // Skip helper methods 1762 continue; 1763 } 1764 if (PRINT_GRAPH) { 1765 System.out.println("\nGraph for " + graph); 1766 } 1767 // Parse graph using regular expressions to determine if it contains forbidden nodes 1768 Test[] annos = test.getAnnotationsByType(Test.class); 1769 Test anno = null; 1770 for (Test a : annos) { 1771 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 1772 assert anno == null; 1773 anno = a; 1774 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 1775 assert anno == null; 1776 anno = a; 1777 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 1778 assert anno == null; 1779 anno = a; 1780 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 1781 assert anno == null; 1782 anno = a; 1783 } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) { 1784 assert anno == null; 1785 anno = a; 1786 } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) { 1787 assert anno == null; 1788 anno = a; 1789 } 1790 } 1791 assert anno != null; 1792 String regexFail = anno.failOn(); 1793 if (!regexFail.isEmpty()) { 1794 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 1795 Matcher matcher = pattern.matcher(graph); 1796 boolean found = matcher.find(); 1797 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 1798 } 1799 String[] regexMatch = anno.match(); 1800 int[] matchCount = anno.matchCount(); 1801 for (int i = 0; i < regexMatch.length; ++i) { 1802 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 1803 Matcher matcher = pattern.matcher(graph); 1804 int count = 0; 1805 String nodes = ""; 1806 while (matcher.find()) { 1807 count++; 1808 nodes += matcher.group() + "\n"; 1809 } 1810 if (matchCount[i] < 0) { 1811 Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 1812 } else { 1813 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 1814 } 1815 } 1816 tests.remove(testName); 1817 System.out.println(testName + " passed"); 1818 } 1819 // Check if all tests were compiled 1820 if (tests.size() != 0) { 1821 for (String name : tests.keySet()) { 1822 System.out.println("Test '" + name + "' not compiled!"); 1823 } 1824 throw new RuntimeException("Not all tests were compiled"); 1825 } 1826 } 1827 1828 public void setup(Method[] methods) { 1829 for (Method m : methods) { 1830 if (m.isAnnotationPresent(Test.class)) { 1831 // Don't inline tests 1832 WHITE_BOX.testSetDontInlineMethod(m, true); 1833 } 1834 if (m.isAnnotationPresent(DontCompile.class)) { 1835 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 1836 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 1837 } 1838 if (m.isAnnotationPresent(ForceInline.class)) { 1839 WHITE_BOX.testSetForceInlineMethod(m, true); 1840 } else if (m.isAnnotationPresent(DontInline.class)) { 1841 WHITE_BOX.testSetDontInlineMethod(m, true); 1842 } 1843 } 1844 } 1845 1846 public void run() throws Exception { 1847 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 1848 System.out.println("PrintIdeal enabled"); 1849 } 1850 System.out.format("rI = %d, rL = %d\n", rI, rL); 1851 setup(this.getClass().getDeclaredMethods()); 1852 setup(MyValue1.class.getDeclaredMethods()); 1853 setup(MyValue2.class.getDeclaredMethods()); 1854 1855 // TODO enable this after JDK 9 merge and verify that it's compiled 1856 //WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION); 1857 1858 // Execute tests 1859 for (Method test : tests.values()) { 1860 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class); 1861 // Warmup using verifier method 1862 for (int i = 0; i < WARMUP; ++i) { 1863 verifier.invoke(this, true); 1864 } 1865 // Trigger compilation 1866 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION); 1867 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 1868 // Check result 1869 verifier.invoke(this, false); 1870 } 1871 } 1872 } 1873 1874 // Mark method as test 1875 @Retention(RetentionPolicy.RUNTIME) 1876 @Repeatable(Tests.class) 1877 @interface Test { 1878 // Regular expression used to match forbidden IR nodes 1879 // in the C2 IR emitted for this test. 1880 String failOn() default ""; 1881 // Regular expressions used to match and count IR nodes. 1882 String[] match() default { }; 1883 int[] matchCount() default { }; 1884 int valid() default ValueTypeTestBench.AllFlags; 1885 } 1886 1887 @Retention(RetentionPolicy.RUNTIME) 1888 @interface Tests { 1889 Test[] value(); 1890 } 1891 1892 // Force method inlining during compilation 1893 @Retention(RetentionPolicy.RUNTIME) 1894 @interface ForceInline { } 1895 1896 // Prevent method inlining during compilation 1897 @Retention(RetentionPolicy.RUNTIME) 1898 @interface DontInline { } 1899 1900 // Prevent method compilation 1901 @Retention(RetentionPolicy.RUNTIME) 1902 @interface DontCompile { }