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