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