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