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 * @compile -XDenableValueTypes ValueCapableClass1.java ValueCapableClass2.java ValueTypeTestBench.java 32 * @run main ClassFileInstaller sun.hotspot.WhiteBox 33 * @run main ClassFileInstaller jdk.test.lib.Platform 34 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 35 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+VerifyAdapterSharing 36 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten 37 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1 -XX:+FullGCALotWithValueTypes 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:-ValueTypeReturnedAsFields -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:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten 46 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1 47 * compiler.valhalla.valuetypes.ValueTypeTestBench 48 */ 49 50 package compiler.valhalla.valuetypes; 51 52 import compiler.whitebox.CompilerWhiteBoxTest; 53 import jdk.internal.misc.Unsafe; 54 import jdk.test.lib.Asserts; 55 import jdk.test.lib.management.InputArguments; 56 import jdk.test.lib.Platform; 57 import jdk.test.lib.process.ProcessTools; 58 import jdk.test.lib.process.OutputAnalyzer; 59 import jdk.test.lib.Utils; 60 import sun.hotspot.WhiteBox; 61 62 import java.lang.annotation.Retention; 63 import java.lang.annotation.RetentionPolicy; 64 import java.lang.annotation.Repeatable; 65 import java.lang.invoke.*; 66 import java.lang.reflect.Method; 67 import java.util.ArrayList; 68 import java.util.Arrays; 69 import java.util.Hashtable; 70 import java.util.LinkedHashMap; 71 import java.util.List; 72 import java.util.Map; 73 import java.util.regex.Matcher; 74 import java.util.regex.Pattern; 75 import jdk.experimental.value.*; 76 77 // Test value types 78 __ByValue final class MyValue1 { 79 static int s; 80 static final long sf = ValueTypeTestBench.rL; 81 final int x; 82 final long y; 83 final short z; 84 final Integer o; 85 final int[] oa; 86 final MyValue2 v1; 87 final MyValue2 v2; 88 static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true); 89 final int c; 90 91 private MyValue1(int x, long y, short z, Integer o, int[] oa, MyValue2 v1, MyValue2 v2, int c) { 92 s = x; 93 this.x = x; 94 this.y = y; 95 this.z = z; 96 this.o = o; 97 this.oa = oa; 98 this.v1 = v1; 99 this.v2 = v2; 100 this.c = c; 101 } 102 103 private MyValue1() { 104 s = 0; 105 this.x = 0; 106 this.y = 0; 107 this.z = 0; 108 this.o = null; 109 this.oa = null; 110 this.v1 = MyValue2.createDefaultInline(); 111 this.v2 = MyValue2.createDefaultInline(); 112 this.c = 0; 113 } 114 115 @DontInline 116 __ValueFactory static MyValue1 createDefaultDontInline() { 117 return __MakeDefault MyValue1(); 118 } 119 120 @ForceInline 121 __ValueFactory static MyValue1 createDefaultInline() { 122 return __MakeDefault MyValue1(); 123 } 124 125 @DontInline 126 static MyValue1 createWithFieldsDontInline(int x, long y) { 127 MyValue1 v = createDefaultInline(); 128 v = setX(v, x); 129 v = setY(v, y); 130 v = setZ(v, (short)x); 131 v = setO(v, new Integer(x)); 132 int[] oa = {x}; 133 v = setOA(v, oa); 134 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y)); 135 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y)); 136 v = setC(v, ValueTypeTestBench.rI); 137 return v; 138 } 139 140 @ForceInline 141 static MyValue1 createWithFieldsInline(int x, long y) { 142 MyValue1 v = createDefaultInline(); 143 v = setX(v, x); 144 v = setY(v, y); 145 v = setZ(v, (short)x); 146 v = setO(v, new Integer(x)); 147 int[] oa = {x}; 148 v = setOA(v, oa); 149 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y)); 150 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y)); 151 v = setC(v, ValueTypeTestBench.rI); 152 return v; 153 } 154 155 // Hash only primitive and value type fields to avoid NullPointerException 156 @ForceInline 157 public long hashPrimitive() { 158 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash(); 159 } 160 161 @ForceInline 162 public long hash() { 163 return hashPrimitive() + o + oa[0]; 164 } 165 166 @DontCompile 167 public long hashInterpreted() { 168 return s + sf + x + y + z + o + oa[0] + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted(); 169 } 170 171 @ForceInline 172 public void print() { 173 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", o=" + (o != null ? (Integer)o : "NULL") + ", v1["); 174 v1.print(); 175 System.out.print("], v2["); 176 v2.print(); 177 System.out.print("], v3["); 178 v3.print(); 179 System.out.print("], c=" + c); 180 } 181 182 @ForceInline 183 __ValueFactory static MyValue1 setX(MyValue1 v, int x) { 184 v.x = x; 185 return v; 186 } 187 188 @ForceInline 189 __ValueFactory static MyValue1 setY(MyValue1 v, long y) { 190 v.y = y; 191 return v; 192 } 193 194 @ForceInline 195 __ValueFactory static MyValue1 setZ(MyValue1 v, short z) { 196 v.z = z; 197 return v; 198 } 199 200 @ForceInline 201 __ValueFactory static MyValue1 setO(MyValue1 v, Integer o) { 202 v.o = o; 203 return v; 204 } 205 206 @ForceInline 207 __ValueFactory static MyValue1 setOA(MyValue1 v, int[] oa) { 208 v.oa = oa; 209 return v; 210 } 211 212 @ForceInline 213 __ValueFactory static MyValue1 setC(MyValue1 v, int c) { 214 v.c = c; 215 return v; 216 } 217 218 @ForceInline 219 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) { 220 v.v1 = v1; 221 return v; 222 } 223 224 @ForceInline 225 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) { 226 v.v2 = v2; 227 return v; 228 } 229 } 230 231 __ByValue final class MyValue2 { 232 final int x; 233 final byte y; 234 final boolean b; 235 final long c; 236 237 private MyValue2(int x, byte y, boolean b, long c) { 238 this.x = x; 239 this.y = y; 240 this.b = b; 241 this.c = c; 242 } 243 244 private MyValue2() { 245 this.x = 0; 246 this.y = 0; 247 this.b = false; 248 this.c = 0; 249 } 250 251 @ForceInline 252 __ValueFactory public static MyValue2 createDefaultInline() { 253 return __MakeDefault MyValue2(); 254 } 255 256 @ForceInline 257 public static MyValue2 createWithFieldsInline(int x, boolean b) { 258 MyValue2 v = createDefaultInline(); 259 v = setX(v, x); 260 v = setY(v, (byte)x); 261 v = setB(v, b); 262 v = setC(v, ValueTypeTestBench.rL); 263 return v; 264 } 265 266 @ForceInline 267 public long hash() { 268 return x + y + (b ? 0 : 1) + c; 269 } 270 271 @DontInline 272 public long hashInterpreted() { 273 return x + y + (b ? 0 : 1) + c; 274 } 275 276 @ForceInline 277 public void print() { 278 System.out.print("x=" + x + "y=" + y + ", b=" + b + ", c=" + c); 279 } 280 281 @ForceInline 282 __ValueFactory static MyValue2 setX(MyValue2 v, int x) { 283 v.x = x; 284 return v; 285 } 286 287 @ForceInline 288 __ValueFactory static MyValue2 setY(MyValue2 v, byte y) { 289 v.y = y; 290 return v; 291 } 292 293 @ForceInline 294 __ValueFactory static MyValue2 setC(MyValue2 v, long c) { 295 v.c = c; 296 return v; 297 } 298 299 @ForceInline 300 __ValueFactory static MyValue2 setB(MyValue2 v, boolean b) { 301 v.b = b; 302 return v; 303 } 304 } 305 306 // Value type definition to stress test return of a value in registers 307 // (uses all registers of calling convention on x86_64) 308 __ByValue final class MyValue3 { 309 final char c; 310 final byte bb; 311 final short s; 312 final int i; 313 final long l; 314 final Object o; 315 final float f1; 316 final double f2; 317 final float f3; 318 final double f4; 319 final float f5; 320 final double f6; 321 final float f7; 322 final double f8; 323 324 private MyValue3(char c, 325 byte bb, 326 short s, 327 int i, 328 long l, 329 Object o, 330 float f1, 331 double f2, 332 float f3, 333 double f4, 334 float f5, 335 double f6, 336 float f7, 337 double f8) { 338 this.c = c; 339 this.bb = bb; 340 this.s = s; 341 this.i = i; 342 this.l = l; 343 this.o = o; 344 this.f1 = f1; 345 this.f2 = f2; 346 this.f3 = f3; 347 this.f4 = f4; 348 this.f5 = f5; 349 this.f6 = f6; 350 this.f7 = f7; 351 this.f8 = f8; 352 } 353 354 private MyValue3() { 355 this.c = 0; 356 this.bb = 0; 357 this.s = 0; 358 this.i = 0; 359 this.l = 0; 360 this.o = null; 361 this.f1 = 0; 362 this.f2 = 0; 363 this.f3 = 0; 364 this.f4 = 0; 365 this.f5 = 0; 366 this.f6 = 0; 367 this.f7 = 0; 368 this.f8 = 0; 369 } 370 371 @ForceInline 372 __ValueFactory static MyValue3 setC(MyValue3 v, char c) { 373 v.c = c; 374 return v; 375 } 376 377 @ForceInline 378 __ValueFactory static MyValue3 setBB(MyValue3 v, byte bb) { 379 v.bb = bb; 380 return v; 381 } 382 383 @ForceInline 384 __ValueFactory static MyValue3 setS(MyValue3 v, short s) { 385 v.s = s; 386 return v; 387 } 388 389 @ForceInline 390 __ValueFactory static MyValue3 setI(MyValue3 v, int i) { 391 v.i = i; 392 return v; 393 } 394 395 @ForceInline 396 __ValueFactory static MyValue3 setL(MyValue3 v, long l) { 397 v.l = l; 398 return v; 399 } 400 401 @ForceInline 402 __ValueFactory static MyValue3 setO(MyValue3 v, Object o) { 403 v.o = o; 404 return v; 405 } 406 407 @ForceInline 408 __ValueFactory static MyValue3 setF1(MyValue3 v, float f1) { 409 v.f1 = f1; 410 return v; 411 } 412 413 @ForceInline 414 __ValueFactory static MyValue3 setF2(MyValue3 v, double f2) { 415 v.f2 = f2; 416 return v; 417 } 418 419 @ForceInline 420 __ValueFactory static MyValue3 setF3(MyValue3 v, float f3) { 421 v.f3 = f3; 422 return v; 423 } 424 425 @ForceInline 426 __ValueFactory static MyValue3 setF4(MyValue3 v, double f4) { 427 v.f4 = f4; 428 return v; 429 } 430 431 @ForceInline 432 __ValueFactory static MyValue3 setF5(MyValue3 v, float f5) { 433 v.f5 = f5; 434 return v; 435 } 436 437 @ForceInline 438 __ValueFactory static MyValue3 setF6(MyValue3 v, double f6) { 439 v.f6 = f6; 440 return v; 441 } 442 443 @ForceInline 444 __ValueFactory static MyValue3 setF7(MyValue3 v, float f7) { 445 v.f7 = f7; 446 return v; 447 } 448 449 @ForceInline 450 __ValueFactory static MyValue3 setF8(MyValue3 v, double f8) { 451 v.f8 = f8; 452 return v; 453 } 454 455 @ForceInline 456 __ValueFactory public static MyValue3 createDefault() { 457 return __MakeDefault MyValue3(); 458 } 459 460 @ForceInline 461 public static MyValue3 create() { 462 java.util.Random r = Utils.getRandomInstance(); 463 MyValue3 v = createDefault(); 464 v = setC(v, (char)r.nextInt()); 465 v = setBB(v, (byte)r.nextInt()); 466 v = setS(v, (short)r.nextInt()); 467 v = setI(v, r.nextInt()); 468 v = setL(v, r.nextLong()); 469 v = setO(v, new Object()); 470 v = setF1(v, r.nextFloat()); 471 v = setF2(v, r.nextDouble()); 472 v = setF3(v, r.nextFloat()); 473 v = setF4(v, r.nextDouble()); 474 v = setF5(v, r.nextFloat()); 475 v = setF6(v, r.nextDouble()); 476 v = setF7(v, r.nextFloat()); 477 v = setF8(v, r.nextDouble()); 478 return v; 479 } 480 481 public void verify(MyValue3 other) { 482 Asserts.assertEQ(c, other.c); 483 Asserts.assertEQ(bb, other.bb); 484 Asserts.assertEQ(s, other.s); 485 Asserts.assertEQ(i, other.i); 486 Asserts.assertEQ(l, other.l); 487 Asserts.assertEQ(o, other.o); 488 Asserts.assertEQ(f1, other.f1); 489 Asserts.assertEQ(f2, other.f2); 490 Asserts.assertEQ(f3, other.f3); 491 Asserts.assertEQ(f4, other.f4); 492 Asserts.assertEQ(f5, other.f5); 493 Asserts.assertEQ(f6, other.f6); 494 Asserts.assertEQ(f7, other.f7); 495 Asserts.assertEQ(f8, other.f8); 496 } 497 } 498 499 // Value type definition with too many fields to return in registers 500 __ByValue final class MyValue4 { 501 final MyValue3 v1; 502 final MyValue3 v2; 503 504 private MyValue4(MyValue3 v1, MyValue3 v2) { 505 this.v1 = v1; 506 this.v2 = v2; 507 } 508 509 private MyValue4() { 510 this.v1 = MyValue3.createDefault(); 511 this.v2 = MyValue3.createDefault(); 512 } 513 514 @ForceInline 515 __ValueFactory static MyValue4 setV1(MyValue4 v, MyValue3 v1) { 516 v.v1 = v1; 517 return v; 518 } 519 520 @ForceInline 521 __ValueFactory static MyValue4 setV2(MyValue4 v, MyValue3 v2) { 522 v.v2 = v2; 523 return v; 524 } 525 526 @ForceInline 527 __ValueFactory public static MyValue4 createDefault() { 528 return __MakeDefault MyValue4(); 529 } 530 531 @ForceInline 532 public static MyValue4 create() { 533 MyValue4 v = createDefault(); 534 MyValue3 v1 = MyValue3.create(); 535 v = setV1(v, v1); 536 MyValue3 v2 = MyValue3.create(); 537 v = setV2(v, v2); 538 return v; 539 } 540 541 public void verify(MyValue4 other) { 542 v1.verify(other.v1); 543 v2.verify(other.v2); 544 } 545 } 546 547 548 public class ValueTypeTestBench { 549 // Print ideal graph after execution of each test 550 private static final boolean PRINT_GRAPH = true; 551 552 // Random test values 553 public static final int rI = Utils.getRandomInstance().nextInt() % 1000; 554 public static final long rL = Utils.getRandomInstance().nextLong() % 1000; 555 556 public ValueTypeTestBench() { 557 val3 = MyValue1.createWithFieldsInline(rI, rL); 558 } 559 560 // MethodHandles and value-capable class instance needed for testing vbox/vunbox 561 private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH(); 562 private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH(); 563 private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH(); 564 private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH(); 565 private static final MethodHandle nullvccUnboxLoadLongMH = generateNullVCCUnboxLoadLongMH(); 566 private static final MethodHandle objectUnboxLoadLongMH = generateObjectUnboxLoadLongMH(); 567 private static final MethodHandle objectBoxMH = generateObjectBoxMH(); 568 private static final MethodHandle checkedvccUnboxLoadLongMH = generateCheckedVCCUnboxLoadLongMH(); 569 570 private static final ValueCapableClass1 vcc = ValueCapableClass1.create(rL, rI, (short)rI, (short)rI); 571 private static final ValueCapableClass2 vcc2 = ValueCapableClass2.create(rL + 1); 572 573 // ========== Helper methods ========== 574 575 public long hash() { 576 return hash(rI, rL); 577 } 578 579 public long hash(int x, long y) { 580 return MyValue1.createWithFieldsInline(x, y).hash(); 581 } 582 583 // ========== Test definitions ========== 584 585 // Receive value type through call to interpreter 586 @Test(failOn = ALLOC + STORE + TRAP) 587 public long test1() { 588 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 589 return v.hash(); 590 } 591 592 @DontCompile 593 public void test1_verifier(boolean warmup) { 594 long result = test1(); 595 Asserts.assertEQ(result, hash()); 596 } 597 598 // Receive value type from interpreter via parameter 599 @Test(failOn = ALLOC + STORE + TRAP) 600 public long test2(MyValue1 v) { 601 return v.hash(); 602 } 603 604 @DontCompile 605 public void test2_verifier(boolean warmup) { 606 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 607 long result = test2(v); 608 Asserts.assertEQ(result, hash()); 609 } 610 611 // Return incoming value type without accessing fields 612 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 11}, failOn = LOAD + TRAP) 613 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP) 614 public MyValue1 test3(MyValue1 v) { 615 return v; 616 } 617 618 @DontCompile 619 public void test3_verifier(boolean warmup) { 620 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 621 MyValue1 v2 = test3(v1); 622 Asserts.assertEQ(v1.x, v2.x); 623 Asserts.assertEQ(v1.y, v2.y); 624 } 625 626 // Create a value type in compiled code and only use fields. 627 // Allocation should go away because value type does not escape. 628 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 629 public long test4() { 630 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 631 return v.hash(); 632 } 633 634 @DontCompile 635 public void test4_verifier(boolean warmup) { 636 long result = test4(); 637 Asserts.assertEQ(result, hash()); 638 } 639 640 // Create a value type in compiled code and pass it to 641 // an inlined compiled method via a call. 642 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 643 public long test5() { 644 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 645 return test5Inline(v); 646 } 647 648 @ForceInline 649 public long test5Inline(MyValue1 v) { 650 return v.hash(); 651 } 652 653 @DontCompile 654 public void test5_verifier(boolean warmup) { 655 long result = test5(); 656 Asserts.assertEQ(result, hash()); 657 } 658 659 // Create a value type in compiled code and pass it to 660 // the interpreter via a call. 661 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC) 662 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 663 public long test6() { 664 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 665 // Pass to interpreter 666 return v.hashInterpreted(); 667 } 668 669 @DontCompile 670 public void test6_verifier(boolean warmup) { 671 long result = test6(); 672 Asserts.assertEQ(result, hash()); 673 } 674 675 // Create a value type in compiled code and pass it to 676 // the interpreter by returning. 677 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 678 public MyValue1 test7(int x, long y) { 679 return MyValue1.createWithFieldsInline(x, y); 680 } 681 682 @DontCompile 683 public void test7_verifier(boolean warmup) { 684 MyValue1 v = test7(rI, rL); 685 Asserts.assertEQ(v.hash(), hash()); 686 } 687 688 // Merge value types created from two branches 689 @Test(failOn = ALLOC + STORE + TRAP) 690 public long test8(boolean b) { 691 MyValue1 v; 692 if (b) { 693 v = MyValue1.createWithFieldsInline(rI, rL); 694 } else { 695 v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1); 696 } 697 return v.hash(); 698 } 699 700 @DontCompile 701 public void test8_verifier(boolean warmup) { 702 Asserts.assertEQ(test8(true), hash()); 703 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1)); 704 } 705 706 // Merge value types created from two branches 707 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {10}, failOn = TRAP + ALLOC + STORE) 708 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP) 709 public MyValue1 test9(boolean b) { 710 MyValue1 v; 711 if (b) { 712 // Value type is not allocated 713 v = MyValue1.createWithFieldsInline(rI, rL); 714 } else { 715 // Value type is allocated by the callee 716 v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1); 717 } 718 // Need to allocate value type if 'b' is true 719 long sum = v.hashInterpreted(); 720 if (b) { 721 v = MyValue1.createWithFieldsDontInline(rI, sum); 722 } else { 723 v = MyValue1.createWithFieldsDontInline(rI, sum + 1); 724 } 725 // Don't need to allocate value type because both branches allocate 726 return v; 727 } 728 729 @DontCompile 730 public void test9_verifier(boolean warmup) { 731 MyValue1 v = test9(true); 732 Asserts.assertEQ(v.x, rI); 733 Asserts.assertEQ(v.y, hash()); 734 v = test9(false); 735 Asserts.assertEQ(v.x, rI); 736 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1); 737 } 738 739 // Merge value types created in a loop (not inlined) 740 @Test(failOn = ALLOC + STORE + TRAP) 741 public long test10(int x, long y) { 742 MyValue1 v = MyValue1.createWithFieldsDontInline(x, y); 743 for (int i = 0; i < 10; ++i) { 744 v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1); 745 } 746 return v.hash(); 747 } 748 749 @DontCompile 750 public void test10_verifier(boolean warmup) { 751 long result = test10(rI, rL); 752 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 753 } 754 755 // Merge value types created in a loop (inlined) 756 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 757 public long test11(int x, long y) { 758 MyValue1 v = MyValue1.createWithFieldsInline(x, y); 759 for (int i = 0; i < 10; ++i) { 760 v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1); 761 } 762 return v.hash(); 763 } 764 765 @DontCompile 766 public void test11_verifier(boolean warmup) { 767 long result = test11(rI, rL); 768 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 769 } 770 771 // Test loop with uncommon trap referencing a value type 772 @Test(match = {TRAP, SCOBJ}, matchCount = {1, -1 /* at least 1 */}, failOn = LOAD) 773 public long test12(boolean b) { 774 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 775 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 776 for (int i = 0; i < va.length; ++i) { 777 va[i] = MyValue1.createWithFieldsInline(rI, rL); 778 } 779 long result = rL; 780 for (int i = 0; i < 1000; ++i) { 781 if (b) { 782 result += v.x; 783 } else { 784 // Uncommon trap referencing v. We delegate allocation to the 785 // interpreter by adding a SafePointScalarObjectNode. 786 result = v.hashInterpreted(); 787 for (int j = 0; j < va.length; ++j) { 788 result += va[j].hash(); 789 } 790 } 791 } 792 return result; 793 } 794 795 @DontCompile 796 public void test12_verifier(boolean warmup) { 797 long result = test12(warmup); 798 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 799 } 800 801 // Test loop with uncommon trap referencing a value type 802 @Test(match = {TRAP}, matchCount = {1}) 803 public long test13(boolean b) { 804 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 805 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 806 for (int i = 0; i < va.length; ++i) { 807 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 808 } 809 long result = rL; 810 for (int i = 0; i < 1000; ++i) { 811 if (b) { 812 result += v.x; 813 } else { 814 // Uncommon trap referencing v. Should not allocate 815 // but just pass the existing oop to the uncommon trap. 816 result = v.hashInterpreted(); 817 for (int j = 0; j < va.length; ++j) { 818 result += va[j].hashInterpreted(); 819 } 820 } 821 } 822 return result; 823 } 824 825 @DontCompile 826 public void test13_verifier(boolean warmup) { 827 long result = test13(warmup); 828 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 829 } 830 831 // Create a value type in a non-inlined method and then call a 832 // non-inlined method on that value type. 833 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {10}) 834 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP)) 835 public long test14() { 836 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 837 return v.hashInterpreted(); 838 } 839 840 @DontCompile 841 public void test14_verifier(boolean b) { 842 long result = test14(); 843 Asserts.assertEQ(result, hash()); 844 } 845 846 // Create a value type in an inlined method and then call a 847 // non-inlined method on that value type. 848 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC)) 849 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1}) 850 public long test15() { 851 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 852 return v.hashInterpreted(); 853 } 854 855 @DontCompile 856 public void test15_verifier(boolean b) { 857 long result = test15(); 858 Asserts.assertEQ(result, hash()); 859 } 860 861 // Create a value type in a non-inlined method and then call an 862 // inlined method on that value type. 863 @Test(failOn = (ALLOC + STORE + TRAP)) 864 public long test16() { 865 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 866 return v.hash(); 867 } 868 869 @DontCompile 870 public void test16_verifier(boolean b) { 871 long result = test16(); 872 Asserts.assertEQ(result, hash()); 873 } 874 875 // Create a value type in an inlined method and then call an 876 // inlined method on that value type. 877 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 878 public long test17() { 879 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 880 return v.hash(); 881 } 882 883 @DontCompile 884 public void test17_verifier(boolean b) { 885 long result = test17(); 886 Asserts.assertEQ(result, hash()); 887 } 888 889 // Create a value type in compiled code and pass it to the 890 // interpreter via a call. The value is live at the first call so 891 // debug info should include a reference to all its fields. 892 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 893 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 894 public long test18() { 895 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 896 v.hashInterpreted(); 897 return v.hashInterpreted(); 898 } 899 900 @DontCompile 901 public void test18_verifier(boolean warmup) { 902 long result = test18(); 903 Asserts.assertEQ(result, hash()); 904 } 905 906 // Create a value type in compiled code and pass it to the 907 // interpreter via a call. The value type is passed twice but 908 // should only be allocated once. 909 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 910 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 911 public long test19() { 912 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 913 return sumValue(v, v); 914 } 915 916 @DontCompile 917 public long sumValue(MyValue1 v, MyValue1 dummy) { 918 return v.hash(); 919 } 920 921 @DontCompile 922 public void test19_verifier(boolean warmup) { 923 long result = test19(); 924 Asserts.assertEQ(result, hash()); 925 } 926 927 // Create a value type (array) in compiled code and pass it to the 928 // interpreter via a call. The value type is live at the uncommon 929 // trap: verify that deoptimization causes the value type to be 930 // correctly allocated. 931 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE) 932 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {2}, failOn = LOAD) 933 public long test20(boolean deopt) { 934 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 935 MyValue2[] va = new MyValue2[3]; 936 if (deopt) { 937 // uncommon trap 938 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20")); 939 } 940 return v.hashInterpreted() + va[0].hashInterpreted() + 941 va[1].hashInterpreted() + va[2].hashInterpreted(); 942 } 943 944 @DontCompile 945 public void test20_verifier(boolean warmup) { 946 MyValue2[] va = new MyValue2[42]; 947 long result = test20(!warmup); 948 Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash()); 949 } 950 951 // Value type fields in regular object 952 MyValue1 val1; 953 MyValue2 val2; 954 final MyValue1 val3; 955 static MyValue1 val4; 956 static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL); 957 958 // Test value type fields in objects 959 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP)) 960 public long test21(int x, long y) { 961 // Compute hash of value type fields 962 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 963 // Update fields 964 val1 = MyValue1.createWithFieldsInline(x, y); 965 val2 = MyValue2.createWithFieldsInline(x, true); 966 val4 = MyValue1.createWithFieldsInline(x, y); 967 return result; 968 } 969 970 @DontCompile 971 public void test21_verifier(boolean warmup) { 972 // Check if hash computed by test18 is correct 973 val1 = MyValue1.createWithFieldsInline(rI, rL); 974 val2 = val1.v2; 975 // val3 is initialized in the constructor 976 val4 = val1; 977 // val5 is initialized in the static initializer 978 long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 979 long result = test21(rI + 1, rL + 1); 980 Asserts.assertEQ(result, hash); 981 // Check if value type fields were updated 982 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1)); 983 Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, true).hash()); 984 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1)); 985 } 986 987 // Test folding of constant value type fields 988 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 989 public long test22() { 990 // This should be constant folded 991 return val5.hash() + val5.v3.hash(); 992 } 993 994 @DontCompile 995 public void test22_verifier(boolean warmup) { 996 long result = test22(); 997 Asserts.assertEQ(result, val5.hash() + val5.v3.hash()); 998 } 999 1000 // Test OSR compilation 1001 @Test() 1002 public long test23() { 1003 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 1004 MyValue1[] va = new MyValue1[Math.abs(rI) % 3]; 1005 for (int i = 0; i < va.length; ++i) { 1006 va[i] = MyValue1.createWithFieldsInline(rI, rL); 1007 } 1008 long result = 0; 1009 // Long loop to trigger OSR compilation 1010 for (int i = 0 ; i < 100_000; ++i) { 1011 // Reference local value type in interpreter state 1012 result = v.hash(); 1013 for (int j = 0; j < va.length; ++j) { 1014 result += va[j].hash(); 1015 } 1016 } 1017 return result; 1018 } 1019 1020 @DontCompile 1021 public void test23_verifier(boolean warmup) { 1022 long result = test23(); 1023 Asserts.assertEQ(result, ((Math.abs(rI) % 3) + 1) * hash()); 1024 } 1025 1026 // Test interpreter to compiled code with various signatures 1027 @Test(failOn = ALLOC + STORE + TRAP) 1028 public long test24(MyValue2 v) { 1029 return v.hash(); 1030 } 1031 1032 @DontCompile 1033 public void test24_verifier(boolean warmup) { 1034 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1035 long result = test24(v); 1036 Asserts.assertEQ(result, v.hashInterpreted()); 1037 } 1038 1039 @Test(failOn = ALLOC + STORE + TRAP) 1040 public long test25(int i1, MyValue2 v, int i2) { 1041 return v.hash() + i1 - i2; 1042 } 1043 1044 @DontCompile 1045 public void test25_verifier(boolean warmup) { 1046 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1047 long result = test25(rI, v, 2*rI); 1048 Asserts.assertEQ(result, v.hashInterpreted() - rI); 1049 } 1050 1051 @Test(failOn = ALLOC + STORE + TRAP) 1052 public long test26(long l1, MyValue2 v, long l2) { 1053 return v.hash() + l1 - l2; 1054 } 1055 1056 @DontCompile 1057 public void test26_verifier(boolean warmup) { 1058 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1059 long result = test26(rL, v, 2*rL); 1060 Asserts.assertEQ(result, v.hashInterpreted() - rL); 1061 } 1062 1063 @Test(failOn = ALLOC + STORE + TRAP) 1064 public long test27(int i, MyValue2 v, long l) { 1065 return v.hash() + i + l; 1066 } 1067 1068 @DontCompile 1069 public void test27_verifier(boolean warmup) { 1070 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1071 long result = test27(rI, v, rL); 1072 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1073 } 1074 1075 @Test(failOn = ALLOC + STORE + TRAP) 1076 public long test28(long l, MyValue2 v, int i) { 1077 return v.hash() + i + l; 1078 } 1079 1080 @DontCompile 1081 public void test28_verifier(boolean warmup) { 1082 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1083 long result = test28(rL, v, rI); 1084 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1085 } 1086 1087 @Test(failOn = ALLOC + STORE + TRAP) 1088 public long test29(long l, MyValue1 v1, int i, MyValue2 v2) { 1089 return v1.hash() + i + l + v2.hash(); 1090 } 1091 1092 @DontCompile 1093 public void test29_verifier(boolean warmup) { 1094 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 1095 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 1096 long result = test29(rL, v1, rI, v2); 1097 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 1098 } 1099 1100 // Test compiled code to interpreter with various signatures 1101 @DontCompile 1102 public long test30_interp(MyValue2 v) { 1103 return v.hash(); 1104 } 1105 1106 @Test(failOn = ALLOC + STORE + TRAP) 1107 public long test30(MyValue2 v) { 1108 return test30_interp(v); 1109 } 1110 1111 @DontCompile 1112 public void test30_verifier(boolean warmup) { 1113 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1114 long result = test30(v); 1115 Asserts.assertEQ(result, v.hashInterpreted()); 1116 } 1117 1118 @DontCompile 1119 public long test31_interp(int i1, MyValue2 v, int i2) { 1120 return v.hash() + i1 - i2; 1121 } 1122 1123 @Test(failOn = ALLOC + STORE + TRAP) 1124 public long test31(int i1, MyValue2 v, int i2) { 1125 return test31_interp(i1, v, i2); 1126 } 1127 1128 @DontCompile 1129 public void test31_verifier(boolean warmup) { 1130 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1131 long result = test31(rI, v, 2*rI); 1132 Asserts.assertEQ(result, v.hashInterpreted() - rI); 1133 } 1134 1135 @DontCompile 1136 public long test32_interp(long l1, MyValue2 v, long l2) { 1137 return v.hash() + l1 - l2; 1138 } 1139 1140 @Test(failOn = ALLOC + STORE + TRAP) 1141 public long test32(long l1, MyValue2 v, long l2) { 1142 return test32_interp(l1, v, l2); 1143 } 1144 1145 @DontCompile 1146 public void test32_verifier(boolean warmup) { 1147 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1148 long result = test32(rL, v, 2*rL); 1149 Asserts.assertEQ(result, v.hashInterpreted() - rL); 1150 } 1151 1152 @DontCompile 1153 public long test33_interp(int i, MyValue2 v, long l) { 1154 return v.hash() + i + l; 1155 } 1156 1157 @Test(failOn = ALLOC + STORE + TRAP) 1158 public long test33(int i, MyValue2 v, long l) { 1159 return test33_interp(i, v, l); 1160 } 1161 1162 @DontCompile 1163 public void test33_verifier(boolean warmup) { 1164 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1165 long result = test33(rI, v, rL); 1166 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1167 } 1168 1169 @DontCompile 1170 public long test34_interp(long l, MyValue2 v, int i) { 1171 return v.hash() + i + l; 1172 } 1173 1174 @Test(failOn = ALLOC + STORE + TRAP) 1175 public long test34(long l, MyValue2 v, int i) { 1176 return test34_interp(l, v, i); 1177 } 1178 1179 @DontCompile 1180 public void test34_verifier(boolean warmup) { 1181 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1182 long result = test34(rL, v, rI); 1183 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1184 } 1185 1186 @DontCompile 1187 public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 1188 return v1.hash() + i + l + v2.hash(); 1189 } 1190 1191 @Test(failOn = ALLOC + STORE + TRAP) 1192 public long test35(long l, MyValue1 v1, int i, MyValue2 v2) { 1193 return test35_interp(l, v1, i, v2); 1194 } 1195 1196 @DontCompile 1197 public void test35_verifier(boolean warmup) { 1198 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 1199 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 1200 long result = test35(rL, v1, rI, v2); 1201 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 1202 } 1203 1204 // test that debug info at a call is correct 1205 @DontCompile 1206 public long test36_interp(MyValue2 v, MyValue1[] va, boolean deopt) { 1207 if (deopt) { 1208 // uncommon trap 1209 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36")); 1210 } 1211 return v.hash() + va[0].hash() + va[1].hash(); 1212 } 1213 1214 @Test(failOn = ALLOC + STORE + TRAP) 1215 public long test36(MyValue2 v, MyValue1[] va, boolean flag, long l) { 1216 return test36_interp(v, va, flag) + l; 1217 } 1218 1219 @DontCompile 1220 public void test36_verifier(boolean warmup) { 1221 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1222 MyValue1[] va = new MyValue1[2]; 1223 va[0] = MyValue1.createWithFieldsDontInline(rI, rL); 1224 va[1] = MyValue1.createWithFieldsDontInline(rI, rL); 1225 long result = test36(v, va, !warmup, rL); 1226 Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL); 1227 } 1228 1229 // Test vbox and vunbox 1230 @Test 1231 public long test37() throws Throwable { 1232 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 1233 } 1234 1235 @DontCompile 1236 public void test37_verifier(boolean warmup) { 1237 try { 1238 long result = test37(); 1239 Asserts.assertEQ(vcc.t, result, "Field t of input and result must be equal."); 1240 } catch (Throwable t) { 1241 throw new RuntimeException("test 37 failed", t); 1242 } 1243 } 1244 1245 // Generate a MethodHandle that obtains field t of the 1246 // derived value type 1247 private static MethodHandle generateVCCUnboxLoadLongMH() { 1248 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1249 "vccUnboxLoadLong", 1250 MethodType.methodType(long.class, ValueCapableClass1.class), 1251 CODE -> { 1252 CODE. 1253 aload_0(). 1254 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1255 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1256 lreturn(); 1257 } 1258 ); 1259 } 1260 1261 @Test 1262 public int test38() throws Throwable { 1263 return (int)vccUnboxLoadIntMH.invokeExact(vcc); 1264 } 1265 1266 @DontCompile 1267 public void test38_verifier(boolean warmup) { 1268 try { 1269 int result = test38(); 1270 Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal."); 1271 } catch (Throwable t) { 1272 throw new RuntimeException("test 38 failed", t); 1273 } 1274 } 1275 1276 // Generate a MethodHandle that obtains field x of the 1277 // derived value type 1278 private static MethodHandle generateVCCUnboxLoadIntMH() { 1279 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1280 "vccUnboxLoadInt", 1281 MethodType.methodType(int.class, ValueCapableClass1.class), 1282 CODE -> { 1283 CODE. 1284 aload_0(). 1285 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1286 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "x", "I"). 1287 ireturn(); 1288 } 1289 ); 1290 } 1291 1292 @Test 1293 public ValueCapableClass1 test39() throws Throwable { 1294 return (ValueCapableClass1)vccUnboxBoxMH.invokeExact(vcc); 1295 } 1296 1297 @DontCompile 1298 public void test39_verifier(boolean warmup) { 1299 try { 1300 ValueCapableClass1 result = test39(); 1301 Asserts.assertEQ(vcc.value(), result.value(), "Value of VCC and returned VCC must be equal"); 1302 } catch (Throwable t) { 1303 throw new RuntimeException("test 39 failed", t); 1304 } 1305 } 1306 1307 // Generate a MethodHandle that takes a value-capable class, 1308 // unboxes it, then boxes it again and returns it. 1309 private static MethodHandle generateVCCUnboxBoxMH() { 1310 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1311 "vccUnboxBox", 1312 MethodType.methodType(ValueCapableClass1.class, ValueCapableClass1.class), 1313 CODE -> { 1314 CODE. 1315 aload_0(). 1316 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1317 vbox(ValueCapableClass1.class). 1318 areturn(); 1319 } 1320 ); 1321 } 1322 1323 @Test 1324 public int test40() throws Throwable { 1325 return (int)vccUnboxBoxLoadIntMH.invokeExact(vcc); 1326 } 1327 1328 @DontCompile 1329 public void test40_verifier(boolean warmup) { 1330 try { 1331 int result = test40(); 1332 Asserts.assertEQ(vcc.x, result, "Field x of VCC and result must be equal"); 1333 } catch (Throwable t) { 1334 throw new RuntimeException("Test failed in the interpeter", t); 1335 } 1336 } 1337 1338 // Generate a MethodHandle that takes a value-capable class, 1339 // unboxes it, boxes it, reads a field from it, and returns the 1340 // field. 1341 private static MethodHandle generateVCCUnboxBoxLoadIntMH() { 1342 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1343 "vccUnboxBoxLoadInt", 1344 MethodType.methodType(int.class, ValueCapableClass1.class), 1345 CODE -> { 1346 CODE. 1347 aload_0(). 1348 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1349 vbox(ValueCapableClass1.class). 1350 getfield(ValueCapableClass1.class, "x", "I"). 1351 ireturn(); 1352 } 1353 ); 1354 1355 } 1356 1357 // Test value type array creation and initialization 1358 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD)) 1359 @Test(valid = ValueTypeArrayFlattenOn) 1360 public MyValue1[] test41(int len) { 1361 MyValue1[] va = new MyValue1[len]; 1362 for (int i = 0; i < len; ++i) { 1363 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 1364 } 1365 return va; 1366 } 1367 1368 @DontCompile 1369 public void test41_verifier(boolean warmup) { 1370 int len = Math.abs(rI % 10); 1371 MyValue1[] va = test41(len); 1372 for (int i = 0; i < len; ++i) { 1373 Asserts.assertEQ(va[i].hash(), hash()); 1374 } 1375 } 1376 1377 // Test creation of a value type array and element access 1378 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOOP + TRAP)) 1379 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOC + ALLOCA + LOOP + LOAD + LOADP + STORE + TRAP)) 1380 public long test42() { 1381 MyValue1[] va = new MyValue1[1]; 1382 va[0] = MyValue1.createWithFieldsInline(rI, rL); 1383 return va[0].hash(); 1384 } 1385 1386 @DontCompile 1387 public void test42_verifier(boolean warmup) { 1388 long result = test42(); 1389 Asserts.assertEQ(result, hash()); 1390 } 1391 1392 // Test receiving a value type array from the interpreter, 1393 // updating its elements in a loop and computing a hash. 1394 @Test(failOn = (ALLOCA)) 1395 public long test43(MyValue1[] va) { 1396 long result = 0; 1397 for (int i = 0; i < 10; ++i) { 1398 result += va[i].hash(); 1399 va[i] = MyValue1.createWithFieldsInline(rI + 1, rL + 1); 1400 } 1401 return result; 1402 } 1403 1404 @DontCompile 1405 public void test43_verifier(boolean warmup) { 1406 MyValue1[] va = new MyValue1[10]; 1407 long expected = 0; 1408 for (int i = 0; i < 10; ++i) { 1409 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i); 1410 expected += va[i].hash(); 1411 } 1412 long result = test43(va); 1413 Asserts.assertEQ(expected, result); 1414 for (int i = 0; i < 10; ++i) { 1415 if (va[i].hash() != hash(rI + 1, rL + 1)) { 1416 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1)); 1417 } 1418 } 1419 } 1420 1421 // Test returning a value type array received from the interpreter 1422 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP) 1423 public MyValue1[] test44(MyValue1[] va) { 1424 return va; 1425 } 1426 1427 @DontCompile 1428 public void test44_verifier(boolean warmup) { 1429 MyValue1[] va = new MyValue1[10]; 1430 for (int i = 0; i < 10; ++i) { 1431 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i); 1432 } 1433 va = test44(va); 1434 for (int i = 0; i < 10; ++i) { 1435 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1436 } 1437 } 1438 1439 // Merge value type arrays created from two branches 1440 @Test(failOn = (TRAP)) 1441 public MyValue1[] test45(boolean b) { 1442 MyValue1[] va; 1443 if (b) { 1444 va = new MyValue1[5]; 1445 for (int i = 0; i < 5; ++i) { 1446 va[i] = MyValue1.createWithFieldsInline(rI, rL); 1447 } 1448 } else { 1449 va = new MyValue1[10]; 1450 for (int i = 0; i < 10; ++i) { 1451 va[i] = MyValue1.createWithFieldsInline(rI + i, rL + i); 1452 } 1453 } 1454 long sum = va[0].hashInterpreted(); 1455 if (b) { 1456 va[0] = MyValue1.createWithFieldsDontInline(rI, sum); 1457 } else { 1458 va[0] = MyValue1.createWithFieldsDontInline(rI + 1, sum + 1); 1459 } 1460 return va; 1461 } 1462 1463 @DontCompile 1464 public void test45_verifier(boolean warmup) { 1465 MyValue1[] va = test45(true); 1466 Asserts.assertEQ(va.length, 5); 1467 Asserts.assertEQ(va[0].hash(), hash(rI, hash())); 1468 for (int i = 1; i < 5; ++i) { 1469 Asserts.assertEQ(va[i].hash(), hash()); 1470 } 1471 va = test45(false); 1472 Asserts.assertEQ(va.length, 10); 1473 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1)); 1474 for (int i = 1; i < 10; ++i) { 1475 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1476 } 1477 } 1478 1479 // Test creation of value type array with single element 1480 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP)) 1481 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP)) 1482 public MyValue1 test46() { 1483 MyValue1[] va = new MyValue1[1]; 1484 return va[0]; 1485 } 1486 1487 @DontCompile 1488 public void test46_verifier(boolean warmup) { 1489 MyValue1[] va = new MyValue1[1]; 1490 MyValue1 v = test46(); 1491 Asserts.assertEQ(v.hashPrimitive(), va[0].hashPrimitive()); 1492 } 1493 1494 // Test default initialization of value type arrays 1495 @Test(failOn = LOAD) 1496 public MyValue1[] test47(int len) { 1497 return new MyValue1[len]; 1498 } 1499 1500 @DontCompile 1501 public void test47_verifier(boolean warmup) { 1502 int len = Math.abs(rI % 10); 1503 MyValue1[] va = new MyValue1[len]; 1504 MyValue1[] var = test47(len); 1505 for (int i = 0; i < len; ++i) { 1506 Asserts.assertEQ(va[i].hashPrimitive(), var[i].hashPrimitive()); 1507 } 1508 } 1509 1510 // Test creation of value type array with zero length 1511 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 1512 public MyValue1[] test48() { 1513 return new MyValue1[0]; 1514 } 1515 1516 @DontCompile 1517 public void test48_verifier(boolean warmup) { 1518 MyValue1[] va = test48(); 1519 Asserts.assertEQ(va.length, 0); 1520 } 1521 1522 static MyValue1[] test49_va; 1523 1524 // Test that value type array loaded from field has correct type 1525 @Test(failOn = (LOOP)) 1526 public long test49() { 1527 return test49_va[0].hash(); 1528 } 1529 1530 @DontCompile 1531 public void test49_verifier(boolean warmup) { 1532 test49_va = new MyValue1[1]; 1533 test49_va[0] = MyValue1.createWithFieldsInline(rI, rL); 1534 long result = test49(); 1535 Asserts.assertEQ(result, hash()); 1536 } 1537 1538 // test vdefault 1539 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1540 public long test50() { 1541 MyValue2 v = MyValue2.createDefaultInline(); 1542 return v.hash(); 1543 } 1544 1545 @DontCompile 1546 public void test50_verifier(boolean warmup) { 1547 long result = test50(); 1548 Asserts.assertEQ(result, MyValue2.createDefaultInline().hash()); 1549 } 1550 1551 // test vdefault 1552 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1553 public long test51() { 1554 MyValue1 v1 = MyValue1.createDefaultInline(); 1555 MyValue1 v2 = MyValue1.createDefaultDontInline(); 1556 return v1.hashPrimitive() + v2.hashPrimitive(); 1557 } 1558 1559 @DontCompile 1560 public void test51_verifier(boolean warmup) { 1561 long result = test51(); 1562 Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive()); 1563 } 1564 1565 // test vwithfield 1566 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1567 public long test52() { 1568 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1569 return v.hash(); 1570 } 1571 1572 @DontCompile 1573 public void test52_verifier(boolean warmup) { 1574 long result = test52(); 1575 Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash()); 1576 } 1577 1578 // test vwithfield 1579 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1580 public long test53() { 1581 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL); 1582 MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL); 1583 return v1.hash() + v2.hash(); 1584 } 1585 1586 @DontCompile 1587 public void test53_verifier(boolean warmup) { 1588 long result = test53(); 1589 Asserts.assertEQ(result, 2 * hash()); 1590 } 1591 1592 // multi-dimensional arrays 1593 @Test 1594 public MyValue1[][][] test54(int len1, int len2, int len3) { 1595 MyValue1[][][] arr = new MyValue1[len1][len2][len3]; 1596 for (int i = 0; i < len1; i++) { 1597 for (int j = 0; j < len2; j++) { 1598 for (int k = 0; k < len3; k++) { 1599 arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i , rL + j + k); 1600 } 1601 } 1602 } 1603 return arr; 1604 } 1605 1606 @DontCompile 1607 public void test54_verifier(boolean warmup) { 1608 MyValue1[][][] arr = test54(2, 3, 4); 1609 for (int i = 0; i < 2; i++) { 1610 for (int j = 0; j < 3; j++) { 1611 for (int k = 0; k < 4; k++) { 1612 Asserts.assertEQ(arr[i][j][k].hash(), MyValue1.createWithFieldsDontInline(rI + i , rL + j + k).hash()); 1613 } 1614 } 1615 } 1616 } 1617 1618 @Test 1619 public void test55(MyValue1[][][] arr, long[] res) { 1620 int l = 0; 1621 for (int i = 0; i < arr.length; i++) { 1622 for (int j = 0; j < arr[i].length; j++) { 1623 for (int k = 0; k < arr[i][j].length; k++) { 1624 res[l] = arr[i][j][k].hash(); 1625 l++; 1626 } 1627 } 1628 } 1629 } 1630 1631 @DontCompile 1632 public void test55_verifier(boolean warmup) { 1633 MyValue1[][][] arr = new MyValue1[2][3][4]; 1634 long[] res = new long[2*3*4]; 1635 long[] verif = new long[2*3*4]; 1636 int l = 0; 1637 for (int i = 0; i < 2; i++) { 1638 for (int j = 0; j < 3; j++) { 1639 for (int k = 0; k < 4; k++) { 1640 arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i, rL + j + k); 1641 verif[l] = arr[i][j][k].hash(); 1642 l++; 1643 } 1644 } 1645 } 1646 test55(arr, res); 1647 for (int i = 0; i < verif.length; i++) { 1648 Asserts.assertEQ(res[i], verif[i]); 1649 } 1650 } 1651 1652 class TestClass56 { 1653 public MyValue1 v; 1654 } 1655 1656 // Test allocation elimination of unused object with initialized value type field 1657 @Test(failOn = ALLOC + LOAD + STORE + LOOP) 1658 public void test56(boolean deopt) { 1659 TestClass56 unused = new TestClass56(); 1660 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 1661 unused.v = v; 1662 if (deopt) { 1663 // uncommon trap 1664 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test56")); 1665 } 1666 } 1667 1668 @DontCompile 1669 public void test56_verifier(boolean warmup) { 1670 test56(!warmup); 1671 } 1672 1673 // Test loop peeling 1674 @Test(failOn = ALLOC + LOAD + STORE) 1675 public void test57() { 1676 MyValue1 v = MyValue1.createWithFieldsInline(0, 1); 1677 // Trigger OSR compilation and loop peeling 1678 for (int i = 0; i < 100_000; ++i) { 1679 if (v.x != i || v.y != i + 1) { 1680 // Uncommon trap 1681 throw new RuntimeException("test57 failed"); 1682 } 1683 v = MyValue1.createWithFieldsInline(i + 1, i + 2); 1684 } 1685 } 1686 1687 @DontCompile 1688 public void test57_verifier(boolean warmup) { 1689 test57(); 1690 } 1691 1692 // Test loop peeling and unrolling 1693 @Test() 1694 public void test58() { 1695 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0); 1696 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1); 1697 // Trigger OSR compilation and loop peeling 1698 for (int i = 0; i < 100_000; ++i) { 1699 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) { 1700 // Uncommon trap 1701 throw new RuntimeException("test58 failed"); 1702 } 1703 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0); 1704 v2 = MyValue1.createWithFieldsInline(i+2, i+2); 1705 } 1706 } 1707 1708 @DontCompile 1709 public void test58_verifier(boolean warmup) { 1710 test58(); 1711 } 1712 1713 // When calling a method on __Value, passing fields as arguments is impossible 1714 @Test(failOn = ALLOC + STORE + LOAD) 1715 public String test59(MyValue1 v) { 1716 return v.toString(); 1717 } 1718 1719 @DontCompile 1720 public void test59_verifier(boolean warmup) { 1721 boolean failed = false; 1722 try { 1723 test59(val1); 1724 failed = true; 1725 } catch (UnsupportedOperationException uoe) { 1726 } 1727 Asserts.assertFalse(failed); 1728 } 1729 1730 // Same as above, but the method on __Value is inlined 1731 // hashCode allocates an exception so can't really check the graph shape 1732 @Test() 1733 public int test60(MyValue1 v) { 1734 return v.hashCode(); 1735 } 1736 1737 @DontCompile 1738 public void test60_verifier(boolean warmup) { 1739 boolean failed = false; 1740 try { 1741 test60(val1); 1742 failed = true; 1743 } catch (UnsupportedOperationException uoe) { 1744 } 1745 Asserts.assertFalse(failed); 1746 } 1747 1748 /* The compiler is supposed to determine that the value to be 1749 * unboxed in nullcvvUnboxLoadLong is always null. Therefore, the 1750 * compiler generates only the path leading to the corresponding 1751 * uncommon trap. */ 1752 @Test(failOn = RETURN) 1753 public long test61() throws Throwable { 1754 return (long)nullvccUnboxLoadLongMH.invokeExact(); 1755 } 1756 1757 @DontCompile 1758 public void test61_verifier(boolean warmup) throws Throwable { 1759 try { 1760 long result = test61(); 1761 throw new RuntimeException("Test failed because no exception was thrown"); 1762 } catch (NullPointerException e) { 1763 } 1764 } 1765 1766 public static MethodHandle generateNullVCCUnboxLoadLongMH() { 1767 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1768 "nullvccUnboxLoadLong", 1769 MethodType.methodType(long.class), 1770 CODE -> { 1771 CODE. 1772 aconst_null(). 1773 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1774 vgetfield(ValueCapableClass1.class, "t", "J"). 1775 lreturn(); 1776 } 1777 ); 1778 } 1779 1780 /* The compiler is supposed to determine that the allocated 1781 * ValueCapableClass1 instance is never null (and therefore not 1782 * generate a null check). Also, the source and target type match 1783 * (known at compile time), so no type check is needed either.*/ 1784 @Test(failOn = NPE) 1785 public long test62() throws Throwable { 1786 return (long)checkedvccUnboxLoadLongMH.invokeExact(); 1787 } 1788 1789 @DontCompile 1790 public void test62_verifier(boolean warmup) throws Throwable { 1791 long result = test62(); 1792 Asserts.assertEQ(result, 17L); 1793 } 1794 1795 public static MethodHandle generateCheckedVCCUnboxLoadLongMH() { 1796 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1797 "checkedVCCUnboxLoadLongMH", 1798 MethodType.methodType(long.class), 1799 CODE -> { 1800 CODE. 1801 invokestatic(ValueCapableClass1.class, "createInline", "()Lcompiler/valhalla/valuetypes/ValueCapableClass1;", false). 1802 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1803 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1804 lreturn(); 1805 } 1806 ); 1807 } 1808 1809 /* The compiler is supposed to emit a runtime null check because 1810 * it does not have enough information to determine that the value 1811 * to be unboxed is not null (and either that it is null). The 1812 * declared type of the */ 1813 @Test(match = {NPE}, matchCount = {1}) 1814 public long test63(ValueCapableClass1 vcc) throws Throwable { 1815 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 1816 } 1817 1818 @DontCompile 1819 public void test63_verifier(boolean warmup) throws Throwable { 1820 try { 1821 long result = test63(null); 1822 throw new RuntimeException("Test failed because no exception was thrown"); 1823 } catch (NullPointerException e) { 1824 } 1825 } 1826 1827 /* Attempt to unbox an object that is not a subclass of the 1828 * value-capable class derived from the value type specified in 1829 * the vunbox bytecode. */ 1830 @Test(match = {NPE,CCE}, matchCount = {1,1}) 1831 public long test64(Object vcc) throws Throwable { 1832 return (long)objectUnboxLoadLongMH.invokeExact(vcc); 1833 } 1834 1835 @DontCompile 1836 public void test64_verifier(boolean warmup) throws Throwable { 1837 try { 1838 long result = test64(new Object()); 1839 throw new RuntimeException("Test failed because no exception was thrown"); 1840 } catch (ClassCastException e) { 1841 } 1842 1843 try { 1844 long result = test64(vcc2); 1845 throw new RuntimeException("Test failed because no exception was thrown"); 1846 } catch (ClassCastException e) { 1847 } 1848 1849 Asserts.assertEQ(test64(vcc), rL); 1850 } 1851 1852 private static MethodHandle generateObjectUnboxLoadLongMH() { 1853 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1854 "ObjectUnboxLoadLong", 1855 MethodType.methodType(long.class, Object.class), 1856 CODE -> { 1857 CODE. 1858 aload_0(). 1859 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1860 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1861 lreturn(); 1862 } 1863 ); 1864 } 1865 1866 /* Generate an if-then-else construct with one path that contains 1867 * an invalid boxing operation (boxing of a value-type to a 1868 * non-matching value-capable class).*/ 1869 @Test(match = {NPE, CCE}, matchCount = {2, 2}) 1870 public long test65(Object obj, boolean warmup) throws Throwable { 1871 return (long)objectBoxMH.invokeExact(obj, warmup); 1872 } 1873 1874 @DontCompile 1875 public void test65_verifier(boolean warmup) throws Throwable { 1876 try { 1877 long result = test65(vcc2, true); 1878 throw new RuntimeException("Test failed because no exception was thrown"); 1879 } catch (ClassCastException e) { 1880 } 1881 1882 Asserts.assertEQ(test65(vcc, true), rL); 1883 1884 try { 1885 long result = test65(vcc2, false); 1886 throw new RuntimeException("Test failed because no exception was thrown"); 1887 } catch (ClassCastException e) { 1888 } 1889 1890 try { 1891 long result = test65(vcc, false); 1892 throw new RuntimeException("Test failed because no exception was thrown"); 1893 } catch (ClassCastException e) { 1894 } 1895 } 1896 1897 private static MethodHandle generateObjectBoxMH() { 1898 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1899 "ObjectBox", 1900 MethodType.methodType(long.class, Object.class, boolean.class), 1901 CODE -> { 1902 CODE. 1903 iload_1(). 1904 iconst_1(). 1905 if_icmpne((short)14). 1906 aload_0(). 1907 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1908 vbox(ValueCapableClass1.class). 1909 getfield(ValueCapableClass1.class, "t", "J"). 1910 lreturn(). 1911 aload_0(). 1912 vunbox(ValueType.forClass(ValueCapableClass2.class).valueClass()). 1913 vbox(ValueCapableClass1.class). 1914 getfield(ValueCapableClass1.class, "t", "J"). 1915 lreturn(); 1916 } 1917 ); 1918 } 1919 1920 // Test deoptimization at call return with return value in registers 1921 @DontCompile 1922 public MyValue2 test66_interp(boolean deopt) { 1923 if (deopt) { 1924 // uncommon trap 1925 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test66")); 1926 } 1927 return MyValue2.createWithFieldsInline(rI, true); 1928 } 1929 1930 @Test() 1931 public MyValue2 test66(boolean flag) { 1932 return test66_interp(flag); 1933 } 1934 1935 @DontCompile 1936 public void test66_verifier(boolean warmup) { 1937 MyValue2 result = test66(!warmup); 1938 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1939 Asserts.assertEQ(result.hash(), v.hash()); 1940 } 1941 1942 // Return value types in registers from interpreter -> compiled 1943 final MyValue3 test67_vt = MyValue3.create(); 1944 @DontCompile 1945 public MyValue3 test67_interp() { 1946 return test67_vt; 1947 } 1948 1949 MyValue3 test67_vt2; 1950 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP) 1951 @Test(valid = ValueTypeReturnedAsFieldsOff) 1952 public void test67() { 1953 test67_vt2 = test67_interp(); 1954 } 1955 1956 @DontCompile 1957 public void test67_verifier(boolean warmup) { 1958 test67(); 1959 test67_vt.verify(test67_vt2); 1960 } 1961 1962 // Return value types in registers from compiled -> interpreter 1963 final MyValue3 test68_vt = MyValue3.create(); 1964 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + TRAP) 1965 @Test(valid = ValueTypeReturnedAsFieldsOff) 1966 public MyValue3 test68() { 1967 return test68_vt; 1968 } 1969 1970 @DontCompile 1971 public void test68_verifier(boolean warmup) { 1972 MyValue3 vt = test68(); 1973 test68_vt.verify(vt); 1974 } 1975 1976 // Return value types in registers from compiled -> compiled 1977 final MyValue3 test69_vt = MyValue3.create(); 1978 @DontInline 1979 public MyValue3 test69_comp() { 1980 return test69_vt; 1981 } 1982 1983 MyValue3 test69_vt2; 1984 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP) 1985 @Test(valid = ValueTypeReturnedAsFieldsOff) 1986 public void test69() { 1987 test69_vt2 = test69_comp(); 1988 } 1989 1990 @DontCompile 1991 public void test69_verifier(boolean warmup) throws Exception { 1992 Method helper_m = getClass().getDeclaredMethod("test69_comp"); 1993 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 1994 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 1995 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test69_comp not compiled"); 1996 } 1997 test69(); 1998 test69_vt.verify(test69_vt2); 1999 } 2000 2001 // Same tests as above but with a value type that cannot be returned in registers 2002 2003 // Return value types in registers from interpreter -> compiled 2004 final MyValue4 test70_vt = MyValue4.create(); 2005 @DontCompile 2006 public MyValue4 test70_interp() { 2007 return test70_vt; 2008 } 2009 2010 MyValue4 test70_vt2; 2011 @Test 2012 public void test70() { 2013 test70_vt2 = test70_interp(); 2014 } 2015 2016 @DontCompile 2017 public void test70_verifier(boolean warmup) { 2018 test70(); 2019 test70_vt.verify(test70_vt2); 2020 } 2021 2022 // Return value types in registers from compiled -> interpreter 2023 final MyValue4 test71_vt = MyValue4.create(); 2024 @Test 2025 public MyValue4 test71() { 2026 return test71_vt; 2027 } 2028 2029 @DontCompile 2030 public void test71_verifier(boolean warmup) { 2031 MyValue4 vt = test71(); 2032 test71_vt.verify(vt); 2033 } 2034 2035 // Return value types in registers from compiled -> compiled 2036 final MyValue4 test72_vt = MyValue4.create(); 2037 @DontInline 2038 public MyValue4 test72_comp() { 2039 return test72_vt; 2040 } 2041 2042 MyValue4 test72_vt2; 2043 @Test 2044 public void test72() { 2045 test72_vt2 = test72_comp(); 2046 } 2047 2048 @DontCompile 2049 public void test72_verifier(boolean warmup) throws Exception { 2050 Method helper_m = getClass().getDeclaredMethod("test72_comp"); 2051 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 2052 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 2053 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test72_comp not compiled"); 2054 } 2055 test72(); 2056 test72_vt.verify(test72_vt2); 2057 } 2058 2059 // Return values and method handles tests 2060 2061 // Everything inlined 2062 final MyValue3 test73_vt = MyValue3.create(); 2063 @ForceInline 2064 MyValue3 test73_target() { 2065 return test73_vt; 2066 } 2067 2068 static final MethodHandle test73_mh; 2069 2070 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + CALL) 2071 @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 11 }) 2072 MyValue3 test73() throws Throwable { 2073 return (MyValue3)test73_mh.invokeExact(this); 2074 } 2075 2076 @DontCompile 2077 public void test73_verifier(boolean warmup) throws Throwable { 2078 MyValue3 vt = test73(); 2079 test73_vt.verify(vt); 2080 } 2081 2082 // Leaf method not inlined but returned type is known 2083 final MyValue3 test74_vt = MyValue3.create(); 2084 @DontInline 2085 MyValue3 test74_target() { 2086 return test74_vt; 2087 } 2088 2089 static final MethodHandle test74_mh; 2090 2091 @Test 2092 MyValue3 test74() throws Throwable { 2093 return (MyValue3)test74_mh.invokeExact(this); 2094 } 2095 2096 @DontCompile 2097 public void test74_verifier(boolean warmup) throws Throwable { 2098 Method helper_m = getClass().getDeclaredMethod("test74_target"); 2099 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 2100 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 2101 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test74_target not compiled"); 2102 } 2103 MyValue3 vt = test74(); 2104 test74_vt.verify(vt); 2105 } 2106 2107 // Leaf method not inlined and returned type not known 2108 final MyValue3 test75_vt = MyValue3.create(); 2109 @DontInline 2110 MyValue3 test75_target() { 2111 return test75_vt; 2112 } 2113 2114 static final MethodHandle test75_mh; 2115 2116 @Test 2117 MyValue3 test75() throws Throwable { 2118 return (MyValue3)test75_mh.invokeExact(this); 2119 } 2120 2121 @DontCompile 2122 public void test75_verifier(boolean warmup) throws Throwable { 2123 // hack so C2 doesn't know the target of the invoke call 2124 Class c = Class.forName("java.lang.invoke.DirectMethodHandle"); 2125 Method m = c.getDeclaredMethod("internalMemberName", Object.class); 2126 WHITE_BOX.testSetDontInlineMethod(m, warmup); 2127 MyValue3 vt = test75(); 2128 test75_vt.verify(vt); 2129 } 2130 2131 // Test no result from inlined method for incremental inlining 2132 final MyValue3 test76_vt = MyValue3.create(); 2133 public MyValue3 test76_inlined() { 2134 throw new RuntimeException(); 2135 } 2136 2137 @Test 2138 public MyValue3 test76() { 2139 try { 2140 return test76_inlined(); 2141 } catch (RuntimeException ex) { 2142 return test76_vt; 2143 } 2144 } 2145 2146 @DontCompile 2147 public void test76_verifier(boolean warmup) throws Exception { 2148 MyValue3 vt = test76(); 2149 test76_vt.verify(vt); 2150 } 2151 2152 static { 2153 try { 2154 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2155 MethodType mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue3;", ValueTypeTestBench.class.getClassLoader()); 2156 test73_mh = lookup.findVirtual(ValueTypeTestBench.class, "test73_target", mt); 2157 test74_mh = lookup.findVirtual(ValueTypeTestBench.class, "test74_target", mt); 2158 test75_mh = lookup.findVirtual(ValueTypeTestBench.class, "test75_target", mt); 2159 } catch (NoSuchMethodException|IllegalAccessException e) { 2160 throw new RuntimeException("method handle lookup fails"); 2161 } 2162 } 2163 2164 // ========== Test infrastructure ========== 2165 2166 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 2167 private static final int ValueTypePassFieldsAsArgsOn = 0x1; 2168 private static final int ValueTypePassFieldsAsArgsOff = 0x2; 2169 private static final int ValueTypeArrayFlattenOn = 0x4; 2170 private static final int ValueTypeArrayFlattenOff = 0x8; 2171 private static final int ValueTypeReturnedAsFieldsOn = 0x10; 2172 private static final int ValueTypeReturnedAsFieldsOff = 0x20; 2173 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn; 2174 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 2175 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten"); 2176 private static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields"); 2177 private static final int COMP_LEVEL_ANY = -1; 2178 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 2179 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 2180 private static final int WARMUP = 251; 2181 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 2182 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 2183 private static boolean XCOMP = Platform.isComp(); 2184 2185 // Regular expressions used to match nodes in the PrintIdeal output 2186 private static final String START = "(\\d+\\t(.*"; 2187 private static final String MID = ".*)+\\t===.*"; 2188 private static final String END = ")|"; 2189 private static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END; 2190 private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END; 2191 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 2192 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END; 2193 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 2194 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END; 2195 private static final String LOOP = START + "Loop" + MID + "" + END; 2196 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END; 2197 private static final String RETURN = START + "Return" + MID + "returns" + END; 2198 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END; 2199 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END; 2200 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END; 2201 private static final String CALL = START + "CallStaticJava" + MID + END; 2202 private static final String SCOBJ = "(.*# ScObj.*" + END; 2203 2204 static { 2205 // Gather all test methods and put them in Hashtable 2206 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) { 2207 Test[] annos = m.getAnnotationsByType(Test.class); 2208 if (annos.length != 0) { 2209 tests.put("ValueTypeTestBench::" + m.getName(), m); 2210 } 2211 } 2212 } 2213 2214 private static void execute_vm(String... args) throws Throwable { 2215 Asserts.assertFalse(tests.isEmpty(), "no tests to execute"); 2216 ArrayList<String> all_args = new ArrayList(List.of(args)); 2217 // Run tests in own process and verify output 2218 all_args.add(ValueTypeTestBench.class.getName()); 2219 all_args.add("run"); 2220 // Spawn process with default JVM options from the test's run command 2221 String[] vmInputArgs = InputArguments.getVmInputArgs(); 2222 String[] cmds = Arrays.copyOf(vmInputArgs, vmInputArgs.length + all_args.size()); 2223 System.arraycopy(all_args.toArray(), 0, cmds, vmInputArgs.length, all_args.size()); 2224 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); 2225 // If ideal graph printing is enabled/supported, verify output 2226 String output = oa.getOutput(); 2227 oa.shouldHaveExitValue(0); 2228 boolean verifyIR = output.contains("PrintIdeal enabled") && 2229 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform"); 2230 if (verifyIR) { 2231 parseOutput(output); 2232 } else { 2233 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); 2234 } 2235 } 2236 2237 public static void main(String[] args) throws Throwable { 2238 //tests.values().removeIf(p -> !p.getName().equals("test74")); // Run single test 2239 if (args.length == 0) { 2240 execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation", 2241 "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly", 2242 "-XX:CICompilerCount=1", 2243 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*", 2244 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", 2245 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*", 2246 "-XX:CompileCommand=compileonly,java.lang.Object::<init>", 2247 "-XX:CompileCommand=inline,java.lang.__Value::hashCode", 2248 "-XX:CompileCommand=compileonly,java.lang.invoke.*::*"); 2249 } else { 2250 // Execute tests 2251 ValueTypeTestBench bench = new ValueTypeTestBench(); 2252 bench.run(); 2253 } 2254 } 2255 2256 public static void parseOutput(String output) throws Exception { 2257 Pattern comp_re = Pattern.compile("\\n\\s+\\d+\\s+\\d+\\s+(%| )(s| )(!| )b(n| )\\s+\\S+\\.(?<name>[^.]+::\\S+)\\s+(?<osr>@ \\d+\\s+)?[(]\\d+ bytes[)]\\n"); 2258 Matcher m = comp_re.matcher(output); 2259 Map<String,String> compilations = new LinkedHashMap<>(); 2260 int prev = 0; 2261 String methodName = null; 2262 while (m.find()) { 2263 if (prev == 0) { 2264 // Print header 2265 System.out.print(output.substring(0, m.start()+1)); 2266 } else if (methodName != null) { 2267 compilations.put(methodName, output.substring(prev, m.start()+1)); 2268 } 2269 if (m.group("osr") != null) { 2270 methodName = null; 2271 } else { 2272 methodName = m.group("name"); 2273 } 2274 prev = m.end(); 2275 } 2276 if (prev == 0) { 2277 // Print header 2278 System.out.print(output); 2279 } else if (methodName != null) { 2280 compilations.put(methodName, output.substring(prev)); 2281 } 2282 // Iterate over compilation output 2283 for (String testName : compilations.keySet()) { 2284 Method test = tests.get(testName); 2285 if (test == null) { 2286 // Skip helper methods 2287 continue; 2288 } 2289 String graph = compilations.get(testName); 2290 if (PRINT_GRAPH) { 2291 System.out.println("\nGraph for " + testName + "\n" + graph); 2292 } 2293 // Parse graph using regular expressions to determine if it contains forbidden nodes 2294 Test[] annos = test.getAnnotationsByType(Test.class); 2295 Test anno = null; 2296 for (Test a : annos) { 2297 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 2298 assert anno == null; 2299 anno = a; 2300 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 2301 assert anno == null; 2302 anno = a; 2303 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 2304 assert anno == null; 2305 anno = a; 2306 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 2307 assert anno == null; 2308 anno = a; 2309 } else if ((a.valid() & ValueTypeReturnedAsFieldsOn) != 0 && ValueTypeReturnedAsFields) { 2310 assert anno == null; 2311 anno = a; 2312 } else if ((a.valid() & ValueTypeReturnedAsFieldsOff) != 0 && !ValueTypeReturnedAsFields) { 2313 assert anno == null; 2314 anno = a; 2315 } 2316 } 2317 assert anno != null; 2318 String regexFail = anno.failOn(); 2319 if (!regexFail.isEmpty()) { 2320 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 2321 Matcher matcher = pattern.matcher(graph); 2322 boolean found = matcher.find(); 2323 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 2324 } 2325 String[] regexMatch = anno.match(); 2326 int[] matchCount = anno.matchCount(); 2327 for (int i = 0; i < regexMatch.length; ++i) { 2328 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 2329 Matcher matcher = pattern.matcher(graph); 2330 int count = 0; 2331 String nodes = ""; 2332 while (matcher.find()) { 2333 count++; 2334 nodes += matcher.group() + "\n"; 2335 } 2336 if (matchCount[i] < 0) { 2337 Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 2338 } else { 2339 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 2340 } 2341 } 2342 tests.remove(testName); 2343 System.out.println(testName + " passed"); 2344 } 2345 // Check if all tests were compiled 2346 if (tests.size() != 0) { 2347 for (String name : tests.keySet()) { 2348 System.out.println("Test '" + name + "' not compiled!"); 2349 } 2350 throw new RuntimeException("Not all tests were compiled"); 2351 } 2352 } 2353 2354 public void setup(Method[] methods) { 2355 if (XCOMP) { 2356 // Don't control compilation if -Xcomp is enabled 2357 return; 2358 } 2359 for (Method m : methods) { 2360 if (m.isAnnotationPresent(Test.class)) { 2361 // Don't inline tests 2362 WHITE_BOX.testSetDontInlineMethod(m, true); 2363 } 2364 if (m.isAnnotationPresent(DontCompile.class)) { 2365 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 2366 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 2367 WHITE_BOX.testSetDontInlineMethod(m, true); 2368 } 2369 if (m.isAnnotationPresent(ForceInline.class)) { 2370 WHITE_BOX.testSetForceInlineMethod(m, true); 2371 } else if (m.isAnnotationPresent(DontInline.class)) { 2372 WHITE_BOX.testSetDontInlineMethod(m, true); 2373 } 2374 } 2375 } 2376 2377 public void run() throws Exception { 2378 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 2379 System.out.println("PrintIdeal enabled"); 2380 } 2381 System.out.format("rI = %d, rL = %d\n", rI, rL); 2382 setup(this.getClass().getDeclaredMethods()); 2383 setup(MyValue1.class.getDeclaredMethods()); 2384 setup(MyValue2.class.getDeclaredMethods()); 2385 2386 // Compile class initializers 2387 WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION); 2388 WHITE_BOX.enqueueInitializerForCompilation(MyValue1.class, COMP_LEVEL_FULL_OPTIMIZATION); 2389 WHITE_BOX.enqueueInitializerForCompilation(MyValue2.class, COMP_LEVEL_FULL_OPTIMIZATION); 2390 2391 // Execute tests 2392 for (Method test : tests.values()) { 2393 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class); 2394 // Warmup using verifier method 2395 for (int i = 0; i < WARMUP; ++i) { 2396 verifier.invoke(this, true); 2397 } 2398 // Trigger compilation 2399 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION); 2400 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 2401 // Check result 2402 verifier.invoke(this, false); 2403 } 2404 } 2405 } 2406 2407 // Mark method as test 2408 @Retention(RetentionPolicy.RUNTIME) 2409 @Repeatable(Tests.class) 2410 @interface Test { 2411 // Regular expression used to match forbidden IR nodes 2412 // in the C2 IR emitted for this test. 2413 String failOn() default ""; 2414 // Regular expressions used to match and count IR nodes. 2415 String[] match() default { }; 2416 int[] matchCount() default { }; 2417 int valid() default ValueTypeTestBench.AllFlags; 2418 } 2419 2420 @Retention(RetentionPolicy.RUNTIME) 2421 @interface Tests { 2422 Test[] value(); 2423 } 2424 2425 // Force method inlining during compilation 2426 @Retention(RetentionPolicy.RUNTIME) 2427 @interface ForceInline { } 2428 2429 // Prevent method inlining during compilation 2430 @Retention(RetentionPolicy.RUNTIME) 2431 @interface DontInline { } 2432 2433 // Prevent method compilation 2434 @Retention(RetentionPolicy.RUNTIME) 2435 @interface DontCompile { }