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