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