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 300 private static final ValueCapableClass1 vcc = ValueCapableClass1.create(rL, rI, (short)rI, (short)rI); 301 302 // ========== Helper methods ========== 303 304 public long hash() { 305 return hash(rI, rL); 306 } 307 308 public long hash(int x, long y) { 309 return MyValue1.createInline(x, y).hash(); 310 } 311 312 // ========== Test definitions ========== 313 314 // Receive value type through call to interpreter 315 @Test(failOn = ALLOC + STORE + TRAP) 316 public long test1() { 317 MyValue1 v = MyValue1.createDontInline(rI, rL); 318 return v.hash(); 319 } 320 321 @DontCompile 322 public void test1_verifier(boolean warmup) { 323 long result = test1(); 324 Asserts.assertEQ(result, hash()); 325 } 326 327 // Receive value type from interpreter via parameter 328 @Test(failOn = ALLOC + STORE + TRAP) 329 public long test2(MyValue1 v) { 330 return v.hash(); 331 } 332 333 @DontCompile 334 public void test2_verifier(boolean warmup) { 335 MyValue1 v = MyValue1.createDontInline(rI, rL); 336 long result = test2(v); 337 Asserts.assertEQ(result, hash()); 338 } 339 340 // Return incoming value type without accessing fields 341 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 11}, failOn = LOAD + TRAP) 342 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP) 343 public MyValue1 test3(MyValue1 v) { 344 return v; 345 } 346 347 @DontCompile 348 public void test3_verifier(boolean warmup) { 349 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 350 MyValue1 v2 = test3(v1); 351 Asserts.assertEQ(v1.x, v2.x); 352 Asserts.assertEQ(v1.y, v2.y); 353 } 354 355 // Create a value type in compiled code and only use fields. 356 // Allocation should go away because value type does not escape. 357 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 358 public long test4() { 359 MyValue1 v = MyValue1.createInline(rI, rL); 360 return v.hash(); 361 } 362 363 @DontCompile 364 public void test4_verifier(boolean warmup) { 365 long result = test4(); 366 Asserts.assertEQ(result, hash()); 367 } 368 369 // Create a value type in compiled code and pass it to 370 // an inlined compiled method via a call. 371 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 372 public long test5() { 373 MyValue1 v = MyValue1.createInline(rI, rL); 374 return test5Inline(v); 375 } 376 377 @ForceInline 378 public long test5Inline(MyValue1 v) { 379 return v.hash(); 380 } 381 382 @DontCompile 383 public void test5_verifier(boolean warmup) { 384 long result = test5(); 385 Asserts.assertEQ(result, hash()); 386 } 387 388 // Create a value type in compiled code and pass it to 389 // the interpreter via a call. 390 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC) 391 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 392 public long test6() { 393 MyValue1 v = MyValue1.createInline(rI, rL); 394 // Pass to interpreter 395 return v.hashInterpreted(); 396 } 397 398 @DontCompile 399 public void test6_verifier(boolean warmup) { 400 long result = test6(); 401 Asserts.assertEQ(result, hash()); 402 } 403 404 // Create a value type in compiled code and pass it to 405 // the interpreter by returning. 406 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 407 public MyValue1 test7(int x, long y) { 408 return MyValue1.createInline(x, y); 409 } 410 411 @DontCompile 412 public void test7_verifier(boolean warmup) { 413 MyValue1 v = test7(rI, rL); 414 Asserts.assertEQ(v.hash(), hash()); 415 } 416 417 // Merge value types created from two branches 418 @Test(failOn = ALLOC + STORE + TRAP) 419 public long test8(boolean b) { 420 MyValue1 v; 421 if (b) { 422 v = MyValue1.createInline(rI, rL); 423 } else { 424 v = MyValue1.createDontInline(rI + 1, rL + 1); 425 } 426 return v.hash(); 427 } 428 429 @DontCompile 430 public void test8_verifier(boolean warmup) { 431 Asserts.assertEQ(test8(true), hash()); 432 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1)); 433 } 434 435 // Merge value types created from two branches 436 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {10}, failOn = TRAP + ALLOC + STORE) 437 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP) 438 public MyValue1 test9(boolean b) { 439 MyValue1 v; 440 if (b) { 441 // Value type is not allocated 442 v = MyValue1.createInline(rI, rL); 443 } else { 444 // Value type is allocated by the callee 445 v = MyValue1.createDontInline(rI + 1, rL + 1); 446 } 447 // Need to allocate value type if 'b' is true 448 long sum = v.hashInterpreted(); 449 if (b) { 450 v = MyValue1.createDontInline(rI, sum); 451 } else { 452 v = MyValue1.createDontInline(rI, sum + 1); 453 } 454 // Don't need to allocate value type because both branches allocate 455 return v; 456 } 457 458 @DontCompile 459 public void test9_verifier(boolean warmup) { 460 MyValue1 v = test9(true); 461 Asserts.assertEQ(v.x, rI); 462 Asserts.assertEQ(v.y, hash()); 463 v = test9(false); 464 Asserts.assertEQ(v.x, rI); 465 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1); 466 } 467 468 // Merge value types created in a loop (not inlined) 469 @Test(failOn = ALLOC + STORE + TRAP) 470 public long test10(int x, long y) { 471 MyValue1 v = MyValue1.createDontInline(x, y); 472 for (int i = 0; i < 10; ++i) { 473 v = MyValue1.createDontInline(v.x + 1, v.y + 1); 474 } 475 return v.hash(); 476 } 477 478 @DontCompile 479 public void test10_verifier(boolean warmup) { 480 long result = test10(rI, rL); 481 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 482 } 483 484 // Merge value types created in a loop (inlined) 485 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 486 public long test11(int x, long y) { 487 MyValue1 v = MyValue1.createInline(x, y); 488 for (int i = 0; i < 10; ++i) { 489 v = MyValue1.createInline(v.x + 1, v.y + 1); 490 } 491 return v.hash(); 492 } 493 494 @DontCompile 495 public void test11_verifier(boolean warmup) { 496 long result = test11(rI, rL); 497 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 498 } 499 500 // Test loop with uncommon trap referencing a value type 501 @Test(match = {TRAP, SCOBJ}, matchCount = {1, -1 /* at least 1 */}, failOn = LOAD) 502 public long test12(boolean b) { 503 MyValue1 v = MyValue1.createInline(rI, rL); 504 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 505 for (int i = 0; i < va.length; ++i) { 506 va[i] = MyValue1.createInline(rI, rL); 507 } 508 long result = rL; 509 for (int i = 0; i < 1000; ++i) { 510 if (b) { 511 result += v.x; 512 } else { 513 // Uncommon trap referencing v. We delegate allocation to the 514 // interpreter by adding a SafePointScalarObjectNode. 515 result = v.hashInterpreted(); 516 for (int j = 0; j < va.length; ++j) { 517 result += va[j].hash(); 518 } 519 } 520 } 521 return result; 522 } 523 524 @DontCompile 525 public void test12_verifier(boolean warmup) { 526 long result = test12(warmup); 527 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 528 } 529 530 // Test loop with uncommon trap referencing a value type 531 @Test(match = {TRAP}, matchCount = {1}) 532 public long test13(boolean b) { 533 MyValue1 v = MyValue1.createDontInline(rI, rL); 534 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 535 for (int i = 0; i < va.length; ++i) { 536 va[i] = MyValue1.createDontInline(rI, rL); 537 } 538 long result = rL; 539 for (int i = 0; i < 1000; ++i) { 540 if (b) { 541 result += v.x; 542 } else { 543 // Uncommon trap referencing v. Should not allocate 544 // but just pass the existing oop to the uncommon trap. 545 result = v.hashInterpreted(); 546 for (int j = 0; j < va.length; ++j) { 547 result += va[j].hashInterpreted(); 548 } 549 } 550 } 551 return result; 552 } 553 554 @DontCompile 555 public void test13_verifier(boolean warmup) { 556 long result = test13(warmup); 557 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 558 } 559 560 // Create a value type in a non-inlined method and then call a 561 // non-inlined method on that value type. 562 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {10}) 563 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP)) 564 public long test14() { 565 MyValue1 v = MyValue1.createDontInline(rI, rL); 566 return v.hashInterpreted(); 567 } 568 569 @DontCompile 570 public void test14_verifier(boolean b) { 571 long result = test14(); 572 Asserts.assertEQ(result, hash()); 573 } 574 575 // Create a value type in an inlined method and then call a 576 // non-inlined method on that value type. 577 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC)) 578 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1}) 579 public long test15() { 580 MyValue1 v = MyValue1.createInline(rI, rL); 581 return v.hashInterpreted(); 582 } 583 584 @DontCompile 585 public void test15_verifier(boolean b) { 586 long result = test15(); 587 Asserts.assertEQ(result, hash()); 588 } 589 590 // Create a value type in a non-inlined method and then call an 591 // inlined method on that value type. 592 @Test(failOn = (ALLOC + STORE + TRAP)) 593 public long test16() { 594 MyValue1 v = MyValue1.createDontInline(rI, rL); 595 return v.hash(); 596 } 597 598 @DontCompile 599 public void test16_verifier(boolean b) { 600 long result = test16(); 601 Asserts.assertEQ(result, hash()); 602 } 603 604 // Create a value type in an inlined method and then call an 605 // inlined method on that value type. 606 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 607 public long test17() { 608 MyValue1 v = MyValue1.createInline(rI, rL); 609 return v.hash(); 610 } 611 612 @DontCompile 613 public void test17_verifier(boolean b) { 614 long result = test17(); 615 Asserts.assertEQ(result, hash()); 616 } 617 618 // Create a value type in compiled code and pass it to the 619 // interpreter via a call. The value is live at the first call so 620 // debug info should include a reference to all its fields. 621 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 622 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 623 public long test18() { 624 MyValue1 v = MyValue1.createInline(rI, rL); 625 v.hashInterpreted(); 626 return v.hashInterpreted(); 627 } 628 629 @DontCompile 630 public void test18_verifier(boolean warmup) { 631 long result = test18(); 632 Asserts.assertEQ(result, hash()); 633 } 634 635 // Create a value type in compiled code and pass it to the 636 // interpreter via a call. The value type is passed twice but 637 // should only be allocated once. 638 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 639 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 640 public long test19() { 641 MyValue1 v = MyValue1.createInline(rI, rL); 642 return sumValue(v, v); 643 } 644 645 @DontCompile 646 public long sumValue(MyValue1 v, MyValue1 dummy) { 647 return v.hash(); 648 } 649 650 @DontCompile 651 public void test19_verifier(boolean warmup) { 652 long result = test19(); 653 Asserts.assertEQ(result, hash()); 654 } 655 656 // Create a value type (array) in compiled code and pass it to the 657 // interpreter via a call. The value type is live at the uncommon 658 // trap: verify that deoptimization causes the value type to be 659 // correctly allocated. 660 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE) 661 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {2}, failOn = LOAD) 662 public long test20(boolean deopt) { 663 MyValue1 v = MyValue1.createInline(rI, rL); 664 MyValue1[] va = new MyValue1[3]; 665 if (deopt) { 666 // uncommon trap 667 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20")); 668 } 669 return v.hashInterpreted() + va[0].hashInterpreted() + 670 va[1].hashInterpreted() + va[2].hashInterpreted(); 671 } 672 673 @DontCompile 674 public void test20_verifier(boolean warmup) { 675 MyValue1[] va = new MyValue1[42]; 676 long result = test20(!warmup); 677 Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash()); 678 } 679 680 // Value type fields in regular object 681 MyValue1 val1; 682 MyValue2 val2; 683 final MyValue1 val3; 684 static MyValue1 val4; 685 static final MyValue1 val5 = MyValue1.createInline(rI, rL); 686 687 // Test value type fields in objects 688 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP)) 689 public long test21(int x, long y) { 690 // Compute hash of value type fields 691 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 692 // Update fields 693 val1 = MyValue1.createInline(x, y); 694 val2 = MyValue2.createInline(x, true); 695 val4 = MyValue1.createInline(x, y); 696 return result; 697 } 698 699 @DontCompile 700 public void test21_verifier(boolean warmup) { 701 // Check if hash computed by test18 is correct 702 val1 = MyValue1.createInline(rI, rL); 703 val2 = val1.v2; 704 // val3 is initialized in the constructor 705 val4 = val1; 706 // val5 is initialized in the static initializer 707 long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 708 long result = test21(rI + 1, rL + 1); 709 Asserts.assertEQ(result, hash); 710 // Check if value type fields were updated 711 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1)); 712 Asserts.assertEQ(val2.hash(), MyValue2.createInline(rI + 1, true).hash()); 713 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1)); 714 } 715 716 // Test folding of constant value type fields 717 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 718 public long test22() { 719 // This should be constant folded 720 return val5.hash() + val5.v3.hash(); 721 } 722 723 @DontCompile 724 public void test22_verifier(boolean warmup) { 725 long result = test22(); 726 Asserts.assertEQ(result, val5.hash() + val5.v3.hash()); 727 } 728 729 // Test OSR compilation 730 @Test() 731 public long test23() { 732 MyValue1 v = MyValue1.createInline(rI, rL); 733 MyValue1[] va = new MyValue1[Math.abs(rI) % 3]; 734 for (int i = 0; i < va.length; ++i) { 735 va[i] = MyValue1.createInline(rI, rL); 736 } 737 long result = 0; 738 // Long loop to trigger OSR compilation 739 for (int i = 0 ; i < 100_000; ++i) { 740 // Reference local value type in interpreter state 741 result = v.hash(); 742 for (int j = 0; j < va.length; ++j) { 743 result += va[j].hash(); 744 } 745 } 746 return result; 747 } 748 749 @DontCompile 750 public void test23_verifier(boolean warmup) { 751 long result = test23(); 752 Asserts.assertEQ(result, ((Math.abs(rI) % 3) + 1) * hash()); 753 } 754 755 // Test interpreter to compiled code with various signatures 756 @Test(failOn = ALLOC + STORE + TRAP) 757 public long test24(MyValue2 v) { 758 return v.hash(); 759 } 760 761 @DontCompile 762 public void test24_verifier(boolean warmup) { 763 MyValue2 v = MyValue2.createInline(rI, true); 764 long result = test24(v); 765 Asserts.assertEQ(result, v.hashInterpreted()); 766 } 767 768 @Test(failOn = ALLOC + STORE + TRAP) 769 public long test25(int i1, MyValue2 v, int i2) { 770 return v.hash() + i1 - i2; 771 } 772 773 @DontCompile 774 public void test25_verifier(boolean warmup) { 775 MyValue2 v = MyValue2.createInline(rI, true); 776 long result = test25(rI, v, 2*rI); 777 Asserts.assertEQ(result, v.hashInterpreted() - rI); 778 } 779 780 @Test(failOn = ALLOC + STORE + TRAP) 781 public long test26(long l1, MyValue2 v, long l2) { 782 return v.hash() + l1 - l2; 783 } 784 785 @DontCompile 786 public void test26_verifier(boolean warmup) { 787 MyValue2 v = MyValue2.createInline(rI, true); 788 long result = test26(rL, v, 2*rL); 789 Asserts.assertEQ(result, v.hashInterpreted() - rL); 790 } 791 792 @Test(failOn = ALLOC + STORE + TRAP) 793 public long test27(int i, MyValue2 v, long l) { 794 return v.hash() + i + l; 795 } 796 797 @DontCompile 798 public void test27_verifier(boolean warmup) { 799 MyValue2 v = MyValue2.createInline(rI, true); 800 long result = test27(rI, v, rL); 801 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 802 } 803 804 @Test(failOn = ALLOC + STORE + TRAP) 805 public long test28(long l, MyValue2 v, int i) { 806 return v.hash() + i + l; 807 } 808 809 @DontCompile 810 public void test28_verifier(boolean warmup) { 811 MyValue2 v = MyValue2.createInline(rI, true); 812 long result = test28(rL, v, rI); 813 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 814 } 815 816 @Test(failOn = ALLOC + STORE + TRAP) 817 public long test29(long l, MyValue1 v1, int i, MyValue2 v2) { 818 return v1.hash() + i + l + v2.hash(); 819 } 820 821 @DontCompile 822 public void test29_verifier(boolean warmup) { 823 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 824 MyValue2 v2 = MyValue2.createInline(rI, true); 825 long result = test29(rL, v1, rI, v2); 826 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 827 } 828 829 // Test compiled code to interpreter with various signatures 830 @DontCompile 831 public long test30_interp(MyValue2 v) { 832 return v.hash(); 833 } 834 835 @Test(failOn = ALLOC + STORE + TRAP) 836 public long test30(MyValue2 v) { 837 return test30_interp(v); 838 } 839 840 @DontCompile 841 public void test30_verifier(boolean warmup) { 842 MyValue2 v = MyValue2.createInline(rI, true); 843 long result = test30(v); 844 Asserts.assertEQ(result, v.hashInterpreted()); 845 } 846 847 @DontCompile 848 public long test31_interp(int i1, MyValue2 v, int i2) { 849 return v.hash() + i1 - i2; 850 } 851 852 @Test(failOn = ALLOC + STORE + TRAP) 853 public long test31(int i1, MyValue2 v, int i2) { 854 return test31_interp(i1, v, i2); 855 } 856 857 @DontCompile 858 public void test31_verifier(boolean warmup) { 859 MyValue2 v = MyValue2.createInline(rI, true); 860 long result = test31(rI, v, 2*rI); 861 Asserts.assertEQ(result, v.hashInterpreted() - rI); 862 } 863 864 @DontCompile 865 public long test32_interp(long l1, MyValue2 v, long l2) { 866 return v.hash() + l1 - l2; 867 } 868 869 @Test(failOn = ALLOC + STORE + TRAP) 870 public long test32(long l1, MyValue2 v, long l2) { 871 return test32_interp(l1, v, l2); 872 } 873 874 @DontCompile 875 public void test32_verifier(boolean warmup) { 876 MyValue2 v = MyValue2.createInline(rI, true); 877 long result = test32(rL, v, 2*rL); 878 Asserts.assertEQ(result, v.hashInterpreted() - rL); 879 } 880 881 @DontCompile 882 public long test33_interp(int i, MyValue2 v, long l) { 883 return v.hash() + i + l; 884 } 885 886 @Test(failOn = ALLOC + STORE + TRAP) 887 public long test33(int i, MyValue2 v, long l) { 888 return test33_interp(i, v, l); 889 } 890 891 @DontCompile 892 public void test33_verifier(boolean warmup) { 893 MyValue2 v = MyValue2.createInline(rI, true); 894 long result = test33(rI, v, rL); 895 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 896 } 897 898 @DontCompile 899 public long test34_interp(long l, MyValue2 v, int i) { 900 return v.hash() + i + l; 901 } 902 903 @Test(failOn = ALLOC + STORE + TRAP) 904 public long test34(long l, MyValue2 v, int i) { 905 return test34_interp(l, v, i); 906 } 907 908 @DontCompile 909 public void test34_verifier(boolean warmup) { 910 MyValue2 v = MyValue2.createInline(rI, true); 911 long result = test34(rL, v, rI); 912 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 913 } 914 915 @DontCompile 916 public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 917 return v1.hash() + i + l + v2.hash(); 918 } 919 920 @Test(failOn = ALLOC + STORE + TRAP) 921 public long test35(long l, MyValue1 v1, int i, MyValue2 v2) { 922 return test35_interp(l, v1, i, v2); 923 } 924 925 @DontCompile 926 public void test35_verifier(boolean warmup) { 927 MyValue1 v1 = MyValue1.createDontInline(rI, rL); 928 MyValue2 v2 = MyValue2.createInline(rI, true); 929 long result = test35(rL, v1, rI, v2); 930 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 931 } 932 933 // test that debug info at a call is correct 934 @DontCompile 935 public long test36_interp(MyValue2 v, MyValue1[] va, boolean deopt) { 936 if (deopt) { 937 // uncommon trap 938 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36")); 939 } 940 return v.hash() + va[0].hash() + va[1].hash(); 941 } 942 943 @Test(failOn = ALLOC + STORE + TRAP) 944 public long test36(MyValue2 v, MyValue1[] va, boolean flag, long l) { 945 return test36_interp(v, va, flag) + l; 946 } 947 948 @DontCompile 949 public void test36_verifier(boolean warmup) { 950 MyValue2 v = MyValue2.createInline(rI, true); 951 MyValue1[] va = new MyValue1[2]; 952 va[0] = MyValue1.createDontInline(rI, rL); 953 va[1] = MyValue1.createDontInline(rI, rL); 954 long result = test36(v, va, !warmup, rL); 955 Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL); 956 } 957 958 // Test vbox and vunbox 959 @Test 960 public long test37() throws Throwable { 961 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 962 } 963 964 @DontCompile 965 public void test37_verifier(boolean warmup) { 966 try { 967 long result = test37(); 968 Asserts.assertEQ(vcc.t, result, "Field t of input and result must be equal."); 969 } catch (Throwable t) { 970 throw new RuntimeException("test 37 failed", t); 971 } 972 } 973 974 // Generate a MethodHandle that obtains field t of the 975 // derived value type 976 private static MethodHandle generateVCCUnboxLoadLongMH() { 977 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 978 "vccUnboxLoadLong", 979 MethodType.methodType(long.class, ValueCapableClass1.class), 980 CODE -> { 981 CODE. 982 aload_0(). 983 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 984 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 985 lreturn(); 986 } 987 ); 988 } 989 990 @Test 991 public int test38() throws Throwable { 992 return (int)vccUnboxLoadIntMH.invokeExact(vcc); 993 } 994 995 @DontCompile 996 public void test38_verifier(boolean warmup) { 997 try { 998 int result = test38(); 999 Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal."); 1000 } catch (Throwable t) { 1001 throw new RuntimeException("test 38 failed", t); 1002 } 1003 } 1004 1005 // Generate a MethodHandle that obtains field x of the 1006 // derived value type 1007 private static MethodHandle generateVCCUnboxLoadIntMH() { 1008 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1009 "vccUnboxLoadInt", 1010 MethodType.methodType(int.class, ValueCapableClass1.class), 1011 CODE -> { 1012 CODE. 1013 aload_0(). 1014 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1015 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "x", "I"). 1016 ireturn(); 1017 } 1018 ); 1019 } 1020 1021 @Test 1022 public ValueCapableClass1 test39() throws Throwable { 1023 return (ValueCapableClass1)vccUnboxBoxMH.invokeExact(vcc); 1024 } 1025 1026 @DontCompile 1027 public void test39_verifier(boolean warmup) { 1028 try { 1029 ValueCapableClass1 result = test39(); 1030 Asserts.assertEQ(vcc.value(), result.value(), "Value of VCC and returned VCC must be equal"); 1031 } catch (Throwable t) { 1032 throw new RuntimeException("test 39 failed", t); 1033 } 1034 } 1035 1036 // Generate a MethodHandle that takes a value-capable class, 1037 // unboxes it, then boxes it again and returns it. 1038 private static MethodHandle generateVCCUnboxBoxMH() { 1039 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1040 "vccUnboxBox", 1041 MethodType.methodType(ValueCapableClass1.class, ValueCapableClass1.class), 1042 CODE -> { 1043 CODE. 1044 aload_0(). 1045 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1046 vbox(ValueCapableClass1.class). 1047 areturn(); 1048 } 1049 ); 1050 } 1051 1052 @Test 1053 public int test40() throws Throwable { 1054 return (int)vccUnboxBoxLoadIntMH.invokeExact(vcc); 1055 } 1056 1057 @DontCompile 1058 public void test40_verifier(boolean warmup) { 1059 try { 1060 int result = test40(); 1061 Asserts.assertEQ(vcc.x, result, "Field x of VCC and result must be equal"); 1062 } catch (Throwable t) { 1063 throw new RuntimeException("Test failed in the interpeter", t); 1064 } 1065 } 1066 1067 // Generate a MethodHandle that takes a value-capable class, 1068 // unboxes it, boxes it, reads a field from it, and returns the 1069 // field. 1070 private static MethodHandle generateVCCUnboxBoxLoadIntMH() { 1071 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1072 "vccUnboxBoxLoadInt", 1073 MethodType.methodType(int.class, ValueCapableClass1.class), 1074 CODE -> { 1075 CODE. 1076 aload_0(). 1077 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1078 vbox(ValueCapableClass1.class). 1079 getfield(ValueCapableClass1.class, "x", "I"). 1080 ireturn(); 1081 } 1082 ); 1083 1084 } 1085 1086 // Test value type array creation and initialization 1087 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD)) 1088 @Test(valid = ValueTypeArrayFlattenOn) 1089 public MyValue1[] test41(int len) { 1090 MyValue1[] va = new MyValue1[len]; 1091 for (int i = 0; i < len; ++i) { 1092 va[i] = MyValue1.createDontInline(rI, rL); 1093 } 1094 return va; 1095 } 1096 1097 @DontCompile 1098 public void test41_verifier(boolean warmup) { 1099 int len = Math.abs(rI % 10); 1100 MyValue1[] va = test41(len); 1101 for (int i = 0; i < len; ++i) { 1102 Asserts.assertEQ(va[i].hash(), hash()); 1103 } 1104 } 1105 1106 // Test creation of a value type array and element access 1107 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOOP + LOAD + TRAP)) 1108 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOC + ALLOCA + LOOP + LOAD + LOADP + STORE + TRAP)) 1109 public long test42() { 1110 MyValue1[] va = new MyValue1[1]; 1111 va[0] = MyValue1.createInline(rI, rL); 1112 return va[0].hash(); 1113 } 1114 1115 @DontCompile 1116 public void test42_verifier(boolean warmup) { 1117 long result = test42(); 1118 Asserts.assertEQ(result, hash()); 1119 } 1120 1121 // Test receiving a value type array from the interpreter, 1122 // updating its elements in a loop and computing a hash. 1123 @Test(failOn = (ALLOCA)) 1124 public long test43(MyValue1[] va) { 1125 long result = 0; 1126 for (int i = 0; i < 10; ++i) { 1127 result += va[i].hash(); 1128 va[i] = MyValue1.createInline(rI + 1, rL + 1); 1129 } 1130 return result; 1131 } 1132 1133 @DontCompile 1134 public void test43_verifier(boolean warmup) { 1135 MyValue1[] va = new MyValue1[10]; 1136 long expected = 0; 1137 for (int i = 0; i < 10; ++i) { 1138 va[i] = MyValue1.createDontInline(rI + i, rL + i); 1139 expected += va[i].hash(); 1140 } 1141 long result = test43(va); 1142 Asserts.assertEQ(expected, result); 1143 for (int i = 0; i < 10; ++i) { 1144 if (va[i].hash() != hash(rI + 1, rL + 1)) { 1145 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1)); 1146 } 1147 } 1148 } 1149 1150 // Test returning a value type array received from the interpreter 1151 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP) 1152 public MyValue1[] test44(MyValue1[] va) { 1153 return va; 1154 } 1155 1156 @DontCompile 1157 public void test44_verifier(boolean warmup) { 1158 MyValue1[] va = new MyValue1[10]; 1159 for (int i = 0; i < 10; ++i) { 1160 va[i] = MyValue1.createDontInline(rI + i, rL + i); 1161 } 1162 va = test44(va); 1163 for (int i = 0; i < 10; ++i) { 1164 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1165 } 1166 } 1167 1168 @Test(failOn = (TRAP)) 1169 public MyValue1[] test45(boolean b) { 1170 MyValue1[] va; 1171 if (b) { 1172 va = new MyValue1[5]; 1173 for (int i = 0; i < 5; ++i) { 1174 va[i] = MyValue1.createInline(rI, rL); 1175 } 1176 } else { 1177 va = new MyValue1[10]; 1178 for (int i = 0; i < 10; ++i) { 1179 va[i] = MyValue1.createInline(rI + i, rL + i); 1180 } 1181 } 1182 long sum = va[0].hashInterpreted(); 1183 if (b) { 1184 va[0] = MyValue1.createDontInline(rI, sum); 1185 } else { 1186 va[0] = MyValue1.createDontInline(rI + 1, sum + 1); 1187 } 1188 return va; 1189 } 1190 1191 @DontCompile 1192 public void test45_verifier(boolean warmup) { 1193 MyValue1[] va = test45(true); 1194 Asserts.assertEQ(va.length, 5); 1195 Asserts.assertEQ(va[0].hash(), hash(rI, hash())); 1196 for (int i = 1; i < 5; ++i) { 1197 Asserts.assertEQ(va[i].hash(), hash()); 1198 } 1199 va = test45(false); 1200 Asserts.assertEQ(va.length, 10); 1201 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1)); 1202 for (int i = 1; i < 10; ++i) { 1203 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1204 } 1205 } 1206 1207 // Test creation of value type array with single element 1208 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP)) 1209 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP)) 1210 public MyValue1 test46() { 1211 MyValue1[] va = new MyValue1[1]; 1212 return va[0]; 1213 } 1214 1215 @DontCompile 1216 public void test46_verifier(boolean warmup) { 1217 MyValue1[] va = new MyValue1[1]; 1218 MyValue1 v = test46(); 1219 Asserts.assertEQ(v.hash(), va[0].hash()); 1220 } 1221 1222 // Test default initialization of value type arrays 1223 @Test(failOn = LOAD) 1224 public MyValue1[] test47(int len) { 1225 return new MyValue1[len]; 1226 } 1227 1228 @DontCompile 1229 public void test47_verifier(boolean warmup) { 1230 int len = Math.abs(rI % 10); 1231 MyValue1[] va = new MyValue1[len]; 1232 MyValue1[] var = test47(len); 1233 for (int i = 0; i < len; ++i) { 1234 Asserts.assertEQ(va[i].hash(), var[i].hash()); 1235 } 1236 } 1237 1238 // Test creation of value type array with zero length 1239 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 1240 public MyValue1[] test48() { 1241 return new MyValue1[0]; 1242 } 1243 1244 @DontCompile 1245 public void test48_verifier(boolean warmup) { 1246 MyValue1[] va = test48(); 1247 Asserts.assertEQ(va.length, 0); 1248 } 1249 1250 static MyValue1[] test49_va; 1251 1252 // Test that value type array loaded from field has correct type 1253 @Test(failOn = (LOOP)) 1254 public long test49() { 1255 return test49_va[0].hash(); 1256 } 1257 1258 @DontCompile 1259 public void test49_verifier(boolean warmup) { 1260 test49_va = new MyValue1[1]; 1261 test49_va[0] = MyValue1.createInline(rI, rL); 1262 long result = test49(); 1263 Asserts.assertEQ(result, hash()); 1264 } 1265 1266 // test vdefault 1267 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1268 public long test50() { 1269 MyValue2 v = MyValue2.createDefaultInline(); 1270 return v.hash(); 1271 } 1272 1273 @DontCompile 1274 public void test50_verifier(boolean warmup) { 1275 long result = test50(); 1276 Asserts.assertEQ(result, MyValue2.createDefaultInline().hash()); 1277 } 1278 1279 // test vdefault 1280 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1281 public long test51() { 1282 MyValue1 v1 = MyValue1.createDefaultInline(); 1283 MyValue1 v2 = MyValue1.createDefaultDontInline(); 1284 return v1.hash() + v2.hash(); 1285 } 1286 1287 @DontCompile 1288 public void test51_verifier(boolean warmup) { 1289 long result = test51(); 1290 Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hash()); 1291 } 1292 1293 // test vwithfield 1294 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1295 public long test52() { 1296 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1297 return v.hash(); 1298 } 1299 1300 @DontCompile 1301 public void test52_verifier(boolean warmup) { 1302 long result = test52(); 1303 Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash()); 1304 } 1305 1306 // test vwithfield 1307 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1308 public long test53() { 1309 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL); 1310 MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL); 1311 return v1.hash() + v2.hash(); 1312 } 1313 1314 @DontCompile 1315 public void test53_verifier(boolean warmup) { 1316 long result = test53(); 1317 Asserts.assertEQ(result, 2 * hash()); 1318 } 1319 1320 // multi-dimensional arrays 1321 @Test 1322 public MyValue1[][][] test54(int len1, int len2, int len3) { 1323 MyValue1[][][] arr = new MyValue1[len1][len2][len3]; 1324 for (int i = 0; i < len1; i++) { 1325 for (int j = 0; j < len2; j++) { 1326 for (int k = 0; k < len3; k++) { 1327 arr[i][j][k] = MyValue1.createDontInline(rI + i , rL + j + k); 1328 } 1329 } 1330 } 1331 return arr; 1332 } 1333 1334 @DontCompile 1335 public void test54_verifier(boolean warmup) { 1336 MyValue1[][][] arr = test54(2, 3, 4); 1337 for (int i = 0; i < 2; i++) { 1338 for (int j = 0; j < 3; j++) { 1339 for (int k = 0; k < 4; k++) { 1340 Asserts.assertEQ(arr[i][j][k].hash(), MyValue1.createDontInline(rI + i , rL + j + k).hash()); 1341 } 1342 } 1343 } 1344 } 1345 1346 @Test 1347 public void test55(MyValue1[][][] arr, long[] res) { 1348 int l = 0; 1349 for (int i = 0; i < arr.length; i++) { 1350 for (int j = 0; j < arr[i].length; j++) { 1351 for (int k = 0; k < arr[i][j].length; k++) { 1352 res[l] = arr[i][j][k].hash(); 1353 l++; 1354 } 1355 } 1356 } 1357 } 1358 1359 @DontCompile 1360 public void test55_verifier(boolean warmup) { 1361 MyValue1[][][] arr = new MyValue1[2][3][4]; 1362 long[] res = new long[2*3*4]; 1363 long[] verif = new long[2*3*4]; 1364 int l = 0; 1365 for (int i = 0; i < 2; i++) { 1366 for (int j = 0; j < 3; j++) { 1367 for (int k = 0; k < 4; k++) { 1368 arr[i][j][k] = MyValue1.createDontInline(rI + i, rL + j + k); 1369 verif[l] = arr[i][j][k].hash(); 1370 l++; 1371 } 1372 } 1373 } 1374 test55(arr, res); 1375 for (int i = 0; i < verif.length; i++) { 1376 Asserts.assertEQ(res[i], verif[i]); 1377 } 1378 } 1379 1380 class TestClass56 { 1381 public MyValue1 v; 1382 } 1383 1384 // Test allocation elimination of unused object with initialized value type field 1385 @Test(failOn = ALLOC + LOAD + STORE + LOOP) 1386 public void test56(boolean deopt) { 1387 TestClass56 unused = new TestClass56(); 1388 MyValue1 v = MyValue1.createInline(rI, rL); 1389 unused.v = v; 1390 if (deopt) { 1391 // uncommon trap 1392 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test56")); 1393 } 1394 } 1395 1396 @DontCompile 1397 public void test56_verifier(boolean warmup) { 1398 test56(!warmup); 1399 } 1400 1401 // Test loop peeling 1402 @Test(failOn = ALLOC + LOAD + STORE) 1403 public void test57() { 1404 MyValue1 v = MyValue1.createInline(0, 1); 1405 // Trigger OSR compilation and loop peeling 1406 for (int i = 0; i < 100_000; ++i) { 1407 if (v.x != i || v.y != i + 1) { 1408 // Uncommon trap 1409 throw new RuntimeException("test57 failed"); 1410 } 1411 v = MyValue1.createInline(i + 1, i + 2); 1412 } 1413 } 1414 1415 @DontCompile 1416 public void test57_verifier(boolean warmup) { 1417 test57(); 1418 } 1419 1420 // Test loop peeling and unrolling 1421 @Test() 1422 public void test58() { 1423 MyValue1 v1 = MyValue1.createInline(0, 0); 1424 MyValue1 v2 = MyValue1.createInline(1, 1); 1425 // Trigger OSR compilation and loop peeling 1426 for (int i = 0; i < 100_000; ++i) { 1427 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) { 1428 // Uncommon trap 1429 throw new RuntimeException("test58 failed"); 1430 } 1431 v1 = MyValue1.createInline(2*(i+1), 0); 1432 v2 = MyValue1.createInline(i+2, i+2); 1433 } 1434 } 1435 1436 @DontCompile 1437 public void test58_verifier(boolean warmup) { 1438 test58(); 1439 } 1440 1441 1442 // ========== Test infrastructure ========== 1443 1444 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 1445 private static final int ValueTypePassFieldsAsArgsOn = 0x1; 1446 private static final int ValueTypePassFieldsAsArgsOff = 0x2; 1447 private static final int ValueTypeArrayFlattenOn = 0x4; 1448 private static final int ValueTypeArrayFlattenOff = 0x8; 1449 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff; 1450 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 1451 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten"); 1452 private static final int COMP_LEVEL_ANY = -1; 1453 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 1454 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 1455 private static final int WARMUP = 250; 1456 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 1457 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 1458 // TODO use Platform.isComp() after merge with JDK 9 1459 private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled "); 1460 1461 // Regular expressions used to match nodes in the PrintIdeal output 1462 private static final String START = "(\\d+\\t(.*"; 1463 private static final String MID = ".*)+\\t===.*"; 1464 private static final String END = ")|"; 1465 private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END; 1466 private static final String ALLOCA = START + "CallStaticJava" + MID + "_new_array_Java" + END; 1467 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1468 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END; 1469 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1470 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END; 1471 private static final String LOOP = START + "Loop" + MID + "" + END; 1472 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap" + END; 1473 // TODO: match field values of scalar replaced object 1474 private static final String SCOBJ = "(.*# ScObj.*" + END; 1475 1476 static { 1477 // Gather all test methods and put them in Hashtable 1478 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) { 1479 Test[] annos = m.getAnnotationsByType(Test.class); 1480 if (annos.length != 0) { 1481 tests.put("ValueTypeTestBench::" + m.getName(), m); 1482 } 1483 } 1484 } 1485 1486 private static void execute_vm(String... args) throws Throwable { 1487 Asserts.assertFalse(tests.isEmpty(), "no tests to execute"); 1488 ArrayList<String> all_args = new ArrayList(List.of(args)); 1489 // Run tests in own process and verify output 1490 all_args.add(ValueTypeTestBench.class.getName()); 1491 all_args.add("run"); 1492 // Spawn process with default JVM options from the test's run command 1493 OutputAnalyzer oa = ProcessTools.executeTestJvmAllArgs(all_args.toArray(new String[all_args.size()])); 1494 // If ideal graph printing is enabled/supported, verify output 1495 String output = oa.getOutput(); 1496 oa.shouldHaveExitValue(0); 1497 boolean verifyIR = output.contains("PrintIdeal enabled") && 1498 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform"); 1499 if (verifyIR) { 1500 parseOutput(output); 1501 } else { 1502 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); 1503 } 1504 } 1505 1506 public static void main(String[] args) throws Throwable { 1507 //tests.values().removeIf(p -> !p.getName().equals("test61")); // Run single test 1508 if (args.length == 0) { 1509 execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation", 1510 "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly", 1511 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*", 1512 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", 1513 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*", 1514 "-XX:CompileCommand=compileonly,java.lang.Object::<init>"); 1515 } else { 1516 // Execute tests 1517 ValueTypeTestBench bench = new ValueTypeTestBench(); 1518 bench.run(); 1519 } 1520 } 1521 1522 public static void parseOutput(String output) throws Exception { 1523 String split = "b compiler.valhalla.valuetypes."; 1524 String[] compilations = output.split(split); 1525 // Print header 1526 System.out.println(compilations[0]); 1527 // Iterate over compilation output 1528 for (String graph : compilations) { 1529 String[] lines = graph.split("\\n"); 1530 if (lines[0].contains("@")) { 1531 continue; // Ignore OSR compilations 1532 } 1533 String testName = lines[0].split(" ")[0]; 1534 Method test = tests.get(testName); 1535 if (test == null) { 1536 // Skip helper methods 1537 continue; 1538 } 1539 if (PRINT_GRAPH) { 1540 System.out.println("\nGraph for " + graph); 1541 } 1542 // Parse graph using regular expressions to determine if it contains forbidden nodes 1543 Test[] annos = test.getAnnotationsByType(Test.class); 1544 Test anno = null; 1545 for (Test a : annos) { 1546 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 1547 assert anno == null; 1548 anno = a; 1549 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 1550 assert anno == null; 1551 anno = a; 1552 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 1553 assert anno == null; 1554 anno = a; 1555 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 1556 assert anno == null; 1557 anno = a; 1558 } 1559 } 1560 assert anno != null; 1561 String regexFail = anno.failOn(); 1562 if (!regexFail.isEmpty()) { 1563 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 1564 Matcher matcher = pattern.matcher(graph); 1565 boolean found = matcher.find(); 1566 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 1567 } 1568 String[] regexMatch = anno.match(); 1569 int[] matchCount = anno.matchCount(); 1570 for (int i = 0; i < regexMatch.length; ++i) { 1571 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 1572 Matcher matcher = pattern.matcher(graph); 1573 int count = 0; 1574 String nodes = ""; 1575 while (matcher.find()) { 1576 count++; 1577 nodes += matcher.group() + "\n"; 1578 } 1579 if (matchCount[i] < 0) { 1580 Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 1581 } else { 1582 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 1583 } 1584 } 1585 tests.remove(testName); 1586 System.out.println(testName + " passed"); 1587 } 1588 // Check if all tests were compiled 1589 if (tests.size() != 0) { 1590 for (String name : tests.keySet()) { 1591 System.out.println("Test '" + name + "' not compiled!"); 1592 } 1593 throw new RuntimeException("Not all tests were compiled"); 1594 } 1595 } 1596 1597 public void setup(Method[] methods) { 1598 for (Method m : methods) { 1599 if (m.isAnnotationPresent(Test.class)) { 1600 // Don't inline tests 1601 WHITE_BOX.testSetDontInlineMethod(m, true); 1602 } 1603 if (m.isAnnotationPresent(DontCompile.class)) { 1604 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 1605 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 1606 } 1607 if (m.isAnnotationPresent(ForceInline.class)) { 1608 WHITE_BOX.testSetForceInlineMethod(m, true); 1609 } else if (m.isAnnotationPresent(DontInline.class)) { 1610 WHITE_BOX.testSetDontInlineMethod(m, true); 1611 } 1612 } 1613 } 1614 1615 public void run() throws Exception { 1616 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 1617 System.out.println("PrintIdeal enabled"); 1618 } 1619 System.out.format("rI = %d, rL = %d\n", rI, rL); 1620 setup(this.getClass().getDeclaredMethods()); 1621 setup(MyValue1.class.getDeclaredMethods()); 1622 setup(MyValue2.class.getDeclaredMethods()); 1623 1624 // TODO enable this after JDK 9 merge and verify that it's compiled 1625 //WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION); 1626 1627 // Execute tests 1628 for (Method test : tests.values()) { 1629 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class); 1630 // Warmup using verifier method 1631 for (int i = 0; i < WARMUP; ++i) { 1632 verifier.invoke(this, true); 1633 } 1634 // Trigger compilation 1635 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION); 1636 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 1637 // Check result 1638 verifier.invoke(this, false); 1639 } 1640 } 1641 } 1642 1643 // Mark method as test 1644 @Retention(RetentionPolicy.RUNTIME) 1645 @Repeatable(Tests.class) 1646 @interface Test { 1647 // Regular expression used to match forbidden IR nodes 1648 // in the C2 IR emitted for this test. 1649 String failOn() default ""; 1650 // Regular expressions used to match and count IR nodes. 1651 String[] match() default { }; 1652 int[] matchCount() default { }; 1653 int valid() default ValueTypeTestBench.AllFlags; 1654 } 1655 1656 @Retention(RetentionPolicy.RUNTIME) 1657 @interface Tests { 1658 Test[] value(); 1659 } 1660 1661 // Force method inlining during compilation 1662 @Retention(RetentionPolicy.RUNTIME) 1663 @interface ForceInline { } 1664 1665 // Prevent method inlining during compilation 1666 @Retention(RetentionPolicy.RUNTIME) 1667 @interface DontInline { } 1668 1669 // Prevent method compilation 1670 @Retention(RetentionPolicy.RUNTIME) 1671 @interface DontCompile { }