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 -XX:+VerifyStack 36 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten 37 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1 38 * -Djdk.lang.reflect.DVT=true 39 * compiler.valhalla.valuetypes.ValueTypeTestBench 40 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 41 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+VerifyStack 42 * -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten 43 * -Djdk.lang.reflect.DVT=true 44 * compiler.valhalla.valuetypes.ValueTypeTestBench 45 * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 46 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline 47 * -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten 48 * -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1 49 * -Djdk.lang.reflect.DVT=true 50 * compiler.valhalla.valuetypes.ValueTypeTestBench 51 */ 52 53 package compiler.valhalla.valuetypes; 54 55 import compiler.whitebox.CompilerWhiteBoxTest; 56 import jdk.internal.misc.Unsafe; 57 import jdk.test.lib.Asserts; 58 import jdk.test.lib.management.InputArguments; 59 import jdk.test.lib.Platform; 60 import jdk.test.lib.process.ProcessTools; 61 import jdk.test.lib.process.OutputAnalyzer; 62 import jdk.test.lib.Utils; 63 import sun.hotspot.WhiteBox; 64 65 import java.lang.annotation.Retention; 66 import java.lang.annotation.RetentionPolicy; 67 import java.lang.annotation.Repeatable; 68 import java.lang.invoke.*; 69 import java.lang.reflect.Method; 70 import java.util.ArrayList; 71 import java.util.Arrays; 72 import java.util.Hashtable; 73 import java.util.LinkedHashMap; 74 import java.util.List; 75 import java.util.Map; 76 import java.util.regex.Matcher; 77 import java.util.regex.Pattern; 78 import jdk.experimental.value.*; 79 80 // Test value types 81 __ByValue final class MyValue1 { 82 static int s; 83 static final long sf = ValueTypeTestBench.rL; 84 final int x; 85 final long y; 86 final short z; 87 final Integer o; 88 final int[] oa; 89 final MyValue2 v1; 90 final MyValue2 v2; 91 static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true); 92 final int c; 93 94 private MyValue1() { 95 s = 0; 96 this.x = 0; 97 this.y = 0; 98 this.z = 0; 99 this.o = null; 100 this.oa = null; 101 this.v1 = MyValue2.createDefaultInline(); 102 this.v2 = MyValue2.createDefaultInline(); 103 this.c = 0; 104 } 105 106 @DontInline 107 __ValueFactory static MyValue1 createDefaultDontInline() { 108 return createDefaultInline(); 109 } 110 111 @ForceInline 112 __ValueFactory static MyValue1 createDefaultInline() { 113 return __MakeDefault MyValue1(); 114 } 115 116 @DontInline 117 static MyValue1 createWithFieldsDontInline(int x, long y) { 118 return createWithFieldsInline(x, y); 119 } 120 121 @ForceInline 122 static MyValue1 createWithFieldsInline(int x, long y) { 123 MyValue1 v = createDefaultInline(); 124 v = setX(v, x); 125 v = setY(v, y); 126 v = setZ(v, (short)x); 127 v = setO(v, new Integer(x)); 128 int[] oa = {x}; 129 v = setOA(v, oa); 130 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y)); 131 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y)); 132 v = setC(v, ValueTypeTestBench.rI); 133 return v; 134 } 135 136 // Hash only primitive and value type fields to avoid NullPointerException 137 @ForceInline 138 public long hashPrimitive() { 139 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash(); 140 } 141 142 @ForceInline 143 public long hash() { 144 return hashPrimitive() + o + oa[0]; 145 } 146 147 @DontCompile 148 public long hashInterpreted() { 149 return s + sf + x + y + z + o + oa[0] + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted(); 150 } 151 152 @ForceInline 153 public void print() { 154 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", o=" + (o != null ? (Integer)o : "NULL") + ", v1["); 155 v1.print(); 156 System.out.print("], v2["); 157 v2.print(); 158 System.out.print("], v3["); 159 v3.print(); 160 System.out.print("], c=" + c); 161 } 162 163 @ForceInline 164 __ValueFactory static MyValue1 setX(MyValue1 v, int x) { 165 v.x = x; 166 return v; 167 } 168 169 @ForceInline 170 __ValueFactory static MyValue1 setY(MyValue1 v, long y) { 171 v.y = y; 172 return v; 173 } 174 175 @ForceInline 176 __ValueFactory static MyValue1 setZ(MyValue1 v, short z) { 177 v.z = z; 178 return v; 179 } 180 181 @ForceInline 182 __ValueFactory static MyValue1 setO(MyValue1 v, Integer o) { 183 v.o = o; 184 return v; 185 } 186 187 @ForceInline 188 __ValueFactory static MyValue1 setOA(MyValue1 v, int[] oa) { 189 v.oa = oa; 190 return v; 191 } 192 193 @ForceInline 194 __ValueFactory static MyValue1 setC(MyValue1 v, int c) { 195 v.c = c; 196 return v; 197 } 198 199 @ForceInline 200 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) { 201 v.v1 = v1; 202 return v; 203 } 204 205 @ForceInline 206 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) { 207 v.v2 = v2; 208 return v; 209 } 210 } 211 212 __ByValue final class MyValue2 { 213 final int x; 214 final byte y; 215 final boolean b; 216 final long c; 217 218 private MyValue2() { 219 this.x = 0; 220 this.y = 0; 221 this.b = false; 222 this.c = 0; 223 } 224 225 @ForceInline 226 __ValueFactory public static MyValue2 createDefaultInline() { 227 return __MakeDefault MyValue2(); 228 } 229 230 @ForceInline 231 public static MyValue2 createWithFieldsInline(int x, boolean b) { 232 MyValue2 v = createDefaultInline(); 233 v = setX(v, x); 234 v = setY(v, (byte)x); 235 v = setB(v, b); 236 v = setC(v, ValueTypeTestBench.rL); 237 return v; 238 } 239 240 @ForceInline 241 public long hash() { 242 return x + y + (b ? 0 : 1) + c; 243 } 244 245 @DontInline 246 public long hashInterpreted() { 247 return x + y + (b ? 0 : 1) + c; 248 } 249 250 @ForceInline 251 public void print() { 252 System.out.print("x=" + x + "y=" + y + ", b=" + b + ", c=" + c); 253 } 254 255 @ForceInline 256 __ValueFactory static MyValue2 setX(MyValue2 v, int x) { 257 v.x = x; 258 return v; 259 } 260 261 @ForceInline 262 __ValueFactory static MyValue2 setY(MyValue2 v, byte y) { 263 v.y = y; 264 return v; 265 } 266 267 @ForceInline 268 __ValueFactory static MyValue2 setC(MyValue2 v, long c) { 269 v.c = c; 270 return v; 271 } 272 273 @ForceInline 274 __ValueFactory static MyValue2 setB(MyValue2 v, boolean b) { 275 v.b = b; 276 return v; 277 } 278 } 279 280 // Value type definition to stress test return of a value in registers 281 // (uses all registers of calling convention on x86_64) 282 __ByValue final class MyValue3 { 283 final char c; 284 final byte bb; 285 final short s; 286 final int i; 287 final long l; 288 final Object o; 289 final float f1; 290 final double f2; 291 final float f3; 292 final double f4; 293 final float f5; 294 final double f6; 295 final float f7; 296 final double f8; 297 298 private MyValue3(char c, 299 byte bb, 300 short s, 301 int i, 302 long l, 303 Object o, 304 float f1, 305 double f2, 306 float f3, 307 double f4, 308 float f5, 309 double f6, 310 float f7, 311 double f8) { 312 this.c = c; 313 this.bb = bb; 314 this.s = s; 315 this.i = i; 316 this.l = l; 317 this.o = o; 318 this.f1 = f1; 319 this.f2 = f2; 320 this.f3 = f3; 321 this.f4 = f4; 322 this.f5 = f5; 323 this.f6 = f6; 324 this.f7 = f7; 325 this.f8 = f8; 326 } 327 328 private MyValue3() { 329 this.c = 0; 330 this.bb = 0; 331 this.s = 0; 332 this.i = 0; 333 this.l = 0; 334 this.o = null; 335 this.f1 = 0; 336 this.f2 = 0; 337 this.f3 = 0; 338 this.f4 = 0; 339 this.f5 = 0; 340 this.f6 = 0; 341 this.f7 = 0; 342 this.f8 = 0; 343 } 344 345 @ForceInline 346 __ValueFactory static MyValue3 setC(MyValue3 v, char c) { 347 v.c = c; 348 return v; 349 } 350 351 @ForceInline 352 __ValueFactory static MyValue3 setBB(MyValue3 v, byte bb) { 353 v.bb = bb; 354 return v; 355 } 356 357 @ForceInline 358 __ValueFactory static MyValue3 setS(MyValue3 v, short s) { 359 v.s = s; 360 return v; 361 } 362 363 @ForceInline 364 __ValueFactory static MyValue3 setI(MyValue3 v, int i) { 365 v.i = i; 366 return v; 367 } 368 369 @ForceInline 370 __ValueFactory static MyValue3 setL(MyValue3 v, long l) { 371 v.l = l; 372 return v; 373 } 374 375 @ForceInline 376 __ValueFactory static MyValue3 setO(MyValue3 v, Object o) { 377 v.o = o; 378 return v; 379 } 380 381 @ForceInline 382 __ValueFactory static MyValue3 setF1(MyValue3 v, float f1) { 383 v.f1 = f1; 384 return v; 385 } 386 387 @ForceInline 388 __ValueFactory static MyValue3 setF2(MyValue3 v, double f2) { 389 v.f2 = f2; 390 return v; 391 } 392 393 @ForceInline 394 __ValueFactory static MyValue3 setF3(MyValue3 v, float f3) { 395 v.f3 = f3; 396 return v; 397 } 398 399 @ForceInline 400 __ValueFactory static MyValue3 setF4(MyValue3 v, double f4) { 401 v.f4 = f4; 402 return v; 403 } 404 405 @ForceInline 406 __ValueFactory static MyValue3 setF5(MyValue3 v, float f5) { 407 v.f5 = f5; 408 return v; 409 } 410 411 @ForceInline 412 __ValueFactory static MyValue3 setF6(MyValue3 v, double f6) { 413 v.f6 = f6; 414 return v; 415 } 416 417 @ForceInline 418 __ValueFactory static MyValue3 setF7(MyValue3 v, float f7) { 419 v.f7 = f7; 420 return v; 421 } 422 423 @ForceInline 424 __ValueFactory static MyValue3 setF8(MyValue3 v, double f8) { 425 v.f8 = f8; 426 return v; 427 } 428 429 @ForceInline 430 __ValueFactory public static MyValue3 createDefault() { 431 return __MakeDefault MyValue3(); 432 } 433 434 @ForceInline 435 public static MyValue3 create() { 436 java.util.Random r = Utils.getRandomInstance(); 437 MyValue3 v = createDefault(); 438 v = setC(v, (char)r.nextInt()); 439 v = setBB(v, (byte)r.nextInt()); 440 v = setS(v, (short)r.nextInt()); 441 v = setI(v, r.nextInt()); 442 v = setL(v, r.nextLong()); 443 v = setO(v, new Object()); 444 v = setF1(v, r.nextFloat()); 445 v = setF2(v, r.nextDouble()); 446 v = setF3(v, r.nextFloat()); 447 v = setF4(v, r.nextDouble()); 448 v = setF5(v, r.nextFloat()); 449 v = setF6(v, r.nextDouble()); 450 v = setF7(v, r.nextFloat()); 451 v = setF8(v, r.nextDouble()); 452 return v; 453 } 454 455 @DontInline 456 public static MyValue3 createDontInline() { 457 return create(); 458 } 459 460 @ForceInline 461 public static MyValue3 copy(MyValue3 other) { 462 MyValue3 v = createDefault(); 463 v = setC(v, other.c); 464 v = setBB(v, other.bb); 465 v = setS(v, other.s); 466 v = setI(v, other.i); 467 v = setL(v, other.l); 468 v = setO(v, other.o); 469 v = setF1(v, other.f1); 470 v = setF2(v, other.f2); 471 v = setF3(v, other.f3); 472 v = setF4(v, other.f4); 473 v = setF5(v, other.f5); 474 v = setF6(v, other.f6); 475 v = setF7(v, other.f7); 476 v = setF8(v, other.f8); 477 return v; 478 } 479 480 @DontInline 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 private static final MethodHandle vastoreMH = generateVastore(); 570 private static final MethodHandle invalidVastoreMH = generateInvalidVastore(); 571 572 private static final ValueCapableClass1 vcc = ValueCapableClass1.create(rL, rI, (short)rI, (short)rI); 573 private static final ValueCapableClass2 vcc2 = ValueCapableClass2.create(rL + 1); 574 575 // ========== Helper methods ========== 576 577 public long hash() { 578 return hash(rI, rL); 579 } 580 581 public long hash(int x, long y) { 582 return MyValue1.createWithFieldsInline(x, y).hash(); 583 } 584 585 // ========== Test definitions ========== 586 587 // Receive value type through call to interpreter 588 @Test(failOn = ALLOC + STORE + TRAP) 589 public long test1() { 590 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 591 return v.hash(); 592 } 593 594 @DontCompile 595 public void test1_verifier(boolean warmup) { 596 long result = test1(); 597 Asserts.assertEQ(result, hash()); 598 } 599 600 // Receive value type from interpreter via parameter 601 @Test(failOn = ALLOC + STORE + TRAP) 602 public long test2(MyValue1 v) { 603 return v.hash(); 604 } 605 606 @DontCompile 607 public void test2_verifier(boolean warmup) { 608 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 609 long result = test2(v); 610 Asserts.assertEQ(result, hash()); 611 } 612 613 // Return incoming value type without accessing fields 614 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 11}, failOn = LOAD + TRAP) 615 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP) 616 public MyValue1 test3(MyValue1 v) { 617 return v; 618 } 619 620 @DontCompile 621 public void test3_verifier(boolean warmup) { 622 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 623 MyValue1 v2 = test3(v1); 624 Asserts.assertEQ(v1.x, v2.x); 625 Asserts.assertEQ(v1.y, v2.y); 626 } 627 628 // Create a value type in compiled code and only use fields. 629 // Allocation should go away because value type does not escape. 630 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 631 public long test4() { 632 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 633 return v.hash(); 634 } 635 636 @DontCompile 637 public void test4_verifier(boolean warmup) { 638 long result = test4(); 639 Asserts.assertEQ(result, hash()); 640 } 641 642 // Create a value type in compiled code and pass it to 643 // an inlined compiled method via a call. 644 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 645 public long test5() { 646 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 647 return test5Inline(v); 648 } 649 650 @ForceInline 651 public long test5Inline(MyValue1 v) { 652 return v.hash(); 653 } 654 655 @DontCompile 656 public void test5_verifier(boolean warmup) { 657 long result = test5(); 658 Asserts.assertEQ(result, hash()); 659 } 660 661 // Create a value type in compiled code and pass it to 662 // the interpreter via a call. 663 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC) 664 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 665 public long test6() { 666 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 667 // Pass to interpreter 668 return v.hashInterpreted(); 669 } 670 671 @DontCompile 672 public void test6_verifier(boolean warmup) { 673 long result = test6(); 674 Asserts.assertEQ(result, hash()); 675 } 676 677 // Create a value type in compiled code and pass it to 678 // the interpreter by returning. 679 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 680 public MyValue1 test7(int x, long y) { 681 return MyValue1.createWithFieldsInline(x, y); 682 } 683 684 @DontCompile 685 public void test7_verifier(boolean warmup) { 686 MyValue1 v = test7(rI, rL); 687 Asserts.assertEQ(v.hash(), hash()); 688 } 689 690 // Merge value types created from two branches 691 @Test(failOn = ALLOC + STORE + TRAP) 692 public long test8(boolean b) { 693 MyValue1 v; 694 if (b) { 695 v = MyValue1.createWithFieldsInline(rI, rL); 696 } else { 697 v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1); 698 } 699 return v.hash(); 700 } 701 702 @DontCompile 703 public void test8_verifier(boolean warmup) { 704 Asserts.assertEQ(test8(true), hash()); 705 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1)); 706 } 707 708 // Merge value types created from two branches 709 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {10}, failOn = TRAP + ALLOC + STORE) 710 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP) 711 public MyValue1 test9(boolean b) { 712 MyValue1 v; 713 if (b) { 714 // Value type is not allocated 715 v = MyValue1.createWithFieldsInline(rI, rL); 716 } else { 717 // Value type is allocated by the callee 718 v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1); 719 } 720 // Need to allocate value type if 'b' is true 721 long sum = v.hashInterpreted(); 722 if (b) { 723 v = MyValue1.createWithFieldsDontInline(rI, sum); 724 } else { 725 v = MyValue1.createWithFieldsDontInline(rI, sum + 1); 726 } 727 // Don't need to allocate value type because both branches allocate 728 return v; 729 } 730 731 @DontCompile 732 public void test9_verifier(boolean warmup) { 733 MyValue1 v = test9(true); 734 Asserts.assertEQ(v.x, rI); 735 Asserts.assertEQ(v.y, hash()); 736 v = test9(false); 737 Asserts.assertEQ(v.x, rI); 738 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1); 739 } 740 741 // Merge value types created in a loop (not inlined) 742 @Test(failOn = ALLOC + STORE + TRAP) 743 public long test10(int x, long y) { 744 MyValue1 v = MyValue1.createWithFieldsDontInline(x, y); 745 for (int i = 0; i < 10; ++i) { 746 v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1); 747 } 748 return v.hash(); 749 } 750 751 @DontCompile 752 public void test10_verifier(boolean warmup) { 753 long result = test10(rI, rL); 754 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 755 } 756 757 // Merge value types created in a loop (inlined) 758 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 759 public long test11(int x, long y) { 760 MyValue1 v = MyValue1.createWithFieldsInline(x, y); 761 for (int i = 0; i < 10; ++i) { 762 v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1); 763 } 764 return v.hash(); 765 } 766 767 @DontCompile 768 public void test11_verifier(boolean warmup) { 769 long result = test11(rI, rL); 770 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 771 } 772 773 // Test loop with uncommon trap referencing a value type 774 @Test(match = {SCOBJ}, matchCount = {-1 /* at least 1 */}, failOn = LOAD) 775 public long test12(boolean b) { 776 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 777 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 778 for (int i = 0; i < va.length; ++i) { 779 va[i] = MyValue1.createWithFieldsInline(rI, rL); 780 } 781 long result = rL; 782 for (int i = 0; i < 1000; ++i) { 783 if (b) { 784 result += v.x; 785 } else { 786 // Uncommon trap referencing v. We delegate allocation to the 787 // interpreter by adding a SafePointScalarObjectNode. 788 result = v.hashInterpreted(); 789 for (int j = 0; j < va.length; ++j) { 790 result += va[j].hash(); 791 } 792 } 793 } 794 return result; 795 } 796 797 @DontCompile 798 public void test12_verifier(boolean warmup) { 799 long result = test12(warmup); 800 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 801 } 802 803 // Test loop with uncommon trap referencing a value type 804 @Test 805 public long test13(boolean b) { 806 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 807 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 808 for (int i = 0; i < va.length; ++i) { 809 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 810 } 811 long result = rL; 812 for (int i = 0; i < 1000; ++i) { 813 if (b) { 814 result += v.x; 815 } else { 816 // Uncommon trap referencing v. Should not allocate 817 // but just pass the existing oop to the uncommon trap. 818 result = v.hashInterpreted(); 819 for (int j = 0; j < va.length; ++j) { 820 result += va[j].hashInterpreted(); 821 } 822 } 823 } 824 return result; 825 } 826 827 @DontCompile 828 public void test13_verifier(boolean warmup) { 829 long result = test13(warmup); 830 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 831 } 832 833 // Create a value type in a non-inlined method and then call a 834 // non-inlined method on that value type. 835 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {10}) 836 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP)) 837 public long test14() { 838 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 839 return v.hashInterpreted(); 840 } 841 842 @DontCompile 843 public void test14_verifier(boolean b) { 844 long result = test14(); 845 Asserts.assertEQ(result, hash()); 846 } 847 848 // Create a value type in an inlined method and then call a 849 // non-inlined method on that value type. 850 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC)) 851 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1}) 852 public long test15() { 853 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 854 return v.hashInterpreted(); 855 } 856 857 @DontCompile 858 public void test15_verifier(boolean b) { 859 long result = test15(); 860 Asserts.assertEQ(result, hash()); 861 } 862 863 // Create a value type in a non-inlined method and then call an 864 // inlined method on that value type. 865 @Test(failOn = (ALLOC + STORE + TRAP)) 866 public long test16() { 867 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 868 return v.hash(); 869 } 870 871 @DontCompile 872 public void test16_verifier(boolean b) { 873 long result = test16(); 874 Asserts.assertEQ(result, hash()); 875 } 876 877 // Create a value type in an inlined method and then call an 878 // inlined method on that value type. 879 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 880 public long test17() { 881 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 882 return v.hash(); 883 } 884 885 @DontCompile 886 public void test17_verifier(boolean b) { 887 long result = test17(); 888 Asserts.assertEQ(result, hash()); 889 } 890 891 // Create a value type in compiled code and pass it to the 892 // interpreter via a call. The value is live at the first call so 893 // debug info should include a reference to all its fields. 894 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 895 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 896 public long test18() { 897 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 898 v.hashInterpreted(); 899 return v.hashInterpreted(); 900 } 901 902 @DontCompile 903 public void test18_verifier(boolean warmup) { 904 long result = test18(); 905 Asserts.assertEQ(result, hash()); 906 } 907 908 // Create a value type in compiled code and pass it to the 909 // interpreter via a call. The value type is passed twice but 910 // should only be allocated once. 911 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 912 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 913 public long test19() { 914 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 915 return sumValue(v, v); 916 } 917 918 @DontCompile 919 public long sumValue(MyValue1 v, MyValue1 dummy) { 920 return v.hash(); 921 } 922 923 @DontCompile 924 public void test19_verifier(boolean warmup) { 925 long result = test19(); 926 Asserts.assertEQ(result, hash()); 927 } 928 929 // Create a value type (array) in compiled code and pass it to the 930 // interpreter via a call. The value type is live at the uncommon 931 // trap: verify that deoptimization causes the value type to be 932 // correctly allocated. 933 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE) 934 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {2}, failOn = LOAD) 935 public long test20(boolean deopt) { 936 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 937 MyValue2[] va = new MyValue2[3]; 938 if (deopt) { 939 // uncommon trap 940 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20")); 941 } 942 return v.hashInterpreted() + va[0].hashInterpreted() + 943 va[1].hashInterpreted() + va[2].hashInterpreted(); 944 } 945 946 @DontCompile 947 public void test20_verifier(boolean warmup) { 948 MyValue2[] va = new MyValue2[42]; 949 long result = test20(!warmup); 950 Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash()); 951 } 952 953 // Value type fields in regular object 954 MyValue1 val1; 955 MyValue2 val2; 956 final MyValue1 val3; 957 static MyValue1 val4; 958 static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL); 959 960 // Test value type fields in objects 961 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP)) 962 public long test21(int x, long y) { 963 // Compute hash of value type fields 964 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 965 // Update fields 966 val1 = MyValue1.createWithFieldsInline(x, y); 967 val2 = MyValue2.createWithFieldsInline(x, true); 968 val4 = MyValue1.createWithFieldsInline(x, y); 969 return result; 970 } 971 972 @DontCompile 973 public void test21_verifier(boolean warmup) { 974 // Check if hash computed by test18 is correct 975 val1 = MyValue1.createWithFieldsInline(rI, rL); 976 val2 = val1.v2; 977 // val3 is initialized in the constructor 978 val4 = val1; 979 // val5 is initialized in the static initializer 980 long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 981 long result = test21(rI + 1, rL + 1); 982 Asserts.assertEQ(result, hash); 983 // Check if value type fields were updated 984 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1)); 985 Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, true).hash()); 986 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1)); 987 } 988 989 // Test folding of constant value type fields 990 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 991 public long test22() { 992 // This should be constant folded 993 return val5.hash() + val5.v3.hash(); 994 } 995 996 @DontCompile 997 public void test22_verifier(boolean warmup) { 998 long result = test22(); 999 Asserts.assertEQ(result, val5.hash() + val5.v3.hash()); 1000 } 1001 1002 // Test OSR compilation 1003 @Test() 1004 public long test23() { 1005 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 1006 MyValue1[] va = new MyValue1[Math.abs(rI) % 3]; 1007 for (int i = 0; i < va.length; ++i) { 1008 va[i] = MyValue1.createWithFieldsInline(rI, rL); 1009 } 1010 long result = 0; 1011 // Long loop to trigger OSR compilation 1012 for (int i = 0 ; i < 100_000; ++i) { 1013 // Reference local value type in interpreter state 1014 result = v.hash(); 1015 for (int j = 0; j < va.length; ++j) { 1016 result += va[j].hash(); 1017 } 1018 } 1019 return result; 1020 } 1021 1022 @DontCompile 1023 public void test23_verifier(boolean warmup) { 1024 long result = test23(); 1025 Asserts.assertEQ(result, ((Math.abs(rI) % 3) + 1) * hash()); 1026 } 1027 1028 // Test interpreter to compiled code with various signatures 1029 @Test(failOn = ALLOC + STORE + TRAP) 1030 public long test24(MyValue2 v) { 1031 return v.hash(); 1032 } 1033 1034 @DontCompile 1035 public void test24_verifier(boolean warmup) { 1036 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1037 long result = test24(v); 1038 Asserts.assertEQ(result, v.hashInterpreted()); 1039 } 1040 1041 @Test(failOn = ALLOC + STORE + TRAP) 1042 public long test25(int i1, MyValue2 v, int i2) { 1043 return v.hash() + i1 - i2; 1044 } 1045 1046 @DontCompile 1047 public void test25_verifier(boolean warmup) { 1048 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1049 long result = test25(rI, v, 2*rI); 1050 Asserts.assertEQ(result, v.hashInterpreted() - rI); 1051 } 1052 1053 @Test(failOn = ALLOC + STORE + TRAP) 1054 public long test26(long l1, MyValue2 v, long l2) { 1055 return v.hash() + l1 - l2; 1056 } 1057 1058 @DontCompile 1059 public void test26_verifier(boolean warmup) { 1060 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1061 long result = test26(rL, v, 2*rL); 1062 Asserts.assertEQ(result, v.hashInterpreted() - rL); 1063 } 1064 1065 @Test(failOn = ALLOC + STORE + TRAP) 1066 public long test27(int i, MyValue2 v, long l) { 1067 return v.hash() + i + l; 1068 } 1069 1070 @DontCompile 1071 public void test27_verifier(boolean warmup) { 1072 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1073 long result = test27(rI, v, rL); 1074 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1075 } 1076 1077 @Test(failOn = ALLOC + STORE + TRAP) 1078 public long test28(long l, MyValue2 v, int i) { 1079 return v.hash() + i + l; 1080 } 1081 1082 @DontCompile 1083 public void test28_verifier(boolean warmup) { 1084 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1085 long result = test28(rL, v, rI); 1086 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1087 } 1088 1089 @Test(failOn = ALLOC + STORE + TRAP) 1090 public long test29(long l, MyValue1 v1, int i, MyValue2 v2) { 1091 return v1.hash() + i + l + v2.hash(); 1092 } 1093 1094 @DontCompile 1095 public void test29_verifier(boolean warmup) { 1096 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 1097 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 1098 long result = test29(rL, v1, rI, v2); 1099 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 1100 } 1101 1102 // Test compiled code to interpreter with various signatures 1103 @DontCompile 1104 public long test30_interp(MyValue2 v) { 1105 return v.hash(); 1106 } 1107 1108 @Test(failOn = ALLOC + STORE + TRAP) 1109 public long test30(MyValue2 v) { 1110 return test30_interp(v); 1111 } 1112 1113 @DontCompile 1114 public void test30_verifier(boolean warmup) { 1115 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1116 long result = test30(v); 1117 Asserts.assertEQ(result, v.hashInterpreted()); 1118 } 1119 1120 @DontCompile 1121 public long test31_interp(int i1, MyValue2 v, int i2) { 1122 return v.hash() + i1 - i2; 1123 } 1124 1125 @Test(failOn = ALLOC + STORE + TRAP) 1126 public long test31(int i1, MyValue2 v, int i2) { 1127 return test31_interp(i1, v, i2); 1128 } 1129 1130 @DontCompile 1131 public void test31_verifier(boolean warmup) { 1132 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1133 long result = test31(rI, v, 2*rI); 1134 Asserts.assertEQ(result, v.hashInterpreted() - rI); 1135 } 1136 1137 @DontCompile 1138 public long test32_interp(long l1, MyValue2 v, long l2) { 1139 return v.hash() + l1 - l2; 1140 } 1141 1142 @Test(failOn = ALLOC + STORE + TRAP) 1143 public long test32(long l1, MyValue2 v, long l2) { 1144 return test32_interp(l1, v, l2); 1145 } 1146 1147 @DontCompile 1148 public void test32_verifier(boolean warmup) { 1149 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1150 long result = test32(rL, v, 2*rL); 1151 Asserts.assertEQ(result, v.hashInterpreted() - rL); 1152 } 1153 1154 @DontCompile 1155 public long test33_interp(int i, MyValue2 v, long l) { 1156 return v.hash() + i + l; 1157 } 1158 1159 @Test(failOn = ALLOC + STORE + TRAP) 1160 public long test33(int i, MyValue2 v, long l) { 1161 return test33_interp(i, v, l); 1162 } 1163 1164 @DontCompile 1165 public void test33_verifier(boolean warmup) { 1166 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1167 long result = test33(rI, v, rL); 1168 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1169 } 1170 1171 @DontCompile 1172 public long test34_interp(long l, MyValue2 v, int i) { 1173 return v.hash() + i + l; 1174 } 1175 1176 @Test(failOn = ALLOC + STORE + TRAP) 1177 public long test34(long l, MyValue2 v, int i) { 1178 return test34_interp(l, v, i); 1179 } 1180 1181 @DontCompile 1182 public void test34_verifier(boolean warmup) { 1183 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1184 long result = test34(rL, v, rI); 1185 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 1186 } 1187 1188 @DontCompile 1189 public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 1190 return v1.hash() + i + l + v2.hash(); 1191 } 1192 1193 @Test(failOn = ALLOC + STORE + TRAP) 1194 public long test35(long l, MyValue1 v1, int i, MyValue2 v2) { 1195 return test35_interp(l, v1, i, v2); 1196 } 1197 1198 @DontCompile 1199 public void test35_verifier(boolean warmup) { 1200 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 1201 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 1202 long result = test35(rL, v1, rI, v2); 1203 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 1204 } 1205 1206 // test that debug info at a call is correct 1207 @DontCompile 1208 public long test36_interp(MyValue2 v, MyValue1[] va, boolean deopt) { 1209 if (deopt) { 1210 // uncommon trap 1211 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36")); 1212 } 1213 return v.hash() + va[0].hash() + va[1].hash(); 1214 } 1215 1216 @Test(failOn = ALLOC + STORE + TRAP) 1217 public long test36(MyValue2 v, MyValue1[] va, boolean flag, long l) { 1218 return test36_interp(v, va, flag) + l; 1219 } 1220 1221 @DontCompile 1222 public void test36_verifier(boolean warmup) { 1223 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1224 MyValue1[] va = new MyValue1[2]; 1225 va[0] = MyValue1.createWithFieldsDontInline(rI, rL); 1226 va[1] = MyValue1.createWithFieldsDontInline(rI, rL); 1227 long result = test36(v, va, !warmup, rL); 1228 Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL); 1229 } 1230 1231 // Test vbox and vunbox 1232 @Test 1233 public long test37() throws Throwable { 1234 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 1235 } 1236 1237 @DontCompile 1238 public void test37_verifier(boolean warmup) { 1239 try { 1240 long result = test37(); 1241 Asserts.assertEQ(vcc.t, result, "Field t of input and result must be equal."); 1242 } catch (Throwable t) { 1243 throw new RuntimeException("test 37 failed", t); 1244 } 1245 } 1246 1247 // Generate a MethodHandle that obtains field t of the 1248 // derived value type 1249 private static MethodHandle generateVCCUnboxLoadLongMH() { 1250 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1251 "vccUnboxLoadLong", 1252 MethodType.methodType(long.class, ValueCapableClass1.class), 1253 CODE -> { 1254 CODE. 1255 aload_0(). 1256 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1257 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1258 lreturn(); 1259 } 1260 ); 1261 } 1262 1263 @Test 1264 public int test38() throws Throwable { 1265 return (int)vccUnboxLoadIntMH.invokeExact(vcc); 1266 } 1267 1268 @DontCompile 1269 public void test38_verifier(boolean warmup) { 1270 try { 1271 int result = test38(); 1272 Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal."); 1273 } catch (Throwable t) { 1274 throw new RuntimeException("test 38 failed", t); 1275 } 1276 } 1277 1278 // Generate a MethodHandle that obtains field x of the 1279 // derived value type 1280 private static MethodHandle generateVCCUnboxLoadIntMH() { 1281 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1282 "vccUnboxLoadInt", 1283 MethodType.methodType(int.class, ValueCapableClass1.class), 1284 CODE -> { 1285 CODE. 1286 aload_0(). 1287 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1288 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "x", "I"). 1289 ireturn(); 1290 } 1291 ); 1292 } 1293 1294 @Test 1295 public ValueCapableClass1 test39() throws Throwable { 1296 return (ValueCapableClass1)vccUnboxBoxMH.invokeExact(vcc); 1297 } 1298 1299 @DontCompile 1300 public void test39_verifier(boolean warmup) { 1301 try { 1302 ValueCapableClass1 result = test39(); 1303 Asserts.assertEQ(vcc.value(), result.value(), "Value of VCC and returned VCC must be equal"); 1304 } catch (Throwable t) { 1305 throw new RuntimeException("test 39 failed", t); 1306 } 1307 } 1308 1309 // Generate a MethodHandle that takes a value-capable class, 1310 // unboxes it, then boxes it again and returns it. 1311 private static MethodHandle generateVCCUnboxBoxMH() { 1312 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1313 "vccUnboxBox", 1314 MethodType.methodType(ValueCapableClass1.class, ValueCapableClass1.class), 1315 CODE -> { 1316 CODE. 1317 aload_0(). 1318 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1319 vbox(ValueCapableClass1.class). 1320 areturn(); 1321 } 1322 ); 1323 } 1324 1325 @Test 1326 public int test40() throws Throwable { 1327 return (int)vccUnboxBoxLoadIntMH.invokeExact(vcc); 1328 } 1329 1330 @DontCompile 1331 public void test40_verifier(boolean warmup) { 1332 try { 1333 int result = test40(); 1334 Asserts.assertEQ(vcc.x, result, "Field x of VCC and result must be equal"); 1335 } catch (Throwable t) { 1336 throw new RuntimeException("Test failed in the interpeter", t); 1337 } 1338 } 1339 1340 // Generate a MethodHandle that takes a value-capable class, 1341 // unboxes it, boxes it, reads a field from it, and returns the 1342 // field. 1343 private static MethodHandle generateVCCUnboxBoxLoadIntMH() { 1344 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1345 "vccUnboxBoxLoadInt", 1346 MethodType.methodType(int.class, ValueCapableClass1.class), 1347 CODE -> { 1348 CODE. 1349 aload_0(). 1350 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1351 vbox(ValueCapableClass1.class). 1352 getfield(ValueCapableClass1.class, "x", "I"). 1353 ireturn(); 1354 } 1355 ); 1356 1357 } 1358 1359 // Test value type array creation and initialization 1360 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD)) 1361 @Test(valid = ValueTypeArrayFlattenOn) 1362 public MyValue1[] test41(int len) { 1363 MyValue1[] va = new MyValue1[len]; 1364 for (int i = 0; i < len; ++i) { 1365 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 1366 } 1367 return va; 1368 } 1369 1370 @DontCompile 1371 public void test41_verifier(boolean warmup) { 1372 int len = Math.abs(rI % 10); 1373 MyValue1[] va = test41(len); 1374 for (int i = 0; i < len; ++i) { 1375 Asserts.assertEQ(va[i].hash(), hash()); 1376 } 1377 } 1378 1379 // Test creation of a value type array and element access 1380 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOOP + TRAP)) 1381 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOC + ALLOCA + LOOP + LOAD + LOADP + STORE + TRAP)) 1382 public long test42() { 1383 MyValue1[] va = new MyValue1[1]; 1384 va[0] = MyValue1.createWithFieldsInline(rI, rL); 1385 return va[0].hash(); 1386 } 1387 1388 @DontCompile 1389 public void test42_verifier(boolean warmup) { 1390 long result = test42(); 1391 Asserts.assertEQ(result, hash()); 1392 } 1393 1394 // Test receiving a value type array from the interpreter, 1395 // updating its elements in a loop and computing a hash. 1396 @Test(failOn = (ALLOCA)) 1397 public long test43(MyValue1[] va) { 1398 long result = 0; 1399 for (int i = 0; i < 10; ++i) { 1400 result += va[i].hash(); 1401 va[i] = MyValue1.createWithFieldsInline(rI + 1, rL + 1); 1402 } 1403 return result; 1404 } 1405 1406 @DontCompile 1407 public void test43_verifier(boolean warmup) { 1408 MyValue1[] va = new MyValue1[10]; 1409 long expected = 0; 1410 for (int i = 0; i < 10; ++i) { 1411 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i); 1412 expected += va[i].hash(); 1413 } 1414 long result = test43(va); 1415 Asserts.assertEQ(expected, result); 1416 for (int i = 0; i < 10; ++i) { 1417 if (va[i].hash() != hash(rI + 1, rL + 1)) { 1418 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1)); 1419 } 1420 } 1421 } 1422 1423 // Test returning a value type array received from the interpreter 1424 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP) 1425 public MyValue1[] test44(MyValue1[] va) { 1426 return va; 1427 } 1428 1429 @DontCompile 1430 public void test44_verifier(boolean warmup) { 1431 MyValue1[] va = new MyValue1[10]; 1432 for (int i = 0; i < 10; ++i) { 1433 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i); 1434 } 1435 va = test44(va); 1436 for (int i = 0; i < 10; ++i) { 1437 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1438 } 1439 } 1440 1441 // Merge value type arrays created from two branches 1442 @Test 1443 public MyValue1[] test45(boolean b) { 1444 MyValue1[] va; 1445 if (b) { 1446 va = new MyValue1[5]; 1447 for (int i = 0; i < 5; ++i) { 1448 va[i] = MyValue1.createWithFieldsInline(rI, rL); 1449 } 1450 } else { 1451 va = new MyValue1[10]; 1452 for (int i = 0; i < 10; ++i) { 1453 va[i] = MyValue1.createWithFieldsInline(rI + i, rL + i); 1454 } 1455 } 1456 long sum = va[0].hashInterpreted(); 1457 if (b) { 1458 va[0] = MyValue1.createWithFieldsDontInline(rI, sum); 1459 } else { 1460 va[0] = MyValue1.createWithFieldsDontInline(rI + 1, sum + 1); 1461 } 1462 return va; 1463 } 1464 1465 @DontCompile 1466 public void test45_verifier(boolean warmup) { 1467 MyValue1[] va = test45(true); 1468 Asserts.assertEQ(va.length, 5); 1469 Asserts.assertEQ(va[0].hash(), hash(rI, hash())); 1470 for (int i = 1; i < 5; ++i) { 1471 Asserts.assertEQ(va[i].hash(), hash()); 1472 } 1473 va = test45(false); 1474 Asserts.assertEQ(va.length, 10); 1475 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1)); 1476 for (int i = 1; i < 10; ++i) { 1477 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1478 } 1479 } 1480 1481 // Test creation of value type array with single element 1482 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP)) 1483 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP)) 1484 public MyValue1 test46() { 1485 MyValue1[] va = new MyValue1[1]; 1486 return va[0]; 1487 } 1488 1489 @DontCompile 1490 public void test46_verifier(boolean warmup) { 1491 MyValue1[] va = new MyValue1[1]; 1492 MyValue1 v = test46(); 1493 Asserts.assertEQ(v.hashPrimitive(), va[0].hashPrimitive()); 1494 } 1495 1496 // Test default initialization of value type arrays 1497 @Test(failOn = LOAD) 1498 public MyValue1[] test47(int len) { 1499 return new MyValue1[len]; 1500 } 1501 1502 @DontCompile 1503 public void test47_verifier(boolean warmup) { 1504 int len = Math.abs(rI % 10); 1505 MyValue1[] va = new MyValue1[len]; 1506 MyValue1[] var = test47(len); 1507 for (int i = 0; i < len; ++i) { 1508 Asserts.assertEQ(va[i].hashPrimitive(), var[i].hashPrimitive()); 1509 } 1510 } 1511 1512 // Test creation of value type array with zero length 1513 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 1514 public MyValue1[] test48() { 1515 return new MyValue1[0]; 1516 } 1517 1518 @DontCompile 1519 public void test48_verifier(boolean warmup) { 1520 MyValue1[] va = test48(); 1521 Asserts.assertEQ(va.length, 0); 1522 } 1523 1524 static MyValue1[] test49_va; 1525 1526 // Test that value type array loaded from field has correct type 1527 @Test(failOn = (LOOP)) 1528 public long test49() { 1529 return test49_va[0].hash(); 1530 } 1531 1532 @DontCompile 1533 public void test49_verifier(boolean warmup) { 1534 test49_va = new MyValue1[1]; 1535 test49_va[0] = MyValue1.createWithFieldsInline(rI, rL); 1536 long result = test49(); 1537 Asserts.assertEQ(result, hash()); 1538 } 1539 1540 // test vdefault 1541 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1542 public long test50() { 1543 MyValue2 v = MyValue2.createDefaultInline(); 1544 return v.hash(); 1545 } 1546 1547 @DontCompile 1548 public void test50_verifier(boolean warmup) { 1549 long result = test50(); 1550 Asserts.assertEQ(result, MyValue2.createDefaultInline().hash()); 1551 } 1552 1553 // test vdefault 1554 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1555 public long test51() { 1556 MyValue1 v1 = MyValue1.createDefaultInline(); 1557 MyValue1 v2 = MyValue1.createDefaultDontInline(); 1558 return v1.hashPrimitive() + v2.hashPrimitive(); 1559 } 1560 1561 @DontCompile 1562 public void test51_verifier(boolean warmup) { 1563 long result = test51(); 1564 Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive()); 1565 } 1566 1567 // test vwithfield 1568 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1569 public long test52() { 1570 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1571 return v.hash(); 1572 } 1573 1574 @DontCompile 1575 public void test52_verifier(boolean warmup) { 1576 long result = test52(); 1577 Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash()); 1578 } 1579 1580 // test vwithfield 1581 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1582 public long test53() { 1583 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL); 1584 MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL); 1585 return v1.hash() + v2.hash(); 1586 } 1587 1588 @DontCompile 1589 public void test53_verifier(boolean warmup) { 1590 long result = test53(); 1591 Asserts.assertEQ(result, 2 * hash()); 1592 } 1593 1594 // multi-dimensional arrays 1595 @Test 1596 public MyValue1[][][] test54(int len1, int len2, int len3) { 1597 MyValue1[][][] arr = new MyValue1[len1][len2][len3]; 1598 for (int i = 0; i < len1; i++) { 1599 for (int j = 0; j < len2; j++) { 1600 for (int k = 0; k < len3; k++) { 1601 arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i , rL + j + k); 1602 } 1603 } 1604 } 1605 return arr; 1606 } 1607 1608 @DontCompile 1609 public void test54_verifier(boolean warmup) { 1610 MyValue1[][][] arr = test54(2, 3, 4); 1611 for (int i = 0; i < 2; i++) { 1612 for (int j = 0; j < 3; j++) { 1613 for (int k = 0; k < 4; k++) { 1614 Asserts.assertEQ(arr[i][j][k].hash(), MyValue1.createWithFieldsDontInline(rI + i , rL + j + k).hash()); 1615 } 1616 } 1617 } 1618 } 1619 1620 @Test 1621 public void test55(MyValue1[][][] arr, long[] res) { 1622 int l = 0; 1623 for (int i = 0; i < arr.length; i++) { 1624 for (int j = 0; j < arr[i].length; j++) { 1625 for (int k = 0; k < arr[i][j].length; k++) { 1626 res[l] = arr[i][j][k].hash(); 1627 l++; 1628 } 1629 } 1630 } 1631 } 1632 1633 @DontCompile 1634 public void test55_verifier(boolean warmup) { 1635 MyValue1[][][] arr = new MyValue1[2][3][4]; 1636 long[] res = new long[2*3*4]; 1637 long[] verif = new long[2*3*4]; 1638 int l = 0; 1639 for (int i = 0; i < 2; i++) { 1640 for (int j = 0; j < 3; j++) { 1641 for (int k = 0; k < 4; k++) { 1642 arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i, rL + j + k); 1643 verif[l] = arr[i][j][k].hash(); 1644 l++; 1645 } 1646 } 1647 } 1648 test55(arr, res); 1649 for (int i = 0; i < verif.length; i++) { 1650 Asserts.assertEQ(res[i], verif[i]); 1651 } 1652 } 1653 1654 class TestClass56 { 1655 public MyValue1 v; 1656 } 1657 1658 // Test allocation elimination of unused object with initialized value type field 1659 @Test(failOn = ALLOC + LOAD + STORE + LOOP) 1660 public void test56(boolean deopt) { 1661 TestClass56 unused = new TestClass56(); 1662 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 1663 unused.v = v; 1664 if (deopt) { 1665 // uncommon trap 1666 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test56")); 1667 } 1668 } 1669 1670 @DontCompile 1671 public void test56_verifier(boolean warmup) { 1672 test56(!warmup); 1673 } 1674 1675 // Test loop peeling 1676 @Test(failOn = ALLOC + LOAD + STORE) 1677 public void test57() { 1678 MyValue1 v = MyValue1.createWithFieldsInline(0, 1); 1679 // Trigger OSR compilation and loop peeling 1680 for (int i = 0; i < 100_000; ++i) { 1681 if (v.x != i || v.y != i + 1) { 1682 // Uncommon trap 1683 throw new RuntimeException("test57 failed"); 1684 } 1685 v = MyValue1.createWithFieldsInline(i + 1, i + 2); 1686 } 1687 } 1688 1689 @DontCompile 1690 public void test57_verifier(boolean warmup) { 1691 test57(); 1692 } 1693 1694 // Test loop peeling and unrolling 1695 @Test() 1696 public void test58() { 1697 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0); 1698 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1); 1699 // Trigger OSR compilation and loop peeling 1700 for (int i = 0; i < 100_000; ++i) { 1701 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) { 1702 // Uncommon trap 1703 throw new RuntimeException("test58 failed"); 1704 } 1705 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0); 1706 v2 = MyValue1.createWithFieldsInline(i+2, i+2); 1707 } 1708 } 1709 1710 @DontCompile 1711 public void test58_verifier(boolean warmup) { 1712 test58(); 1713 } 1714 1715 // When calling a method on __Value, passing fields as arguments is impossible 1716 @Test(failOn = ALLOC + STORE + LOAD) 1717 public String test59(MyValue1 v) { 1718 return v.toString(); 1719 } 1720 1721 @DontCompile 1722 public void test59_verifier(boolean warmup) { 1723 boolean failed = false; 1724 try { 1725 test59(val1); 1726 failed = true; 1727 } catch (UnsupportedOperationException uoe) { 1728 } 1729 Asserts.assertFalse(failed); 1730 } 1731 1732 // Same as above, but the method on __Value is inlined 1733 // hashCode allocates an exception so can't really check the graph shape 1734 @Test() 1735 public int test60(MyValue1 v) { 1736 return v.hashCode(); 1737 } 1738 1739 @DontCompile 1740 public void test60_verifier(boolean warmup) { 1741 boolean failed = false; 1742 try { 1743 test60(val1); 1744 failed = true; 1745 } catch (UnsupportedOperationException uoe) { 1746 } 1747 Asserts.assertFalse(failed); 1748 } 1749 1750 /* The compiler is supposed to determine that the value to be 1751 * unboxed in nullcvvUnboxLoadLong is always null. Therefore, the 1752 * compiler generates only the path leading to the corresponding 1753 * uncommon trap. */ 1754 @Test(failOn = RETURN) 1755 public long test61() throws Throwable { 1756 return (long)nullvccUnboxLoadLongMH.invokeExact(); 1757 } 1758 1759 @DontCompile 1760 public void test61_verifier(boolean warmup) throws Throwable { 1761 try { 1762 long result = test61(); 1763 throw new RuntimeException("Test failed because no exception was thrown"); 1764 } catch (NullPointerException e) { 1765 } 1766 } 1767 1768 public static MethodHandle generateNullVCCUnboxLoadLongMH() { 1769 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1770 "nullvccUnboxLoadLong", 1771 MethodType.methodType(long.class), 1772 CODE -> { 1773 CODE. 1774 aconst_null(). 1775 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1776 vgetfield(ValueCapableClass1.class, "t", "J"). 1777 lreturn(); 1778 } 1779 ); 1780 } 1781 1782 /* The compiler is supposed to determine that the allocated 1783 * ValueCapableClass1 instance is never null (and therefore not 1784 * generate a null check). Also, the source and target type match 1785 * (known at compile time), so no type check is needed either.*/ 1786 @Test(failOn = NPE) 1787 public long test62() throws Throwable { 1788 return (long)checkedvccUnboxLoadLongMH.invokeExact(); 1789 } 1790 1791 @DontCompile 1792 public void test62_verifier(boolean warmup) throws Throwable { 1793 long result = test62(); 1794 Asserts.assertEQ(result, 17L); 1795 } 1796 1797 public static MethodHandle generateCheckedVCCUnboxLoadLongMH() { 1798 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1799 "checkedVCCUnboxLoadLongMH", 1800 MethodType.methodType(long.class), 1801 CODE -> { 1802 CODE. 1803 invokestatic(ValueCapableClass1.class, "createInline", "()Lcompiler/valhalla/valuetypes/ValueCapableClass1;", false). 1804 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1805 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1806 lreturn(); 1807 } 1808 ); 1809 } 1810 1811 /* The compiler is supposed to emit a runtime null check because 1812 * it does not have enough information to determine that the value 1813 * to be unboxed is not null (and either that it is null). The 1814 * declared type of the */ 1815 @Test(match = {NPE}, matchCount = {1}) 1816 public long test63(ValueCapableClass1 vcc) throws Throwable { 1817 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 1818 } 1819 1820 @DontCompile 1821 public void test63_verifier(boolean warmup) throws Throwable { 1822 try { 1823 long result = test63(null); 1824 throw new RuntimeException("Test failed because no exception was thrown"); 1825 } catch (NullPointerException e) { 1826 } 1827 } 1828 1829 /* Attempt to unbox an object that is not a subclass of the 1830 * value-capable class derived from the value type specified in 1831 * the vunbox bytecode. */ 1832 @Test(match = {NPE,CCE}, matchCount = {1,1}) 1833 public long test64(Object vcc) throws Throwable { 1834 return (long)objectUnboxLoadLongMH.invokeExact(vcc); 1835 } 1836 1837 @DontCompile 1838 public void test64_verifier(boolean warmup) throws Throwable { 1839 try { 1840 long result = test64(new Object()); 1841 throw new RuntimeException("Test failed because no exception was thrown"); 1842 } catch (ClassCastException e) { 1843 } 1844 1845 try { 1846 long result = test64(vcc2); 1847 throw new RuntimeException("Test failed because no exception was thrown"); 1848 } catch (ClassCastException e) { 1849 } 1850 1851 Asserts.assertEQ(test64(vcc), rL); 1852 } 1853 1854 private static MethodHandle generateObjectUnboxLoadLongMH() { 1855 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1856 "ObjectUnboxLoadLong", 1857 MethodType.methodType(long.class, Object.class), 1858 CODE -> { 1859 CODE. 1860 aload_0(). 1861 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1862 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1863 lreturn(); 1864 } 1865 ); 1866 } 1867 1868 /* Generate an if-then-else construct with one path that contains 1869 * an invalid boxing operation (boxing of a value-type to a 1870 * non-matching value-capable class).*/ 1871 @Test(match = {NPE, CCE}, matchCount = {2, 2}) 1872 public long test65(Object obj, boolean warmup) throws Throwable { 1873 return (long)objectBoxMH.invokeExact(obj, warmup); 1874 } 1875 1876 @DontCompile 1877 public void test65_verifier(boolean warmup) throws Throwable { 1878 try { 1879 long result = test65(vcc2, true); 1880 throw new RuntimeException("Test failed because no exception was thrown"); 1881 } catch (ClassCastException e) { 1882 } 1883 1884 Asserts.assertEQ(test65(vcc, true), rL); 1885 1886 try { 1887 long result = test65(vcc2, false); 1888 throw new RuntimeException("Test failed because no exception was thrown"); 1889 } catch (ClassCastException e) { 1890 } 1891 1892 try { 1893 long result = test65(vcc, false); 1894 throw new RuntimeException("Test failed because no exception was thrown"); 1895 } catch (ClassCastException e) { 1896 } 1897 } 1898 1899 private static MethodHandle generateObjectBoxMH() { 1900 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1901 "ObjectBox", 1902 MethodType.methodType(long.class, Object.class, boolean.class), 1903 CODE -> { 1904 CODE. 1905 iload_1(). 1906 iconst_1(). 1907 if_icmpne((short)14). 1908 aload_0(). 1909 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1910 vbox(ValueCapableClass1.class). 1911 getfield(ValueCapableClass1.class, "t", "J"). 1912 lreturn(). 1913 aload_0(). 1914 vunbox(ValueType.forClass(ValueCapableClass2.class).valueClass()). 1915 vbox(ValueCapableClass1.class). 1916 getfield(ValueCapableClass1.class, "t", "J"). 1917 lreturn(); 1918 } 1919 ); 1920 } 1921 1922 // Test deoptimization at call return with return value in registers 1923 @DontCompile 1924 public MyValue2 test66_interp(boolean deopt) { 1925 if (deopt) { 1926 // uncommon trap 1927 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test66")); 1928 } 1929 return MyValue2.createWithFieldsInline(rI, true); 1930 } 1931 1932 @Test() 1933 public MyValue2 test66(boolean flag) { 1934 return test66_interp(flag); 1935 } 1936 1937 @DontCompile 1938 public void test66_verifier(boolean warmup) { 1939 MyValue2 result = test66(!warmup); 1940 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1941 Asserts.assertEQ(result.hash(), v.hash()); 1942 } 1943 1944 // Return value types in registers from interpreter -> compiled 1945 final MyValue3 test67_vt = MyValue3.create(); 1946 @DontCompile 1947 public MyValue3 test67_interp() { 1948 return test67_vt; 1949 } 1950 1951 MyValue3 test67_vt2; 1952 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP) 1953 @Test(valid = ValueTypeReturnedAsFieldsOff) 1954 public void test67() { 1955 test67_vt2 = test67_interp(); 1956 } 1957 1958 @DontCompile 1959 public void test67_verifier(boolean warmup) { 1960 test67(); 1961 test67_vt.verify(test67_vt2); 1962 } 1963 1964 // Return value types in registers from compiled -> interpreter 1965 final MyValue3 test68_vt = MyValue3.create(); 1966 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + TRAP) 1967 @Test(valid = ValueTypeReturnedAsFieldsOff) 1968 public MyValue3 test68() { 1969 return test68_vt; 1970 } 1971 1972 @DontCompile 1973 public void test68_verifier(boolean warmup) { 1974 MyValue3 vt = test68(); 1975 test68_vt.verify(vt); 1976 } 1977 1978 // Return value types in registers from compiled -> compiled 1979 final MyValue3 test69_vt = MyValue3.create(); 1980 @DontInline 1981 public MyValue3 test69_comp() { 1982 return test69_vt; 1983 } 1984 1985 MyValue3 test69_vt2; 1986 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP) 1987 @Test(valid = ValueTypeReturnedAsFieldsOff) 1988 public void test69() { 1989 test69_vt2 = test69_comp(); 1990 } 1991 1992 @DontCompile 1993 public void test69_verifier(boolean warmup) throws Exception { 1994 Method helper_m = getClass().getDeclaredMethod("test69_comp"); 1995 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 1996 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 1997 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test69_comp not compiled"); 1998 } 1999 test69(); 2000 test69_vt.verify(test69_vt2); 2001 } 2002 2003 // Same tests as above but with a value type that cannot be returned in registers 2004 2005 // Return value types in registers from interpreter -> compiled 2006 final MyValue4 test70_vt = MyValue4.create(); 2007 @DontCompile 2008 public MyValue4 test70_interp() { 2009 return test70_vt; 2010 } 2011 2012 MyValue4 test70_vt2; 2013 @Test 2014 public void test70() { 2015 test70_vt2 = test70_interp(); 2016 } 2017 2018 @DontCompile 2019 public void test70_verifier(boolean warmup) { 2020 test70(); 2021 test70_vt.verify(test70_vt2); 2022 } 2023 2024 // Return value types in registers from compiled -> interpreter 2025 final MyValue4 test71_vt = MyValue4.create(); 2026 @Test 2027 public MyValue4 test71() { 2028 return test71_vt; 2029 } 2030 2031 @DontCompile 2032 public void test71_verifier(boolean warmup) { 2033 MyValue4 vt = test71(); 2034 test71_vt.verify(vt); 2035 } 2036 2037 // Return value types in registers from compiled -> compiled 2038 final MyValue4 test72_vt = MyValue4.create(); 2039 @DontInline 2040 public MyValue4 test72_comp() { 2041 return test72_vt; 2042 } 2043 2044 MyValue4 test72_vt2; 2045 @Test 2046 public void test72() { 2047 test72_vt2 = test72_comp(); 2048 } 2049 2050 @DontCompile 2051 public void test72_verifier(boolean warmup) throws Exception { 2052 Method helper_m = getClass().getDeclaredMethod("test72_comp"); 2053 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 2054 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 2055 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test72_comp not compiled"); 2056 } 2057 test72(); 2058 test72_vt.verify(test72_vt2); 2059 } 2060 2061 // Return values and method handles tests 2062 2063 // Everything inlined 2064 final MyValue3 test73_vt = MyValue3.create(); 2065 @ForceInline 2066 MyValue3 test73_target() { 2067 return test73_vt; 2068 } 2069 2070 static final MethodHandle test73_mh; 2071 2072 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + CALL) 2073 @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 11 }) 2074 MyValue3 test73() throws Throwable { 2075 return (MyValue3)test73_mh.invokeExact(this); 2076 } 2077 2078 @DontCompile 2079 public void test73_verifier(boolean warmup) throws Throwable { 2080 MyValue3 vt = test73(); 2081 test73_vt.verify(vt); 2082 } 2083 2084 // Leaf method not inlined but returned type is known 2085 final MyValue3 test74_vt = MyValue3.create(); 2086 @DontInline 2087 MyValue3 test74_target() { 2088 return test74_vt; 2089 } 2090 2091 static final MethodHandle test74_mh; 2092 2093 @Test 2094 MyValue3 test74() throws Throwable { 2095 return (MyValue3)test74_mh.invokeExact(this); 2096 } 2097 2098 @DontCompile 2099 public void test74_verifier(boolean warmup) throws Throwable { 2100 Method helper_m = getClass().getDeclaredMethod("test74_target"); 2101 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 2102 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 2103 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test74_target not compiled"); 2104 } 2105 MyValue3 vt = test74(); 2106 test74_vt.verify(vt); 2107 } 2108 2109 // Leaf method not inlined and returned type not known 2110 final MyValue3 test75_vt = MyValue3.create(); 2111 @DontInline 2112 MyValue3 test75_target() { 2113 return test75_vt; 2114 } 2115 2116 static final MethodHandle test75_mh; 2117 2118 @Test 2119 MyValue3 test75() throws Throwable { 2120 return (MyValue3)test75_mh.invokeExact(this); 2121 } 2122 2123 @DontCompile 2124 public void test75_verifier(boolean warmup) throws Throwable { 2125 // hack so C2 doesn't know the target of the invoke call 2126 Class c = Class.forName("java.lang.invoke.DirectMethodHandle"); 2127 Method m = c.getDeclaredMethod("internalMemberName", Object.class); 2128 WHITE_BOX.testSetDontInlineMethod(m, warmup); 2129 MyValue3 vt = test75(); 2130 test75_vt.verify(vt); 2131 } 2132 2133 // Test no result from inlined method for incremental inlining 2134 final MyValue3 test76_vt = MyValue3.create(); 2135 public MyValue3 test76_inlined() { 2136 throw new RuntimeException(); 2137 } 2138 2139 @Test 2140 public MyValue3 test76() { 2141 try { 2142 return test76_inlined(); 2143 } catch (RuntimeException ex) { 2144 return test76_vt; 2145 } 2146 } 2147 2148 @DontCompile 2149 public void test76_verifier(boolean warmup) { 2150 MyValue3 vt = test76(); 2151 test76_vt.verify(vt); 2152 } 2153 2154 static { 2155 try { 2156 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2157 MethodType mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue3;", ValueTypeTestBench.class.getClassLoader()); 2158 test73_mh = lookup.findVirtual(ValueTypeTestBench.class, "test73_target", mt); 2159 test74_mh = lookup.findVirtual(ValueTypeTestBench.class, "test74_target", mt); 2160 test75_mh = lookup.findVirtual(ValueTypeTestBench.class, "test75_target", mt); 2161 } catch (NoSuchMethodException|IllegalAccessException e) { 2162 throw new RuntimeException("method handle lookup fails"); 2163 } 2164 } 2165 2166 /* Array load out of bounds (upper bound) at compile time.*/ 2167 @Test 2168 public int test77() { 2169 int arraySize = Math.abs(rI) % 10;; 2170 MyValue1[] va = new MyValue1[arraySize]; 2171 2172 for (int i = 0; i < arraySize; i++) { 2173 va[i] = MyValue1.createWithFieldsDontInline(rI + 1, rL); 2174 } 2175 2176 try { 2177 return va[arraySize + 1].x; 2178 } catch (ArrayIndexOutOfBoundsException e) { 2179 return rI; 2180 } 2181 } 2182 2183 public void test77_verifier(boolean warmup) { 2184 Asserts.assertEQ(test77(), rI); 2185 } 2186 2187 /* Array load out of bounds (lower bound) at compile time.*/ 2188 @Test 2189 public int test78() { 2190 int arraySize = Math.abs(rI) % 10;; 2191 MyValue1[] va = new MyValue1[arraySize]; 2192 2193 for (int i = 0; i < arraySize; i++) { 2194 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL); 2195 } 2196 2197 try { 2198 return va[-arraySize].x; 2199 } catch (ArrayIndexOutOfBoundsException e) { 2200 return rI; 2201 } 2202 } 2203 2204 public void test78_verifier(boolean warmup) { 2205 Asserts.assertEQ(test78(), rI); 2206 } 2207 2208 /* Array load out of bound not known to compiler (both lower and upper bound). */ 2209 @Test 2210 public int test79(MyValue1[] va, int index) { 2211 return va[index].x; 2212 } 2213 2214 public void test79_verifier(boolean warmup) { 2215 int arraySize = Math.abs(rI) % 10; 2216 MyValue1[] va = new MyValue1[arraySize]; 2217 2218 for (int i = 0; i < arraySize; i++) { 2219 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 2220 } 2221 2222 int result; 2223 for (int i = -20; i < 20; i++) { 2224 try { 2225 result = test79(va, i); 2226 } catch (ArrayIndexOutOfBoundsException e) { 2227 result = rI; 2228 } 2229 Asserts.assertEQ(result, rI); 2230 } 2231 } 2232 2233 /* Array store out of bounds (upper bound) at compile time.*/ 2234 @Test 2235 public int test80() { 2236 int arraySize = Math.abs(rI) % 10;; 2237 MyValue1[] va = new MyValue1[arraySize]; 2238 2239 try { 2240 for (int i = 0; i <= arraySize; i++) { 2241 va[i] = MyValue1.createWithFieldsDontInline(rI + 1, rL); 2242 } 2243 return rI - 1; 2244 } catch (ArrayIndexOutOfBoundsException e) { 2245 return rI; 2246 } 2247 } 2248 2249 public void test80_verifier(boolean warmup) { 2250 Asserts.assertEQ(test80(), rI); 2251 } 2252 2253 /* Array store out of bounds (lower bound) at compile time.*/ 2254 @Test 2255 public int test81() { 2256 int arraySize = Math.abs(rI) % 10;; 2257 MyValue1[] va = new MyValue1[arraySize]; 2258 2259 try { 2260 for (int i = -1; i <= arraySize; i++) { 2261 va[i] = MyValue1.createWithFieldsDontInline(rI + 1, rL); 2262 } 2263 return rI - 1; 2264 } catch (ArrayIndexOutOfBoundsException e) { 2265 return rI; 2266 } 2267 } 2268 2269 public void test81_verifier(boolean warmup) { 2270 Asserts.assertEQ(test81(), rI); 2271 } 2272 2273 /* Array store out of bound not known to compiler (both lower and upper bound). */ 2274 @Test 2275 public int test82(MyValue1[] va, int index, MyValue1 vt) { 2276 va[index] = vt; 2277 return va[index].x; 2278 } 2279 2280 @DontCompile 2281 public void test82_verifier(boolean warmup) { 2282 int arraySize = Math.abs(rI) % 10; 2283 MyValue1[] va = new MyValue1[arraySize]; 2284 2285 for (int i = 0; i < arraySize; i++) { 2286 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 2287 } 2288 2289 MyValue1 vt = MyValue1.createWithFieldsDontInline(rI + 1, rL); 2290 int result; 2291 for (int i = -20; i < 20; i++) { 2292 try { 2293 result = test82(va, i, vt); 2294 } catch (ArrayIndexOutOfBoundsException e) { 2295 result = rI + 1; 2296 } 2297 Asserts.assertEQ(result, rI + 1); 2298 } 2299 2300 for (int i = 0; i < arraySize; i++) { 2301 Asserts.assertEQ(va[i].x, rI + 1); 2302 } 2303 } 2304 2305 /* Create a new value type array and store a value type into 2306 * it. The test should pass without throwing an exception. */ 2307 @Test 2308 public void test83() throws Throwable { 2309 vastoreMH.invokeExact(vcc); 2310 } 2311 2312 public void test83_verifier(boolean warmup) throws Throwable { 2313 test83(); 2314 } 2315 2316 private static MethodHandle generateVastore() { 2317 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 2318 "Vastore", 2319 MethodType.methodType(void.class, ValueCapableClass1.class), 2320 CODE -> { 2321 CODE. 2322 iconst_1(). 2323 anewarray(ValueType.forClass(ValueCapableClass1.class).valueClass()). 2324 iconst_0(). 2325 aload_0(). 2326 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 2327 vastore(). 2328 return_(); 2329 } 2330 ); 2331 } 2332 2333 /* Create a new value type array with element type 2334 * ValueCapableClass1 and attempt to store a value type of type 2335 * ValueCapableClass2 into it. */ 2336 @Test 2337 public void test84() throws Throwable { 2338 invalidVastoreMH.invokeExact(vcc2); 2339 } 2340 2341 public void test84_verifier(boolean warmup) throws Throwable { 2342 boolean exceptionThrown = false; 2343 try { 2344 test84(); 2345 } catch (ArrayStoreException e) { 2346 exceptionThrown = true; 2347 } 2348 Asserts.assertTrue(exceptionThrown, "ArrayStoreException must be thrown"); 2349 } 2350 2351 private static MethodHandle generateInvalidVastore() { 2352 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 2353 "Vastore", 2354 MethodType.methodType(void.class, ValueCapableClass2.class), 2355 CODE -> { 2356 CODE. 2357 iconst_1(). 2358 anewarray(ValueType.forClass(ValueCapableClass1.class).valueClass()). 2359 iconst_0(). 2360 aload_0(). 2361 vunbox(ValueType.forClass(ValueCapableClass2.class).valueClass()). 2362 vastore(). 2363 return_(); 2364 } 2365 ); 2366 } 2367 2368 // When test85_helper1 is inlined in test85, the method handle 2369 // linker that called it is passed a pointer to a copy of vt 2370 // stored in memory. The method handle linker needs to load the 2371 // fields from memory before it inlines test85_helper1. 2372 static public int test85_helper1(MyValue1 vt) { 2373 return vt.x; 2374 } 2375 2376 static MyValue1 test85_vt = MyValue1.createWithFieldsInline(rI, rL); 2377 static public MyValue1 test85_helper2() { 2378 return test85_vt; 2379 } 2380 2381 static final MethodHandle test85_mh; 2382 2383 @Test 2384 public int test85() throws Throwable { 2385 return (int)test85_mh.invokeExact(); 2386 } 2387 2388 @DontCompile 2389 public void test85_verifier(boolean warmup) throws Throwable { 2390 int i = test85(); 2391 Asserts.assertEQ(i, test85_vt.x); 2392 } 2393 2394 // Test method handle call with value type argument 2395 public int test86_target(MyValue1 vt) { 2396 return vt.x; 2397 } 2398 2399 static final MethodHandle test86_mh; 2400 MyValue1 test86_vt = MyValue1.createWithFieldsInline(rI, rL); 2401 2402 @Test 2403 public int test86() throws Throwable { 2404 return (int)test86_mh.invokeExact(this, test86_vt); 2405 } 2406 2407 @DontCompile 2408 public void test86_verifier(boolean warmup) throws Throwable { 2409 int i = test86(); 2410 Asserts.assertEQ(i, test86_vt.x); 2411 } 2412 2413 static { 2414 try { 2415 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2416 2417 MethodType test85_mt1 = MethodType.fromMethodDescriptorString("(Qcompiler/valhalla/valuetypes/MyValue1;)I", ValueTypeTestBench.class.getClassLoader()); 2418 MethodType test85_mt2 = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue1;", ValueTypeTestBench.class.getClassLoader()); 2419 MethodHandle test85_mh1 = lookup.findStatic(ValueTypeTestBench.class, "test85_helper1", test85_mt1); 2420 MethodHandle test85_mh2 = lookup.findStatic(ValueTypeTestBench.class, "test85_helper2", test85_mt2); 2421 test85_mh = MethodHandles.filterReturnValue(test85_mh2, test85_mh1); 2422 2423 MethodType test86_mt = MethodType.fromMethodDescriptorString("(Qcompiler/valhalla/valuetypes/MyValue1;)I", ValueTypeTestBench.class.getClassLoader()); 2424 test86_mh = lookup.findVirtual(ValueTypeTestBench.class, "test86_target", test86_mt); 2425 } catch (NoSuchMethodException|IllegalAccessException e) { 2426 throw new RuntimeException("method handle lookup fails"); 2427 } 2428 } 2429 2430 static MyValue3 staticVal3; 2431 static MyValue3 staticVal3_copy; 2432 2433 // Check elimination of redundant value type allocations 2434 @Test(match = {ALLOC}, matchCount = {1}) 2435 public MyValue3 test87(MyValue3[] va) { 2436 // Create value type and force allocation 2437 MyValue3 vt = MyValue3.create(); 2438 va[0] = vt; 2439 staticVal3 = vt; 2440 vt.verify(staticVal3); 2441 2442 // Value type is now allocated, make a copy and force allocation. 2443 // Because copy is equal to vt, C2 should remove this redundant allocation. 2444 MyValue3 copy = MyValue3.setC(vt, vt.c); 2445 va[0] = copy; 2446 staticVal3_copy = copy; 2447 copy.verify(staticVal3_copy); 2448 return copy; 2449 } 2450 2451 @DontCompile 2452 public void test87_verifier(boolean warmup) { 2453 MyValue3[] va = new MyValue3[1]; 2454 MyValue3 vt = test87(va); 2455 staticVal3.verify(vt); 2456 staticVal3.verify(va[0]); 2457 staticVal3_copy.verify(vt); 2458 staticVal3_copy.verify(va[0]); 2459 } 2460 2461 // Verify that only dominating allocations are re-used 2462 @Test() 2463 public MyValue3 test88(boolean warmup) { 2464 MyValue3 vt = MyValue3.create(); 2465 if (warmup) { 2466 staticVal3 = vt; // Force allocation 2467 } 2468 // Force allocation to verify that above 2469 // non-dominating allocation is not re-used 2470 MyValue3 copy = MyValue3.setC(vt, vt.c); 2471 staticVal3_copy = copy; 2472 copy.verify(vt); 2473 return copy; 2474 } 2475 2476 @DontCompile 2477 public void test88_verifier(boolean warmup) { 2478 MyValue3 vt = test88(warmup); 2479 if (warmup) { 2480 staticVal3.verify(vt); 2481 } 2482 } 2483 2484 // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations 2485 @Test(failOn = ALLOC + ALLOCA + STORE) 2486 public MyValue3 test89(MyValue3[] va) { 2487 // C2 can re-use the oop of staticVal3 because staticVal3 is equal to copy 2488 MyValue3 copy = MyValue3.copy(staticVal3); 2489 va[0] = copy; 2490 staticVal3 = copy; 2491 copy.verify(staticVal3); 2492 return copy; 2493 } 2494 2495 @DontCompile 2496 public void test89_verifier(boolean warmup) { 2497 staticVal3 = MyValue3.create(); 2498 MyValue3[] va = new MyValue3[1]; 2499 MyValue3 vt = test89(va); 2500 staticVal3.verify(vt); 2501 staticVal3.verify(va[0]); 2502 } 2503 2504 // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations 2505 @Test(valid = ValueTypeReturnedAsFieldsOff, failOn = ALLOC + ALLOCA + STORE) 2506 @Test(valid = ValueTypeReturnedAsFieldsOn) 2507 public MyValue3 test90(MyValue3[] va) { 2508 // C2 can re-use the oop returned by createDontInline() 2509 // because the corresponding value type is equal to 'copy'. 2510 MyValue3 copy = MyValue3.copy(MyValue3.createDontInline()); 2511 va[0] = copy; 2512 staticVal3 = copy; 2513 copy.verify(staticVal3); 2514 return copy; 2515 } 2516 2517 @DontCompile 2518 public void test90_verifier(boolean warmup) { 2519 MyValue3[] va = new MyValue3[1]; 2520 MyValue3 vt = test90(va); 2521 staticVal3.verify(vt); 2522 staticVal3.verify(va[0]); 2523 } 2524 2525 // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations 2526 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + ALLOCA + STORE) 2527 @Test(valid = ValueTypePassFieldsAsArgsOn) 2528 public MyValue3 test91(MyValue3 vt, MyValue3[] va) { 2529 // C2 can re-use the oop of vt because vt is equal to 'copy'. 2530 MyValue3 copy = MyValue3.copy(vt); 2531 va[0] = copy; 2532 staticVal3 = copy; 2533 copy.verify(staticVal3); 2534 return copy; 2535 } 2536 2537 @DontCompile 2538 public void test91_verifier(boolean warmup) { 2539 MyValue3 vt = MyValue3.create(); 2540 MyValue3[] va = new MyValue3[1]; 2541 MyValue3 result = test91(vt, va); 2542 staticVal3.verify(vt); 2543 va[0].verify(vt); 2544 result.verify(vt); 2545 } 2546 2547 // Test correct identification of value type copies 2548 @Test() 2549 public MyValue3 test92(MyValue3[] va) { 2550 MyValue3 vt = MyValue3.copy(staticVal3); 2551 vt = MyValue3.setI(vt, (int)vt.c); 2552 // vt is not equal to staticVal3, so C2 should not re-use the oop 2553 va[0] = vt; 2554 staticVal3 = vt; 2555 vt.verify(staticVal3); 2556 return vt; 2557 } 2558 2559 @DontCompile 2560 public void test92_verifier(boolean warmup) { 2561 staticVal3 = MyValue3.create(); 2562 MyValue3[] va = new MyValue3[1]; 2563 MyValue3 vt = test92(va); 2564 Asserts.assertEQ(staticVal3.i, (int)staticVal3.c); 2565 Asserts.assertEQ(va[0].i, (int)staticVal3.c); 2566 Asserts.assertEQ(vt.i, (int)staticVal3.c); 2567 } 2568 2569 // Test correct handling of __Value merges through PhiNodes 2570 @Test() 2571 public long test93() throws Throwable { 2572 // Create a new value type 2573 final MethodHandle dvt = MethodHandleBuilder.loadCode(MethodHandles.lookup(), "createValueType", 2574 MethodType.methodType(ValueType.forClass(ValueCapableClass1.class).valueClass()), 2575 CODE -> { 2576 CODE. 2577 iconst_1(). 2578 anewarray(ValueType.forClass(ValueCapableClass1.class).valueClass()). 2579 iconst_0(). 2580 vaload(). 2581 vreturn(); 2582 }); 2583 // Box the value type 2584 final MethodHandle box = MethodHandleBuilder.loadCode(MethodHandles.lookup(), "boxValueType", 2585 MethodType.methodType(ValueCapableClass1.class, ValueType.forClass(ValueCapableClass1.class).valueClass()), 2586 CODE -> { 2587 CODE. 2588 vload(0). 2589 vbox(ValueCapableClass1.class). 2590 areturn(); 2591 }); 2592 long result = 0; 2593 for (int i = 0; i < 10_000; ++i) { 2594 // Merge __Value (ValueCapableClass1) from the two GWT branches, box to the VCC and access field 2595 MethodHandle gwt = MethodHandles.guardWithTest(MethodHandles.constant(boolean.class, i % 2 == 0), dvt, dvt); 2596 ValueCapableClass1 vcc = (ValueCapableClass1) MethodHandles.filterReturnValue(gwt, box).invokeExact(); 2597 result += vcc.t; 2598 } 2599 return result; 2600 } 2601 2602 @DontCompile 2603 public void test93_verifier(boolean warmup) throws Throwable { 2604 long result = test93(); 2605 Asserts.assertEQ(result, 0L); 2606 } 2607 2608 // Test correctness of the Class::isAssignableFrom intrinsic 2609 @Test() 2610 public boolean test94(Class<?> supercls, Class<?> subcls) { 2611 return supercls.isAssignableFrom(subcls); 2612 } 2613 2614 public void test94_verifier(boolean warmup) { 2615 Asserts.assertTrue(test94(__Value.class, MyValue1.class), "test94_1 failed"); 2616 Asserts.assertTrue(test94(MyValue1.class, MyValue1.class), "test94_2 failed"); 2617 Asserts.assertTrue(test94(Object.class, java.util.ArrayList.class), "test94_3 failed"); 2618 Asserts.assertTrue(test94(java.util.ArrayList.class, java.util.ArrayList.class), "test94_4 failed"); 2619 Asserts.assertTrue(!test94(Object.class, MyValue1.class), "test94_5 failed"); 2620 Asserts.assertTrue(!test94(__Value.class, java.util.ArrayList.class), "test94_6 failed"); 2621 } 2622 2623 // Verify that Class::isAssignableFrom checks with statically known classes are folded 2624 @Test(failOn = LOADK) 2625 public boolean test95() { 2626 boolean check1 = java.util.AbstractList.class.isAssignableFrom(java.util.ArrayList.class); 2627 boolean check2 = MyValue1.class.isAssignableFrom(MyValue1.class); 2628 boolean check3 = Object.class.isAssignableFrom(java.util.ArrayList.class); 2629 boolean check4 = java.lang.__Value.class.isAssignableFrom(MyValue1.class); 2630 boolean check5 = !Object.class.isAssignableFrom(MyValue1.class); 2631 boolean check6 = !MyValue1.class.isAssignableFrom(Object.class); 2632 return check1 && check2 && check3 && check4 && check5 && check6; 2633 } 2634 2635 public void test95_verifier(boolean warmup) { 2636 Asserts.assertTrue(test95(), "test95 failed"); 2637 } 2638 2639 // Test correctness of the Class::getSuperclass intrinsic 2640 @Test() 2641 public Class<?> test96(Class<?> cls) { 2642 return cls.getSuperclass(); 2643 } 2644 2645 public void test96_verifier(boolean warmup) { 2646 Asserts.assertTrue(test96(__Value.class) == null, "test94_1 failed"); 2647 Asserts.assertTrue(test96(Object.class) == null, "test94_2 failed"); 2648 Asserts.assertTrue(test96(MyValue1.class) == __Value.class, "test94_3 failed"); 2649 Asserts.assertTrue(test96(Class.class) == Object.class, "test94_4 failed"); 2650 } 2651 2652 // Verify that Class::getSuperclass checks with statically known classes are folded 2653 @Test(failOn = LOADK) 2654 public boolean test97() { 2655 boolean check1 = __Value.class.getSuperclass() == null; 2656 boolean check2 = Object.class.getSuperclass() == null; 2657 boolean check3 = MyValue1.class.getSuperclass() == __Value.class; 2658 boolean check4 = Class.class.getSuperclass() == Object.class; 2659 return check1 && check2 && check3 && check4; 2660 } 2661 2662 public void test97_verifier(boolean warmup) { 2663 Asserts.assertTrue(test97(), "test97 failed"); 2664 } 2665 2666 // Test Class::cast intrinsic 2667 @Test() 2668 public Object test98(Class<?> cls, Object o) throws ClassCastException { 2669 return cls.cast(o); 2670 } 2671 2672 public void test98_verifier(boolean warmup) { 2673 try { 2674 test98(ValueCapableClass1.class, vcc); 2675 } catch (ClassCastException e) { 2676 throw new RuntimeException("test98_1 failed"); 2677 } 2678 try { 2679 test98(__Value.class, new Object()); 2680 throw new RuntimeException("test98_2 failed"); 2681 } catch (ClassCastException e) { 2682 // Expected 2683 } 2684 } 2685 2686 // method handle combinators 2687 static { 2688 try { 2689 MethodHandles.Lookup lookup = MethodHandles.lookup(); 2690 2691 MethodType test99_mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue3;", ValueTypeTestBench.class.getClassLoader()); 2692 MethodHandle test99_mh1 = lookup.findVirtual(ValueTypeTestBench.class, "test99_target1", test99_mt); 2693 MethodHandle test99_mh2 = lookup.findVirtual(ValueTypeTestBench.class, "test99_target2", test99_mt); 2694 MethodType boolean_mt = MethodType.methodType(boolean.class); 2695 MethodHandle test99_mh_test = lookup.findVirtual(ValueTypeTestBench.class, "test99_test", boolean_mt); 2696 test99_mh = MethodHandles.guardWithTest(test99_mh_test, test99_mh1, test99_mh2); 2697 2698 MethodType myvalue2_mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue2;", ValueTypeTestBench.class.getClassLoader()); 2699 test100_mh1 = lookup.findStatic(ValueTypeTestBench.class, "test100_target1", myvalue2_mt); 2700 MethodHandle test100_mh2 = lookup.findStatic(ValueTypeTestBench.class, "test100_target2", myvalue2_mt); 2701 MethodHandle test100_mh_test = lookup.findStatic(ValueTypeTestBench.class, "test100_test", boolean_mt); 2702 test100_mh = MethodHandles.guardWithTest(test100_mh_test, 2703 MethodHandles.invoker(myvalue2_mt), 2704 MethodHandles.dropArguments(test100_mh2, 0, MethodHandle.class)); 2705 2706 MethodHandle test101_mh1 = lookup.findStatic(ValueTypeTestBench.class, "test101_target1", myvalue2_mt); 2707 test101_mh2 = lookup.findStatic(ValueTypeTestBench.class, "test101_target2", myvalue2_mt); 2708 MethodHandle test101_mh_test = lookup.findStatic(ValueTypeTestBench.class, "test101_test", boolean_mt); 2709 test101_mh = MethodHandles.guardWithTest(test101_mh_test, 2710 MethodHandles.dropArguments(test101_mh1, 0, MethodHandle.class), 2711 MethodHandles.invoker(myvalue2_mt)); 2712 2713 MethodHandle test102_count = MethodHandles.constant(int.class, 100); 2714 ValueType<?> test102_VT = ValueType.forClass(ValueCapableClass2.class); 2715 MethodHandle test102_init = test102_VT.defaultValueConstant(); 2716 MethodHandle test102_getfield = test102_VT.findGetter(lookup, "u", long.class); 2717 MethodHandle test102_add = lookup.findStatic(Long.class, "sum", MethodType.methodType(long.class, long.class, long.class)); 2718 MethodHandle test102_body = MethodHandles.collectArguments(ValueCapableClass2.FACTORY, 2719 0, 2720 MethodHandles.dropArguments(MethodHandles.collectArguments(MethodHandles.insertArguments(test102_add, 2721 0, 2722 1L), 2723 0, 2724 test102_getfield), 2725 1, 2726 int.class)); 2727 test102_mh = MethodHandles.collectArguments(test102_getfield, 2728 0, 2729 MethodHandles.countedLoop(test102_count, test102_init, test102_body)); 2730 2731 MethodType test103_mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue3;", ValueTypeTestBench.class.getClassLoader()); 2732 MethodHandle test103_mh1 = lookup.findVirtual(ValueTypeTestBench.class, "test103_target1", test103_mt); 2733 MethodHandle test103_mh2 = lookup.findVirtual(ValueTypeTestBench.class, "test103_target2", test103_mt); 2734 MethodHandle test103_mh3 = lookup.findVirtual(ValueTypeTestBench.class, "test103_target3", test103_mt); 2735 MethodType test103_mt2 = MethodType.methodType(boolean.class); 2736 MethodHandle test103_mh_test1 = lookup.findVirtual(ValueTypeTestBench.class, "test103_test1", test103_mt2); 2737 MethodHandle test103_mh_test2 = lookup.findVirtual(ValueTypeTestBench.class, "test103_test2", test103_mt2); 2738 test103_mh = MethodHandles.guardWithTest(test103_mh_test1, 2739 test103_mh1, 2740 MethodHandles.guardWithTest(test103_mh_test2, test103_mh2, test103_mh3)); 2741 2742 MethodType test104_mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue2;", ValueTypeTestBench.class.getClassLoader()); 2743 MethodHandle test104_mh1 = lookup.findStatic(ValueTypeTestBench.class, "test104_target1", test104_mt); 2744 test104_mh2 = lookup.findStatic(ValueTypeTestBench.class, "test104_target2", test104_mt); 2745 test104_mh3 = lookup.findStatic(ValueTypeTestBench.class, "test104_target3", test104_mt); 2746 MethodType test104_mt2 = MethodType.methodType(boolean.class); 2747 MethodType test104_mt3 = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue2;", ValueTypeTestBench.class.getClassLoader()); 2748 MethodHandle test104_mh_test1 = lookup.findStatic(ValueTypeTestBench.class, "test104_test1", test104_mt2); 2749 MethodHandle test104_mh_test2 = lookup.findStatic(ValueTypeTestBench.class, "test104_test2", test104_mt2); 2750 test104_mh = MethodHandles.guardWithTest(test104_mh_test1, 2751 MethodHandles.dropArguments(test104_mh1, 0, MethodHandle.class, MethodHandle.class), 2752 MethodHandles.guardWithTest(test104_mh_test2, 2753 MethodHandles.dropArguments(MethodHandles.invoker(test104_mt3), 1, MethodHandle.class), 2754 MethodHandles.dropArguments(MethodHandles.invoker(test104_mt3), 0, MethodHandle.class)) 2755 ); 2756 2757 MethodHandle test105_mh1 = lookup.findStatic(ValueTypeTestBench.class, "test105_target1", myvalue2_mt); 2758 test105_mh2 = lookup.findStatic(ValueTypeTestBench.class, "test105_target2", myvalue2_mt); 2759 MethodHandle test105_mh_test = lookup.findStatic(ValueTypeTestBench.class, "test105_test", boolean_mt); 2760 test105_mh = MethodHandles.guardWithTest(test105_mh_test, 2761 MethodHandles.dropArguments(test105_mh1, 0, MethodHandle.class), 2762 MethodHandles.invoker(myvalue2_mt)); 2763 } catch (NoSuchMethodException|IllegalAccessException|NoSuchFieldException e) { 2764 e.printStackTrace(); 2765 throw new RuntimeException("method handle lookup fails"); 2766 } 2767 } 2768 2769 // Return of target1 and target2 merged in a Lambda Form as an 2770 // __Value. Shouldn't cause any allocation 2771 final MyValue3 test99_vt1 = MyValue3.create(); 2772 @ForceInline 2773 MyValue3 test99_target1() { 2774 return test99_vt1; 2775 } 2776 2777 final MyValue3 test99_vt2 = MyValue3.create(); 2778 @ForceInline 2779 MyValue3 test99_target2() { 2780 return test99_vt2; 2781 } 2782 2783 boolean test99_bool = true; 2784 @ForceInline 2785 boolean test99_test() { 2786 return test99_bool; 2787 } 2788 2789 static final MethodHandle test99_mh; 2790 2791 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 2792 @Test(valid = ValueTypeReturnedAsFieldsOff) 2793 MyValue3 test99() throws Throwable { 2794 return (MyValue3)test99_mh.invokeExact(this); 2795 } 2796 2797 @DontCompile 2798 public void test99_verifier(boolean warmup) throws Throwable { 2799 test99_bool = !test99_bool; 2800 MyValue3 vt = test99(); 2801 vt.verify(test99_bool ? test99_vt1 : test99_vt2); 2802 } 2803 2804 // Similar as above but with the method handle for target1 not 2805 // constant. Shouldn't cause any allocation. 2806 @ForceInline 2807 static MyValue2 test100_target1() { 2808 return MyValue2.createWithFieldsInline(rI, true); 2809 } 2810 2811 @ForceInline 2812 static MyValue2 test100_target2() { 2813 return MyValue2.createWithFieldsInline(rI+1, false); 2814 } 2815 2816 static boolean test100_bool = true; 2817 @ForceInline 2818 static boolean test100_test() { 2819 return test100_bool; 2820 } 2821 2822 static final MethodHandle test100_mh; 2823 static MethodHandle test100_mh1; 2824 2825 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 2826 @Test(valid = ValueTypeReturnedAsFieldsOff) 2827 long test100() throws Throwable { 2828 return ((MyValue2)test100_mh.invokeExact(test100_mh1)).hash(); 2829 } 2830 2831 @DontCompile 2832 public void test100_verifier(boolean warmup) throws Throwable { 2833 test100_bool = !test100_bool; 2834 long hash = test100(); 2835 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+(test100_bool ? 0 : 1), test100_bool).hash()); 2836 } 2837 2838 // Same as above but with the method handle for target2 not 2839 // constant. Shouldn't cause any allocation. 2840 @ForceInline 2841 static MyValue2 test101_target1() { 2842 return MyValue2.createWithFieldsInline(rI, true); 2843 } 2844 2845 @ForceInline 2846 static MyValue2 test101_target2() { 2847 return MyValue2.createWithFieldsInline(rI+1, false); 2848 } 2849 2850 static boolean test101_bool = true; 2851 @ForceInline 2852 static boolean test101_test() { 2853 return test101_bool; 2854 } 2855 2856 static final MethodHandle test101_mh; 2857 static MethodHandle test101_mh2; 2858 2859 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 2860 @Test(valid = ValueTypeReturnedAsFieldsOff) 2861 long test101() throws Throwable { 2862 return ((MyValue2)test101_mh.invokeExact(test101_mh2)).hash(); 2863 } 2864 2865 @DontCompile 2866 public void test101_verifier(boolean warmup) throws Throwable { 2867 test101_bool = !test101_bool; 2868 long hash = test101(); 2869 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+(test101_bool ? 0 : 1), test101_bool).hash()); 2870 } 2871 2872 // Simple reduction with intermediate result merged in a Lambda 2873 // Form as an __Value. Shouldn't cause any allocations. The entire 2874 // loop should go away as the result is a constant. 2875 static final MethodHandle test102_mh; 2876 2877 @Test(failOn = ALLOC + STORE + LOOP + STOREVALUETYPEFIELDS) 2878 long test102() throws Throwable { 2879 return (long)test102_mh.invokeExact(); 2880 } 2881 2882 @DontCompile 2883 public void test102_verifier(boolean warmup) throws Throwable { 2884 long v = test102(); 2885 Asserts.assertEQ(v, 100L); 2886 } 2887 2888 // Return of target1, target2 and target3 merged in Lambda Forms 2889 // as an __Value. Shouldn't cause any allocation 2890 final MyValue3 test103_vt1 = MyValue3.create(); 2891 @ForceInline 2892 MyValue3 test103_target1() { 2893 return test103_vt1; 2894 } 2895 2896 final MyValue3 test103_vt2 = MyValue3.create(); 2897 @ForceInline 2898 MyValue3 test103_target2() { 2899 return test103_vt2; 2900 } 2901 2902 final MyValue3 test103_vt3 = MyValue3.create(); 2903 @ForceInline 2904 MyValue3 test103_target3() { 2905 return test103_vt3; 2906 } 2907 2908 boolean test103_bool1 = true; 2909 @ForceInline 2910 boolean test103_test1() { 2911 return test103_bool1; 2912 } 2913 2914 boolean test103_bool2 = true; 2915 @ForceInline 2916 boolean test103_test2() { 2917 return test103_bool2; 2918 } 2919 2920 static final MethodHandle test103_mh; 2921 2922 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 2923 @Test(valid = ValueTypeReturnedAsFieldsOff) 2924 MyValue3 test103() throws Throwable { 2925 return (MyValue3)test103_mh.invokeExact(this); 2926 } 2927 2928 static int test103_i = 0; 2929 @DontCompile 2930 public void test103_verifier(boolean warmup) throws Throwable { 2931 test103_i++; 2932 test103_bool1 = (test103_i % 2) == 0; 2933 test103_bool2 = (test103_i % 3) == 0; 2934 MyValue3 vt = test103(); 2935 vt.verify(test103_bool1 ? test103_vt1 : (test103_bool2 ? test103_vt2 : test103_vt3)); 2936 } 2937 2938 // Same as above but with non constant target2 and target3 2939 @ForceInline 2940 static MyValue2 test104_target1() { 2941 return MyValue2.createWithFieldsInline(rI, true); 2942 } 2943 2944 @ForceInline 2945 static MyValue2 test104_target2() { 2946 return MyValue2.createWithFieldsInline(rI+1, false); 2947 } 2948 2949 @ForceInline 2950 static MyValue2 test104_target3() { 2951 return MyValue2.createWithFieldsInline(rI+2, true); 2952 } 2953 2954 static boolean test104_bool1 = true; 2955 @ForceInline 2956 static boolean test104_test1() { 2957 return test104_bool1; 2958 } 2959 2960 static boolean test104_bool2 = true; 2961 @ForceInline 2962 static boolean test104_test2() { 2963 return test104_bool2; 2964 } 2965 2966 static final MethodHandle test104_mh; 2967 static MethodHandle test104_mh2; 2968 static MethodHandle test104_mh3; 2969 2970 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 2971 @Test(valid = ValueTypeReturnedAsFieldsOff) 2972 long test104() throws Throwable { 2973 return ((MyValue2)test104_mh.invokeExact(test104_mh2, test104_mh3)).hash(); 2974 } 2975 2976 static int test104_i = 0; 2977 @DontCompile 2978 public void test104_verifier(boolean warmup) throws Throwable { 2979 test104_i++; 2980 test104_bool1 = (test104_i % 2) == 0; 2981 test104_bool2 = (test104_i % 3) == 0; 2982 long hash = test104(); 2983 int i = rI+(test104_bool1 ? 0 : (test104_bool2 ? 1 : 2)); 2984 boolean b = test104_bool1 ? true : (test104_bool2 ? false : true); 2985 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(i, b).hash()); 2986 } 2987 2988 @ForceInline 2989 static MyValue2 test105_target1() { 2990 return MyValue2.createWithFieldsInline(rI+test105_i, true); 2991 } 2992 2993 @ForceInline 2994 static MyValue2 test105_target2() { 2995 return MyValue2.createWithFieldsInline(rI-test105_i, false); 2996 } 2997 2998 static int test105_i = 0; 2999 @ForceInline 3000 static boolean test105_test() { 3001 return (test105_i % 100) == 0; 3002 } 3003 3004 static final MethodHandle test105_mh; 3005 static MethodHandle test105_mh2; 3006 3007 // Check that a buffered value returned by a compiled lambda form 3008 // is properly handled by the caller. 3009 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS) 3010 @Test(valid = ValueTypeReturnedAsFieldsOff) 3011 @Warmup(11000) 3012 long test105() throws Throwable { 3013 return ((MyValue2)test105_mh.invokeExact(test105_mh2)).hash(); 3014 } 3015 3016 @DontCompile 3017 public void test105_verifier(boolean warmup) throws Throwable { 3018 test105_i++; 3019 long hash = test105(); 3020 boolean b = (test105_i % 100) == 0; 3021 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+test105_i * (b ? 1 : -1), b).hash()); 3022 } 3023 3024 // ========== Test infrastructure ========== 3025 3026 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 3027 private static final int ValueTypePassFieldsAsArgsOn = 0x1; 3028 private static final int ValueTypePassFieldsAsArgsOff = 0x2; 3029 private static final int ValueTypeArrayFlattenOn = 0x4; 3030 private static final int ValueTypeArrayFlattenOff = 0x8; 3031 private static final int ValueTypeReturnedAsFieldsOn = 0x10; 3032 private static final int ValueTypeReturnedAsFieldsOff = 0x20; 3033 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn; 3034 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 3035 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten"); 3036 private static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields"); 3037 private static final int COMP_LEVEL_ANY = -2; 3038 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 3039 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 3040 private static final int WARMUP = 251; 3041 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 3042 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 3043 private static boolean XCOMP = Platform.isComp(); 3044 3045 // Regular expressions used to match nodes in the PrintIdeal output 3046 private static final String START = "(\\d+\\t(.*"; 3047 private static final String MID = ".*)+\\t===.*"; 3048 private static final String END = ")|"; 3049 private static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END; 3050 private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END; 3051 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 3052 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END; 3053 private static final String LOADK = START + "LoadK" + MID + END; 3054 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 3055 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END; 3056 private static final String LOOP = START + "Loop" + MID + "" + END; 3057 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END; 3058 private static final String RETURN = START + "Return" + MID + "returns" + END; 3059 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END; 3060 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END; 3061 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END; 3062 private static final String CALL = START + "CallStaticJava" + MID + END; 3063 private static final String STOREVALUETYPEFIELDS = START + "CallStaticJava" + MID + "store_value_type_fields" + END; 3064 private static final String SCOBJ = "(.*# ScObj.*" + END; 3065 3066 static { 3067 // Gather all test methods and put them in Hashtable 3068 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) { 3069 Test[] annos = m.getAnnotationsByType(Test.class); 3070 if (annos.length != 0) { 3071 tests.put("ValueTypeTestBench::" + m.getName(), m); 3072 } 3073 } 3074 } 3075 3076 private static void execute_vm(String... args) throws Throwable { 3077 Asserts.assertFalse(tests.isEmpty(), "no tests to execute"); 3078 ArrayList<String> all_args = new ArrayList(List.of(args)); 3079 // Run tests in own process and verify output 3080 all_args.add(ValueTypeTestBench.class.getName()); 3081 all_args.add("run"); 3082 // Spawn process with default JVM options from the test's run command 3083 String[] vmInputArgs = InputArguments.getVmInputArgs(); 3084 String[] cmds = Arrays.copyOf(vmInputArgs, vmInputArgs.length + all_args.size()); 3085 System.arraycopy(all_args.toArray(), 0, cmds, vmInputArgs.length, all_args.size()); 3086 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); 3087 // If ideal graph printing is enabled/supported, verify output 3088 String output = oa.getOutput(); 3089 oa.shouldHaveExitValue(0); 3090 boolean verifyIR = output.contains("PrintIdeal enabled") && 3091 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform"); 3092 if (verifyIR) { 3093 parseOutput(output); 3094 } else { 3095 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); 3096 } 3097 } 3098 3099 public static void main(String[] args) throws Throwable { 3100 //tests.values().removeIf(p -> !p.getName().equals("test104")); // Run single test 3101 if (args.length == 0) { 3102 execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation", 3103 "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly", 3104 "-XX:CICompilerCount=1", 3105 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*", 3106 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", 3107 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*", 3108 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue3::*", 3109 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue4::*", 3110 "-XX:CompileCommand=compileonly,java.lang.Object::<init>", 3111 "-XX:CompileCommand=inline,java.lang.__Value::hashCode", 3112 "-XX:CompileCommand=compileonly,java.lang.invoke.*::*", 3113 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueCapableClass2_*::*", 3114 "-XX:CompileCommand=compileonly,java.lang.Long::sum"); 3115 } else { 3116 // Execute tests 3117 ValueTypeTestBench bench = new ValueTypeTestBench(); 3118 bench.run(); 3119 } 3120 } 3121 3122 public static void parseOutput(String output) throws Exception { 3123 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"); 3124 Matcher m = comp_re.matcher(output); 3125 Map<String,String> compilations = new LinkedHashMap<>(); 3126 int prev = 0; 3127 String methodName = null; 3128 while (m.find()) { 3129 if (prev == 0) { 3130 // Print header 3131 System.out.print(output.substring(0, m.start()+1)); 3132 } else if (methodName != null) { 3133 compilations.put(methodName, output.substring(prev, m.start()+1)); 3134 } 3135 if (m.group("osr") != null) { 3136 methodName = null; 3137 } else { 3138 methodName = m.group("name"); 3139 } 3140 prev = m.end(); 3141 } 3142 if (prev == 0) { 3143 // Print header 3144 System.out.print(output); 3145 } else if (methodName != null) { 3146 compilations.put(methodName, output.substring(prev)); 3147 } 3148 // Iterate over compilation output 3149 for (String testName : compilations.keySet()) { 3150 Method test = tests.get(testName); 3151 if (test == null) { 3152 // Skip helper methods 3153 continue; 3154 } 3155 String graph = compilations.get(testName); 3156 if (PRINT_GRAPH) { 3157 System.out.println("\nGraph for " + testName + "\n" + graph); 3158 } 3159 // Parse graph using regular expressions to determine if it contains forbidden nodes 3160 Test[] annos = test.getAnnotationsByType(Test.class); 3161 Test anno = null; 3162 for (Test a : annos) { 3163 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 3164 assert anno == null; 3165 anno = a; 3166 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 3167 assert anno == null; 3168 anno = a; 3169 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 3170 assert anno == null; 3171 anno = a; 3172 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 3173 assert anno == null; 3174 anno = a; 3175 } else if ((a.valid() & ValueTypeReturnedAsFieldsOn) != 0 && ValueTypeReturnedAsFields) { 3176 assert anno == null; 3177 anno = a; 3178 } else if ((a.valid() & ValueTypeReturnedAsFieldsOff) != 0 && !ValueTypeReturnedAsFields) { 3179 assert anno == null; 3180 anno = a; 3181 } 3182 } 3183 assert anno != null; 3184 String regexFail = anno.failOn(); 3185 if (!regexFail.isEmpty()) { 3186 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 3187 Matcher matcher = pattern.matcher(graph); 3188 boolean found = matcher.find(); 3189 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 3190 } 3191 String[] regexMatch = anno.match(); 3192 int[] matchCount = anno.matchCount(); 3193 for (int i = 0; i < regexMatch.length; ++i) { 3194 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 3195 Matcher matcher = pattern.matcher(graph); 3196 int count = 0; 3197 String nodes = ""; 3198 while (matcher.find()) { 3199 count++; 3200 nodes += matcher.group() + "\n"; 3201 } 3202 if (matchCount[i] < 0) { 3203 Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 3204 } else { 3205 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 3206 } 3207 } 3208 tests.remove(testName); 3209 System.out.println(testName + " passed"); 3210 } 3211 // Check if all tests were compiled 3212 if (tests.size() != 0) { 3213 for (String name : tests.keySet()) { 3214 System.out.println("Test '" + name + "' not compiled!"); 3215 } 3216 throw new RuntimeException("Not all tests were compiled"); 3217 } 3218 } 3219 3220 public void setup(Method[] methods) { 3221 if (XCOMP) { 3222 // Don't control compilation if -Xcomp is enabled 3223 return; 3224 } 3225 for (Method m : methods) { 3226 if (m.isAnnotationPresent(Test.class)) { 3227 // Don't inline tests 3228 WHITE_BOX.testSetDontInlineMethod(m, true); 3229 } 3230 if (m.isAnnotationPresent(DontCompile.class)) { 3231 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 3232 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 3233 WHITE_BOX.testSetDontInlineMethod(m, true); 3234 } 3235 if (m.isAnnotationPresent(ForceInline.class)) { 3236 WHITE_BOX.testSetForceInlineMethod(m, true); 3237 } else if (m.isAnnotationPresent(DontInline.class)) { 3238 WHITE_BOX.testSetDontInlineMethod(m, true); 3239 } 3240 } 3241 } 3242 3243 public void run() throws Exception { 3244 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 3245 System.out.println("PrintIdeal enabled"); 3246 } 3247 System.out.format("rI = %d, rL = %d\n", rI, rL); 3248 setup(this.getClass().getDeclaredMethods()); 3249 setup(MyValue1.class.getDeclaredMethods()); 3250 setup(MyValue2.class.getDeclaredMethods()); 3251 setup(MyValue3.class.getDeclaredMethods()); 3252 setup(MyValue4.class.getDeclaredMethods()); 3253 3254 // Compile class initializers 3255 WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION); 3256 WHITE_BOX.enqueueInitializerForCompilation(MyValue1.class, COMP_LEVEL_FULL_OPTIMIZATION); 3257 WHITE_BOX.enqueueInitializerForCompilation(MyValue2.class, COMP_LEVEL_FULL_OPTIMIZATION); 3258 WHITE_BOX.enqueueInitializerForCompilation(MyValue3.class, COMP_LEVEL_FULL_OPTIMIZATION); 3259 WHITE_BOX.enqueueInitializerForCompilation(MyValue4.class, COMP_LEVEL_FULL_OPTIMIZATION); 3260 3261 // Execute tests 3262 for (Method test : tests.values()) { 3263 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class); 3264 // Warmup using verifier method 3265 Warmup anno = test.getAnnotation(Warmup.class); 3266 int warmup = anno == null ? WARMUP : anno.value(); 3267 for (int i = 0; i < warmup; ++i) { 3268 verifier.invoke(this, true); 3269 } 3270 // Trigger compilation 3271 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION); 3272 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 3273 // Check result 3274 verifier.invoke(this, false); 3275 } 3276 } 3277 } 3278 3279 // Mark method as test 3280 @Retention(RetentionPolicy.RUNTIME) 3281 @Repeatable(Tests.class) 3282 @interface Test { 3283 // Regular expression used to match forbidden IR nodes 3284 // in the C2 IR emitted for this test. 3285 String failOn() default ""; 3286 // Regular expressions used to match and count IR nodes. 3287 String[] match() default { }; 3288 int[] matchCount() default { }; 3289 int valid() default ValueTypeTestBench.AllFlags; 3290 } 3291 3292 @Retention(RetentionPolicy.RUNTIME) 3293 @interface Tests { 3294 Test[] value(); 3295 } 3296 3297 // Force method inlining during compilation 3298 @Retention(RetentionPolicy.RUNTIME) 3299 @interface ForceInline { } 3300 3301 // Prevent method inlining during compilation 3302 @Retention(RetentionPolicy.RUNTIME) 3303 @interface DontInline { } 3304 3305 // Prevent method compilation 3306 @Retention(RetentionPolicy.RUNTIME) 3307 @interface DontCompile { } 3308 3309 @Retention(RetentionPolicy.RUNTIME) 3310 @interface Warmup { 3311 int value(); 3312 }