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:+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:-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:+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.List; 71 import java.util.regex.Matcher; 72 import java.util.regex.Pattern; 73 import jdk.experimental.value.*; 74 75 // Test value types 76 __ByValue final class MyValue1 { 77 static int s; 78 static final long sf = ValueTypeTestBench.rL; 79 final int x; 80 final long y; 81 final short z; 82 final Integer o; 83 final int[] oa; 84 final MyValue2 v1; 85 final MyValue2 v2; 86 static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true); 87 final int c; 88 89 private MyValue1(int x, long y, short z, Integer o, int[] oa, MyValue2 v1, MyValue2 v2, int c) { 90 s = x; 91 this.x = x; 92 this.y = y; 93 this.z = z; 94 this.o = o; 95 this.oa = oa; 96 this.v1 = v1; 97 this.v2 = v2; 98 this.c = c; 99 } 100 101 private MyValue1() { 102 s = 0; 103 this.x = 0; 104 this.y = 0; 105 this.z = 0; 106 this.o = null; 107 this.oa = null; 108 this.v1 = MyValue2.createDefaultInline(); 109 this.v2 = MyValue2.createDefaultInline(); 110 this.c = 0; 111 } 112 113 @DontInline 114 __ValueFactory static MyValue1 createDefaultDontInline() { 115 return __MakeDefault MyValue1(); 116 } 117 118 @ForceInline 119 __ValueFactory static MyValue1 createDefaultInline() { 120 return __MakeDefault MyValue1(); 121 } 122 123 @DontInline 124 static MyValue1 createWithFieldsDontInline(int x, long y) { 125 MyValue1 v = createDefaultInline(); 126 v = setX(v, x); 127 v = setY(v, y); 128 v = setZ(v, (short)x); 129 v = setO(v, new Integer(x)); 130 int[] oa = {x}; 131 v = setOA(v, oa); 132 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y)); 133 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y)); 134 v = setC(v, ValueTypeTestBench.rI); 135 return v; 136 } 137 138 @ForceInline 139 static MyValue1 createWithFieldsInline(int x, long y) { 140 MyValue1 v = createDefaultInline(); 141 v = setX(v, x); 142 v = setY(v, y); 143 v = setZ(v, (short)x); 144 v = setO(v, new Integer(x)); 145 int[] oa = {x}; 146 v = setOA(v, oa); 147 v = setV1(v, MyValue2.createWithFieldsInline(x, x < y)); 148 v = setV2(v, MyValue2.createWithFieldsInline(x, x > y)); 149 v = setC(v, ValueTypeTestBench.rI); 150 return v; 151 } 152 153 // Hash only primitive and value type fields to avoid NullPointerException 154 @ForceInline 155 public long hashPrimitive() { 156 return s + sf + x + y + z + c + v1.hash() + v2.hash() + v3.hash(); 157 } 158 159 @ForceInline 160 public long hash() { 161 return hashPrimitive() + o + oa[0]; 162 } 163 164 @DontCompile 165 public long hashInterpreted() { 166 return s + sf + x + y + z + o + oa[0] + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted(); 167 } 168 169 @ForceInline 170 public void print() { 171 System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", z=" + z + ", o=" + (o != null ? (Integer)o : "NULL") + ", v1["); 172 v1.print(); 173 System.out.print("], v2["); 174 v2.print(); 175 System.out.print("], v3["); 176 v3.print(); 177 System.out.print("], c=" + c); 178 } 179 180 @ForceInline 181 __ValueFactory static MyValue1 setX(MyValue1 v, int x) { 182 v.x = x; 183 return v; 184 } 185 186 @ForceInline 187 __ValueFactory static MyValue1 setY(MyValue1 v, long y) { 188 v.y = y; 189 return v; 190 } 191 192 @ForceInline 193 __ValueFactory static MyValue1 setZ(MyValue1 v, short z) { 194 v.z = z; 195 return v; 196 } 197 198 @ForceInline 199 __ValueFactory static MyValue1 setO(MyValue1 v, Integer o) { 200 v.o = o; 201 return v; 202 } 203 204 @ForceInline 205 __ValueFactory static MyValue1 setOA(MyValue1 v, int[] oa) { 206 v.oa = oa; 207 return v; 208 } 209 210 @ForceInline 211 __ValueFactory static MyValue1 setC(MyValue1 v, int c) { 212 v.c = c; 213 return v; 214 } 215 216 @ForceInline 217 __ValueFactory static MyValue1 setV1(MyValue1 v, MyValue2 v1) { 218 v.v1 = v1; 219 return v; 220 } 221 222 @ForceInline 223 __ValueFactory static MyValue1 setV2(MyValue1 v, MyValue2 v2) { 224 v.v2 = v2; 225 return v; 226 } 227 } 228 229 __ByValue final class MyValue2 { 230 final int x; 231 final byte y; 232 final boolean b; 233 final long c; 234 235 private MyValue2(int x, byte y, boolean b, long c) { 236 this.x = x; 237 this.y = y; 238 this.b = b; 239 this.c = c; 240 } 241 242 private MyValue2() { 243 this.x = 0; 244 this.y = 0; 245 this.b = false; 246 this.c = 0; 247 } 248 249 @ForceInline 250 __ValueFactory public static MyValue2 createDefaultInline() { 251 return __MakeDefault MyValue2(); 252 } 253 254 @ForceInline 255 public static MyValue2 createWithFieldsInline(int x, boolean b) { 256 MyValue2 v = createDefaultInline(); 257 v = setX(v, x); 258 v = setY(v, (byte)x); 259 v = setB(v, b); 260 v = setC(v, ValueTypeTestBench.rL); 261 return v; 262 } 263 264 @ForceInline 265 public long hash() { 266 return x + y + (b ? 0 : 1) + c; 267 } 268 269 @DontInline 270 public long hashInterpreted() { 271 return x + y + (b ? 0 : 1) + c; 272 } 273 274 @ForceInline 275 public void print() { 276 System.out.print("x=" + x + "y=" + y + ", b=" + b + ", c=" + c); 277 } 278 279 @ForceInline 280 __ValueFactory static MyValue2 setX(MyValue2 v, int x) { 281 v.x = x; 282 return v; 283 } 284 285 @ForceInline 286 __ValueFactory static MyValue2 setY(MyValue2 v, byte y) { 287 v.y = y; 288 return v; 289 } 290 291 @ForceInline 292 __ValueFactory static MyValue2 setC(MyValue2 v, long c) { 293 v.c = c; 294 return v; 295 } 296 297 @ForceInline 298 __ValueFactory static MyValue2 setB(MyValue2 v, boolean b) { 299 v.b = b; 300 return v; 301 } 302 } 303 304 public class ValueTypeTestBench { 305 // Print ideal graph after execution of each test 306 private static final boolean PRINT_GRAPH = true; 307 308 // Random test values 309 public static final int rI = Utils.getRandomInstance().nextInt() % 1000; 310 public static final long rL = Utils.getRandomInstance().nextLong() % 1000; 311 312 public ValueTypeTestBench() { 313 val3 = MyValue1.createWithFieldsInline(rI, rL); 314 } 315 316 // MethodHandles and value-capable class instance needed for testing vbox/vunbox 317 private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH(); 318 private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH(); 319 private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH(); 320 private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH(); 321 private static final MethodHandle nullvccUnboxLoadLongMH = generateNullVCCUnboxLoadLongMH(); 322 private static final MethodHandle objectUnboxLoadLongMH = generateObjectUnboxLoadLongMH(); 323 private static final MethodHandle objectBoxMH = generateObjectBoxMH(); 324 private static final MethodHandle checkedvccUnboxLoadLongMH = generateCheckedVCCUnboxLoadLongMH(); 325 326 private static final ValueCapableClass1 vcc = ValueCapableClass1.create(rL, rI, (short)rI, (short)rI); 327 private static final ValueCapableClass2 vcc2 = ValueCapableClass2.create(rL + 1); 328 329 // ========== Helper methods ========== 330 331 public long hash() { 332 return hash(rI, rL); 333 } 334 335 public long hash(int x, long y) { 336 return MyValue1.createWithFieldsInline(x, y).hash(); 337 } 338 339 // ========== Test definitions ========== 340 341 // Receive value type through call to interpreter 342 @Test(failOn = ALLOC + STORE + TRAP) 343 public long test1() { 344 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 345 return v.hash(); 346 } 347 348 @DontCompile 349 public void test1_verifier(boolean warmup) { 350 long result = test1(); 351 Asserts.assertEQ(result, hash()); 352 } 353 354 // Receive value type from interpreter via parameter 355 @Test(failOn = ALLOC + STORE + TRAP) 356 public long test2(MyValue1 v) { 357 return v.hash(); 358 } 359 360 @DontCompile 361 public void test2_verifier(boolean warmup) { 362 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 363 long result = test2(v); 364 Asserts.assertEQ(result, hash()); 365 } 366 367 // Return incoming value type without accessing fields 368 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 11}, failOn = LOAD + TRAP) 369 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP) 370 public MyValue1 test3(MyValue1 v) { 371 return v; 372 } 373 374 @DontCompile 375 public void test3_verifier(boolean warmup) { 376 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 377 MyValue1 v2 = test3(v1); 378 Asserts.assertEQ(v1.x, v2.x); 379 Asserts.assertEQ(v1.y, v2.y); 380 } 381 382 // Create a value type in compiled code and only use fields. 383 // Allocation should go away because value type does not escape. 384 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 385 public long test4() { 386 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 387 return v.hash(); 388 } 389 390 @DontCompile 391 public void test4_verifier(boolean warmup) { 392 long result = test4(); 393 Asserts.assertEQ(result, hash()); 394 } 395 396 // Create a value type in compiled code and pass it to 397 // an inlined compiled method via a call. 398 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 399 public long test5() { 400 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 401 return test5Inline(v); 402 } 403 404 @ForceInline 405 public long test5Inline(MyValue1 v) { 406 return v.hash(); 407 } 408 409 @DontCompile 410 public void test5_verifier(boolean warmup) { 411 long result = test5(); 412 Asserts.assertEQ(result, hash()); 413 } 414 415 // Create a value type in compiled code and pass it to 416 // the interpreter via a call. 417 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC) 418 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 419 public long test6() { 420 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 421 // Pass to interpreter 422 return v.hashInterpreted(); 423 } 424 425 @DontCompile 426 public void test6_verifier(boolean warmup) { 427 long result = test6(); 428 Asserts.assertEQ(result, hash()); 429 } 430 431 // Create a value type in compiled code and pass it to 432 // the interpreter by returning. 433 @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 434 public MyValue1 test7(int x, long y) { 435 return MyValue1.createWithFieldsInline(x, y); 436 } 437 438 @DontCompile 439 public void test7_verifier(boolean warmup) { 440 MyValue1 v = test7(rI, rL); 441 Asserts.assertEQ(v.hash(), hash()); 442 } 443 444 // Merge value types created from two branches 445 @Test(failOn = ALLOC + STORE + TRAP) 446 public long test8(boolean b) { 447 MyValue1 v; 448 if (b) { 449 v = MyValue1.createWithFieldsInline(rI, rL); 450 } else { 451 v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1); 452 } 453 return v.hash(); 454 } 455 456 @DontCompile 457 public void test8_verifier(boolean warmup) { 458 Asserts.assertEQ(test8(true), hash()); 459 Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1)); 460 } 461 462 // Merge value types created from two branches 463 @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {10}, failOn = TRAP + ALLOC + STORE) 464 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP) 465 public MyValue1 test9(boolean b) { 466 MyValue1 v; 467 if (b) { 468 // Value type is not allocated 469 v = MyValue1.createWithFieldsInline(rI, rL); 470 } else { 471 // Value type is allocated by the callee 472 v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1); 473 } 474 // Need to allocate value type if 'b' is true 475 long sum = v.hashInterpreted(); 476 if (b) { 477 v = MyValue1.createWithFieldsDontInline(rI, sum); 478 } else { 479 v = MyValue1.createWithFieldsDontInline(rI, sum + 1); 480 } 481 // Don't need to allocate value type because both branches allocate 482 return v; 483 } 484 485 @DontCompile 486 public void test9_verifier(boolean warmup) { 487 MyValue1 v = test9(true); 488 Asserts.assertEQ(v.x, rI); 489 Asserts.assertEQ(v.y, hash()); 490 v = test9(false); 491 Asserts.assertEQ(v.x, rI); 492 Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1); 493 } 494 495 // Merge value types created in a loop (not inlined) 496 @Test(failOn = ALLOC + STORE + TRAP) 497 public long test10(int x, long y) { 498 MyValue1 v = MyValue1.createWithFieldsDontInline(x, y); 499 for (int i = 0; i < 10; ++i) { 500 v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1); 501 } 502 return v.hash(); 503 } 504 505 @DontCompile 506 public void test10_verifier(boolean warmup) { 507 long result = test10(rI, rL); 508 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 509 } 510 511 // Merge value types created in a loop (inlined) 512 @Test(failOn = ALLOC + LOAD + STORE + TRAP) 513 public long test11(int x, long y) { 514 MyValue1 v = MyValue1.createWithFieldsInline(x, y); 515 for (int i = 0; i < 10; ++i) { 516 v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1); 517 } 518 return v.hash(); 519 } 520 521 @DontCompile 522 public void test11_verifier(boolean warmup) { 523 long result = test11(rI, rL); 524 Asserts.assertEQ(result, hash(rI + 10, rL + 10)); 525 } 526 527 // Test loop with uncommon trap referencing a value type 528 @Test(match = {TRAP, SCOBJ}, matchCount = {1, -1 /* at least 1 */}, failOn = LOAD) 529 public long test12(boolean b) { 530 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 531 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 532 for (int i = 0; i < va.length; ++i) { 533 va[i] = MyValue1.createWithFieldsInline(rI, rL); 534 } 535 long result = rL; 536 for (int i = 0; i < 1000; ++i) { 537 if (b) { 538 result += v.x; 539 } else { 540 // Uncommon trap referencing v. We delegate allocation to the 541 // interpreter by adding a SafePointScalarObjectNode. 542 result = v.hashInterpreted(); 543 for (int j = 0; j < va.length; ++j) { 544 result += va[j].hash(); 545 } 546 } 547 } 548 return result; 549 } 550 551 @DontCompile 552 public void test12_verifier(boolean warmup) { 553 long result = test12(warmup); 554 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 555 } 556 557 // Test loop with uncommon trap referencing a value type 558 @Test(match = {TRAP}, matchCount = {1}) 559 public long test13(boolean b) { 560 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 561 MyValue1[] va = new MyValue1[Math.abs(rI) % 10]; 562 for (int i = 0; i < va.length; ++i) { 563 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 564 } 565 long result = rL; 566 for (int i = 0; i < 1000; ++i) { 567 if (b) { 568 result += v.x; 569 } else { 570 // Uncommon trap referencing v. Should not allocate 571 // but just pass the existing oop to the uncommon trap. 572 result = v.hashInterpreted(); 573 for (int j = 0; j < va.length; ++j) { 574 result += va[j].hashInterpreted(); 575 } 576 } 577 } 578 return result; 579 } 580 581 @DontCompile 582 public void test13_verifier(boolean warmup) { 583 long result = test13(warmup); 584 Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash()); 585 } 586 587 // Create a value type in a non-inlined method and then call a 588 // non-inlined method on that value type. 589 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {10}) 590 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP)) 591 public long test14() { 592 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 593 return v.hashInterpreted(); 594 } 595 596 @DontCompile 597 public void test14_verifier(boolean b) { 598 long result = test14(); 599 Asserts.assertEQ(result, hash()); 600 } 601 602 // Create a value type in an inlined method and then call a 603 // non-inlined method on that value type. 604 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC)) 605 @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1}) 606 public long test15() { 607 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 608 return v.hashInterpreted(); 609 } 610 611 @DontCompile 612 public void test15_verifier(boolean b) { 613 long result = test15(); 614 Asserts.assertEQ(result, hash()); 615 } 616 617 // Create a value type in a non-inlined method and then call an 618 // inlined method on that value type. 619 @Test(failOn = (ALLOC + STORE + TRAP)) 620 public long test16() { 621 MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL); 622 return v.hash(); 623 } 624 625 @DontCompile 626 public void test16_verifier(boolean b) { 627 long result = test16(); 628 Asserts.assertEQ(result, hash()); 629 } 630 631 // Create a value type in an inlined method and then call an 632 // inlined method on that value type. 633 @Test(failOn = (ALLOC + LOAD + STORE + TRAP)) 634 public long test17() { 635 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 636 return v.hash(); 637 } 638 639 @DontCompile 640 public void test17_verifier(boolean b) { 641 long result = test17(); 642 Asserts.assertEQ(result, hash()); 643 } 644 645 // Create a value type in compiled code and pass it to the 646 // interpreter via a call. The value is live at the first call so 647 // debug info should include a reference to all its fields. 648 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 649 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 650 public long test18() { 651 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 652 v.hashInterpreted(); 653 return v.hashInterpreted(); 654 } 655 656 @DontCompile 657 public void test18_verifier(boolean warmup) { 658 long result = test18(); 659 Asserts.assertEQ(result, hash()); 660 } 661 662 // Create a value type in compiled code and pass it to the 663 // interpreter via a call. The value type is passed twice but 664 // should only be allocated once. 665 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP) 666 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP) 667 public long test19() { 668 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 669 return sumValue(v, v); 670 } 671 672 @DontCompile 673 public long sumValue(MyValue1 v, MyValue1 dummy) { 674 return v.hash(); 675 } 676 677 @DontCompile 678 public void test19_verifier(boolean warmup) { 679 long result = test19(); 680 Asserts.assertEQ(result, hash()); 681 } 682 683 // Create a value type (array) in compiled code and pass it to the 684 // interpreter via a call. The value type is live at the uncommon 685 // trap: verify that deoptimization causes the value type to be 686 // correctly allocated. 687 @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE) 688 @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {2}, failOn = LOAD) 689 public long test20(boolean deopt) { 690 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 691 MyValue2[] va = new MyValue2[3]; 692 if (deopt) { 693 // uncommon trap 694 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20")); 695 } 696 return v.hashInterpreted() + va[0].hashInterpreted() + 697 va[1].hashInterpreted() + va[2].hashInterpreted(); 698 } 699 700 @DontCompile 701 public void test20_verifier(boolean warmup) { 702 MyValue2[] va = new MyValue2[42]; 703 long result = test20(!warmup); 704 Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash()); 705 } 706 707 // Value type fields in regular object 708 MyValue1 val1; 709 MyValue2 val2; 710 final MyValue1 val3; 711 static MyValue1 val4; 712 static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL); 713 714 // Test value type fields in objects 715 @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP)) 716 public long test21(int x, long y) { 717 // Compute hash of value type fields 718 long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 719 // Update fields 720 val1 = MyValue1.createWithFieldsInline(x, y); 721 val2 = MyValue2.createWithFieldsInline(x, true); 722 val4 = MyValue1.createWithFieldsInline(x, y); 723 return result; 724 } 725 726 @DontCompile 727 public void test21_verifier(boolean warmup) { 728 // Check if hash computed by test18 is correct 729 val1 = MyValue1.createWithFieldsInline(rI, rL); 730 val2 = val1.v2; 731 // val3 is initialized in the constructor 732 val4 = val1; 733 // val5 is initialized in the static initializer 734 long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash(); 735 long result = test21(rI + 1, rL + 1); 736 Asserts.assertEQ(result, hash); 737 // Check if value type fields were updated 738 Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1)); 739 Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, true).hash()); 740 Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1)); 741 } 742 743 // Test folding of constant value type fields 744 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 745 public long test22() { 746 // This should be constant folded 747 return val5.hash() + val5.v3.hash(); 748 } 749 750 @DontCompile 751 public void test22_verifier(boolean warmup) { 752 long result = test22(); 753 Asserts.assertEQ(result, val5.hash() + val5.v3.hash()); 754 } 755 756 // Test OSR compilation 757 @Test() 758 public long test23() { 759 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 760 MyValue1[] va = new MyValue1[Math.abs(rI) % 3]; 761 for (int i = 0; i < va.length; ++i) { 762 va[i] = MyValue1.createWithFieldsInline(rI, rL); 763 } 764 long result = 0; 765 // Long loop to trigger OSR compilation 766 for (int i = 0 ; i < 100_000; ++i) { 767 // Reference local value type in interpreter state 768 result = v.hash(); 769 for (int j = 0; j < va.length; ++j) { 770 result += va[j].hash(); 771 } 772 } 773 return result; 774 } 775 776 @DontCompile 777 public void test23_verifier(boolean warmup) { 778 long result = test23(); 779 Asserts.assertEQ(result, ((Math.abs(rI) % 3) + 1) * hash()); 780 } 781 782 // Test interpreter to compiled code with various signatures 783 @Test(failOn = ALLOC + STORE + TRAP) 784 public long test24(MyValue2 v) { 785 return v.hash(); 786 } 787 788 @DontCompile 789 public void test24_verifier(boolean warmup) { 790 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 791 long result = test24(v); 792 Asserts.assertEQ(result, v.hashInterpreted()); 793 } 794 795 @Test(failOn = ALLOC + STORE + TRAP) 796 public long test25(int i1, MyValue2 v, int i2) { 797 return v.hash() + i1 - i2; 798 } 799 800 @DontCompile 801 public void test25_verifier(boolean warmup) { 802 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 803 long result = test25(rI, v, 2*rI); 804 Asserts.assertEQ(result, v.hashInterpreted() - rI); 805 } 806 807 @Test(failOn = ALLOC + STORE + TRAP) 808 public long test26(long l1, MyValue2 v, long l2) { 809 return v.hash() + l1 - l2; 810 } 811 812 @DontCompile 813 public void test26_verifier(boolean warmup) { 814 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 815 long result = test26(rL, v, 2*rL); 816 Asserts.assertEQ(result, v.hashInterpreted() - rL); 817 } 818 819 @Test(failOn = ALLOC + STORE + TRAP) 820 public long test27(int i, MyValue2 v, long l) { 821 return v.hash() + i + l; 822 } 823 824 @DontCompile 825 public void test27_verifier(boolean warmup) { 826 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 827 long result = test27(rI, v, rL); 828 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 829 } 830 831 @Test(failOn = ALLOC + STORE + TRAP) 832 public long test28(long l, MyValue2 v, int i) { 833 return v.hash() + i + l; 834 } 835 836 @DontCompile 837 public void test28_verifier(boolean warmup) { 838 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 839 long result = test28(rL, v, rI); 840 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 841 } 842 843 @Test(failOn = ALLOC + STORE + TRAP) 844 public long test29(long l, MyValue1 v1, int i, MyValue2 v2) { 845 return v1.hash() + i + l + v2.hash(); 846 } 847 848 @DontCompile 849 public void test29_verifier(boolean warmup) { 850 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 851 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 852 long result = test29(rL, v1, rI, v2); 853 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 854 } 855 856 // Test compiled code to interpreter with various signatures 857 @DontCompile 858 public long test30_interp(MyValue2 v) { 859 return v.hash(); 860 } 861 862 @Test(failOn = ALLOC + STORE + TRAP) 863 public long test30(MyValue2 v) { 864 return test30_interp(v); 865 } 866 867 @DontCompile 868 public void test30_verifier(boolean warmup) { 869 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 870 long result = test30(v); 871 Asserts.assertEQ(result, v.hashInterpreted()); 872 } 873 874 @DontCompile 875 public long test31_interp(int i1, MyValue2 v, int i2) { 876 return v.hash() + i1 - i2; 877 } 878 879 @Test(failOn = ALLOC + STORE + TRAP) 880 public long test31(int i1, MyValue2 v, int i2) { 881 return test31_interp(i1, v, i2); 882 } 883 884 @DontCompile 885 public void test31_verifier(boolean warmup) { 886 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 887 long result = test31(rI, v, 2*rI); 888 Asserts.assertEQ(result, v.hashInterpreted() - rI); 889 } 890 891 @DontCompile 892 public long test32_interp(long l1, MyValue2 v, long l2) { 893 return v.hash() + l1 - l2; 894 } 895 896 @Test(failOn = ALLOC + STORE + TRAP) 897 public long test32(long l1, MyValue2 v, long l2) { 898 return test32_interp(l1, v, l2); 899 } 900 901 @DontCompile 902 public void test32_verifier(boolean warmup) { 903 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 904 long result = test32(rL, v, 2*rL); 905 Asserts.assertEQ(result, v.hashInterpreted() - rL); 906 } 907 908 @DontCompile 909 public long test33_interp(int i, MyValue2 v, long l) { 910 return v.hash() + i + l; 911 } 912 913 @Test(failOn = ALLOC + STORE + TRAP) 914 public long test33(int i, MyValue2 v, long l) { 915 return test33_interp(i, v, l); 916 } 917 918 @DontCompile 919 public void test33_verifier(boolean warmup) { 920 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 921 long result = test33(rI, v, rL); 922 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 923 } 924 925 @DontCompile 926 public long test34_interp(long l, MyValue2 v, int i) { 927 return v.hash() + i + l; 928 } 929 930 @Test(failOn = ALLOC + STORE + TRAP) 931 public long test34(long l, MyValue2 v, int i) { 932 return test34_interp(l, v, i); 933 } 934 935 @DontCompile 936 public void test34_verifier(boolean warmup) { 937 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 938 long result = test34(rL, v, rI); 939 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 940 } 941 942 @DontCompile 943 public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 944 return v1.hash() + i + l + v2.hash(); 945 } 946 947 @Test(failOn = ALLOC + STORE + TRAP) 948 public long test35(long l, MyValue1 v1, int i, MyValue2 v2) { 949 return test35_interp(l, v1, i, v2); 950 } 951 952 @DontCompile 953 public void test35_verifier(boolean warmup) { 954 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 955 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 956 long result = test35(rL, v1, rI, v2); 957 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 958 } 959 960 // test that debug info at a call is correct 961 @DontCompile 962 public long test36_interp(MyValue2 v, MyValue1[] va, boolean deopt) { 963 if (deopt) { 964 // uncommon trap 965 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36")); 966 } 967 return v.hash() + va[0].hash() + va[1].hash(); 968 } 969 970 @Test(failOn = ALLOC + STORE + TRAP) 971 public long test36(MyValue2 v, MyValue1[] va, boolean flag, long l) { 972 return test36_interp(v, va, flag) + l; 973 } 974 975 @DontCompile 976 public void test36_verifier(boolean warmup) { 977 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 978 MyValue1[] va = new MyValue1[2]; 979 va[0] = MyValue1.createWithFieldsDontInline(rI, rL); 980 va[1] = MyValue1.createWithFieldsDontInline(rI, rL); 981 long result = test36(v, va, !warmup, rL); 982 Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL); 983 } 984 985 // Test vbox and vunbox 986 @Test 987 public long test37() throws Throwable { 988 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 989 } 990 991 @DontCompile 992 public void test37_verifier(boolean warmup) { 993 try { 994 long result = test37(); 995 Asserts.assertEQ(vcc.t, result, "Field t of input and result must be equal."); 996 } catch (Throwable t) { 997 throw new RuntimeException("test 37 failed", t); 998 } 999 } 1000 1001 // Generate a MethodHandle that obtains field t of the 1002 // derived value type 1003 private static MethodHandle generateVCCUnboxLoadLongMH() { 1004 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1005 "vccUnboxLoadLong", 1006 MethodType.methodType(long.class, ValueCapableClass1.class), 1007 CODE -> { 1008 CODE. 1009 aload_0(). 1010 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1011 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1012 lreturn(); 1013 } 1014 ); 1015 } 1016 1017 @Test 1018 public int test38() throws Throwable { 1019 return (int)vccUnboxLoadIntMH.invokeExact(vcc); 1020 } 1021 1022 @DontCompile 1023 public void test38_verifier(boolean warmup) { 1024 try { 1025 int result = test38(); 1026 Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal."); 1027 } catch (Throwable t) { 1028 throw new RuntimeException("test 38 failed", t); 1029 } 1030 } 1031 1032 // Generate a MethodHandle that obtains field x of the 1033 // derived value type 1034 private static MethodHandle generateVCCUnboxLoadIntMH() { 1035 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1036 "vccUnboxLoadInt", 1037 MethodType.methodType(int.class, ValueCapableClass1.class), 1038 CODE -> { 1039 CODE. 1040 aload_0(). 1041 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1042 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "x", "I"). 1043 ireturn(); 1044 } 1045 ); 1046 } 1047 1048 @Test 1049 public ValueCapableClass1 test39() throws Throwable { 1050 return (ValueCapableClass1)vccUnboxBoxMH.invokeExact(vcc); 1051 } 1052 1053 @DontCompile 1054 public void test39_verifier(boolean warmup) { 1055 try { 1056 ValueCapableClass1 result = test39(); 1057 Asserts.assertEQ(vcc.value(), result.value(), "Value of VCC and returned VCC must be equal"); 1058 } catch (Throwable t) { 1059 throw new RuntimeException("test 39 failed", t); 1060 } 1061 } 1062 1063 // Generate a MethodHandle that takes a value-capable class, 1064 // unboxes it, then boxes it again and returns it. 1065 private static MethodHandle generateVCCUnboxBoxMH() { 1066 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1067 "vccUnboxBox", 1068 MethodType.methodType(ValueCapableClass1.class, ValueCapableClass1.class), 1069 CODE -> { 1070 CODE. 1071 aload_0(). 1072 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1073 vbox(ValueCapableClass1.class). 1074 areturn(); 1075 } 1076 ); 1077 } 1078 1079 @Test 1080 public int test40() throws Throwable { 1081 return (int)vccUnboxBoxLoadIntMH.invokeExact(vcc); 1082 } 1083 1084 @DontCompile 1085 public void test40_verifier(boolean warmup) { 1086 try { 1087 int result = test40(); 1088 Asserts.assertEQ(vcc.x, result, "Field x of VCC and result must be equal"); 1089 } catch (Throwable t) { 1090 throw new RuntimeException("Test failed in the interpeter", t); 1091 } 1092 } 1093 1094 // Generate a MethodHandle that takes a value-capable class, 1095 // unboxes it, boxes it, reads a field from it, and returns the 1096 // field. 1097 private static MethodHandle generateVCCUnboxBoxLoadIntMH() { 1098 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1099 "vccUnboxBoxLoadInt", 1100 MethodType.methodType(int.class, ValueCapableClass1.class), 1101 CODE -> { 1102 CODE. 1103 aload_0(). 1104 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1105 vbox(ValueCapableClass1.class). 1106 getfield(ValueCapableClass1.class, "x", "I"). 1107 ireturn(); 1108 } 1109 ); 1110 1111 } 1112 1113 // Test value type array creation and initialization 1114 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD)) 1115 @Test(valid = ValueTypeArrayFlattenOn) 1116 public MyValue1[] test41(int len) { 1117 MyValue1[] va = new MyValue1[len]; 1118 for (int i = 0; i < len; ++i) { 1119 va[i] = MyValue1.createWithFieldsDontInline(rI, rL); 1120 } 1121 return va; 1122 } 1123 1124 @DontCompile 1125 public void test41_verifier(boolean warmup) { 1126 int len = Math.abs(rI % 10); 1127 MyValue1[] va = test41(len); 1128 for (int i = 0; i < len; ++i) { 1129 Asserts.assertEQ(va[i].hash(), hash()); 1130 } 1131 } 1132 1133 // Test creation of a value type array and element access 1134 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOOP + TRAP)) 1135 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOC + ALLOCA + LOOP + LOAD + LOADP + STORE + TRAP)) 1136 public long test42() { 1137 MyValue1[] va = new MyValue1[1]; 1138 va[0] = MyValue1.createWithFieldsInline(rI, rL); 1139 return va[0].hash(); 1140 } 1141 1142 @DontCompile 1143 public void test42_verifier(boolean warmup) { 1144 long result = test42(); 1145 Asserts.assertEQ(result, hash()); 1146 } 1147 1148 // Test receiving a value type array from the interpreter, 1149 // updating its elements in a loop and computing a hash. 1150 @Test(failOn = (ALLOCA)) 1151 public long test43(MyValue1[] va) { 1152 long result = 0; 1153 for (int i = 0; i < 10; ++i) { 1154 result += va[i].hash(); 1155 va[i] = MyValue1.createWithFieldsInline(rI + 1, rL + 1); 1156 } 1157 return result; 1158 } 1159 1160 @DontCompile 1161 public void test43_verifier(boolean warmup) { 1162 MyValue1[] va = new MyValue1[10]; 1163 long expected = 0; 1164 for (int i = 0; i < 10; ++i) { 1165 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i); 1166 expected += va[i].hash(); 1167 } 1168 long result = test43(va); 1169 Asserts.assertEQ(expected, result); 1170 for (int i = 0; i < 10; ++i) { 1171 if (va[i].hash() != hash(rI + 1, rL + 1)) { 1172 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1)); 1173 } 1174 } 1175 } 1176 1177 // Test returning a value type array received from the interpreter 1178 @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP) 1179 public MyValue1[] test44(MyValue1[] va) { 1180 return va; 1181 } 1182 1183 @DontCompile 1184 public void test44_verifier(boolean warmup) { 1185 MyValue1[] va = new MyValue1[10]; 1186 for (int i = 0; i < 10; ++i) { 1187 va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i); 1188 } 1189 va = test44(va); 1190 for (int i = 0; i < 10; ++i) { 1191 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1192 } 1193 } 1194 1195 // Merge value type arrays created from two branches 1196 @Test(failOn = (TRAP)) 1197 public MyValue1[] test45(boolean b) { 1198 MyValue1[] va; 1199 if (b) { 1200 va = new MyValue1[5]; 1201 for (int i = 0; i < 5; ++i) { 1202 va[i] = MyValue1.createWithFieldsInline(rI, rL); 1203 } 1204 } else { 1205 va = new MyValue1[10]; 1206 for (int i = 0; i < 10; ++i) { 1207 va[i] = MyValue1.createWithFieldsInline(rI + i, rL + i); 1208 } 1209 } 1210 long sum = va[0].hashInterpreted(); 1211 if (b) { 1212 va[0] = MyValue1.createWithFieldsDontInline(rI, sum); 1213 } else { 1214 va[0] = MyValue1.createWithFieldsDontInline(rI + 1, sum + 1); 1215 } 1216 return va; 1217 } 1218 1219 @DontCompile 1220 public void test45_verifier(boolean warmup) { 1221 MyValue1[] va = test45(true); 1222 Asserts.assertEQ(va.length, 5); 1223 Asserts.assertEQ(va[0].hash(), hash(rI, hash())); 1224 for (int i = 1; i < 5; ++i) { 1225 Asserts.assertEQ(va[i].hash(), hash()); 1226 } 1227 va = test45(false); 1228 Asserts.assertEQ(va.length, 10); 1229 Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1)); 1230 for (int i = 1; i < 10; ++i) { 1231 Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i)); 1232 } 1233 } 1234 1235 // Test creation of value type array with single element 1236 @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP)) 1237 @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP)) 1238 public MyValue1 test46() { 1239 MyValue1[] va = new MyValue1[1]; 1240 return va[0]; 1241 } 1242 1243 @DontCompile 1244 public void test46_verifier(boolean warmup) { 1245 MyValue1[] va = new MyValue1[1]; 1246 MyValue1 v = test46(); 1247 Asserts.assertEQ(v.hashPrimitive(), va[0].hashPrimitive()); 1248 } 1249 1250 // Test default initialization of value type arrays 1251 @Test(failOn = LOAD) 1252 public MyValue1[] test47(int len) { 1253 return new MyValue1[len]; 1254 } 1255 1256 @DontCompile 1257 public void test47_verifier(boolean warmup) { 1258 int len = Math.abs(rI % 10); 1259 MyValue1[] va = new MyValue1[len]; 1260 MyValue1[] var = test47(len); 1261 for (int i = 0; i < len; ++i) { 1262 Asserts.assertEQ(va[i].hashPrimitive(), var[i].hashPrimitive()); 1263 } 1264 } 1265 1266 // Test creation of value type array with zero length 1267 @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP) 1268 public MyValue1[] test48() { 1269 return new MyValue1[0]; 1270 } 1271 1272 @DontCompile 1273 public void test48_verifier(boolean warmup) { 1274 MyValue1[] va = test48(); 1275 Asserts.assertEQ(va.length, 0); 1276 } 1277 1278 static MyValue1[] test49_va; 1279 1280 // Test that value type array loaded from field has correct type 1281 @Test(failOn = (LOOP)) 1282 public long test49() { 1283 return test49_va[0].hash(); 1284 } 1285 1286 @DontCompile 1287 public void test49_verifier(boolean warmup) { 1288 test49_va = new MyValue1[1]; 1289 test49_va[0] = MyValue1.createWithFieldsInline(rI, rL); 1290 long result = test49(); 1291 Asserts.assertEQ(result, hash()); 1292 } 1293 1294 // test vdefault 1295 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1296 public long test50() { 1297 MyValue2 v = MyValue2.createDefaultInline(); 1298 return v.hash(); 1299 } 1300 1301 @DontCompile 1302 public void test50_verifier(boolean warmup) { 1303 long result = test50(); 1304 Asserts.assertEQ(result, MyValue2.createDefaultInline().hash()); 1305 } 1306 1307 // test vdefault 1308 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1309 public long test51() { 1310 MyValue1 v1 = MyValue1.createDefaultInline(); 1311 MyValue1 v2 = MyValue1.createDefaultDontInline(); 1312 return v1.hashPrimitive() + v2.hashPrimitive(); 1313 } 1314 1315 @DontCompile 1316 public void test51_verifier(boolean warmup) { 1317 long result = test51(); 1318 Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive()); 1319 } 1320 1321 // test vwithfield 1322 @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP) 1323 public long test52() { 1324 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 1325 return v.hash(); 1326 } 1327 1328 @DontCompile 1329 public void test52_verifier(boolean warmup) { 1330 long result = test52(); 1331 Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash()); 1332 } 1333 1334 // test vwithfield 1335 @Test(failOn = ALLOC + STORE + LOOP + TRAP) 1336 public long test53() { 1337 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL); 1338 MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL); 1339 return v1.hash() + v2.hash(); 1340 } 1341 1342 @DontCompile 1343 public void test53_verifier(boolean warmup) { 1344 long result = test53(); 1345 Asserts.assertEQ(result, 2 * hash()); 1346 } 1347 1348 // multi-dimensional arrays 1349 @Test 1350 public MyValue1[][][] test54(int len1, int len2, int len3) { 1351 MyValue1[][][] arr = new MyValue1[len1][len2][len3]; 1352 for (int i = 0; i < len1; i++) { 1353 for (int j = 0; j < len2; j++) { 1354 for (int k = 0; k < len3; k++) { 1355 arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i , rL + j + k); 1356 } 1357 } 1358 } 1359 return arr; 1360 } 1361 1362 @DontCompile 1363 public void test54_verifier(boolean warmup) { 1364 MyValue1[][][] arr = test54(2, 3, 4); 1365 for (int i = 0; i < 2; i++) { 1366 for (int j = 0; j < 3; j++) { 1367 for (int k = 0; k < 4; k++) { 1368 Asserts.assertEQ(arr[i][j][k].hash(), MyValue1.createWithFieldsDontInline(rI + i , rL + j + k).hash()); 1369 } 1370 } 1371 } 1372 } 1373 1374 @Test 1375 public void test55(MyValue1[][][] arr, long[] res) { 1376 int l = 0; 1377 for (int i = 0; i < arr.length; i++) { 1378 for (int j = 0; j < arr[i].length; j++) { 1379 for (int k = 0; k < arr[i][j].length; k++) { 1380 res[l] = arr[i][j][k].hash(); 1381 l++; 1382 } 1383 } 1384 } 1385 } 1386 1387 @DontCompile 1388 public void test55_verifier(boolean warmup) { 1389 MyValue1[][][] arr = new MyValue1[2][3][4]; 1390 long[] res = new long[2*3*4]; 1391 long[] verif = new long[2*3*4]; 1392 int l = 0; 1393 for (int i = 0; i < 2; i++) { 1394 for (int j = 0; j < 3; j++) { 1395 for (int k = 0; k < 4; k++) { 1396 arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i, rL + j + k); 1397 verif[l] = arr[i][j][k].hash(); 1398 l++; 1399 } 1400 } 1401 } 1402 test55(arr, res); 1403 for (int i = 0; i < verif.length; i++) { 1404 Asserts.assertEQ(res[i], verif[i]); 1405 } 1406 } 1407 1408 class TestClass56 { 1409 public MyValue1 v; 1410 } 1411 1412 // Test allocation elimination of unused object with initialized value type field 1413 @Test(failOn = ALLOC + LOAD + STORE + LOOP) 1414 public void test56(boolean deopt) { 1415 TestClass56 unused = new TestClass56(); 1416 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 1417 unused.v = v; 1418 if (deopt) { 1419 // uncommon trap 1420 WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test56")); 1421 } 1422 } 1423 1424 @DontCompile 1425 public void test56_verifier(boolean warmup) { 1426 test56(!warmup); 1427 } 1428 1429 // Test loop peeling 1430 @Test(failOn = ALLOC + LOAD + STORE) 1431 public void test57() { 1432 MyValue1 v = MyValue1.createWithFieldsInline(0, 1); 1433 // Trigger OSR compilation and loop peeling 1434 for (int i = 0; i < 100_000; ++i) { 1435 if (v.x != i || v.y != i + 1) { 1436 // Uncommon trap 1437 throw new RuntimeException("test57 failed"); 1438 } 1439 v = MyValue1.createWithFieldsInline(i + 1, i + 2); 1440 } 1441 } 1442 1443 @DontCompile 1444 public void test57_verifier(boolean warmup) { 1445 test57(); 1446 } 1447 1448 // Test loop peeling and unrolling 1449 @Test() 1450 public void test58() { 1451 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0); 1452 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1); 1453 // Trigger OSR compilation and loop peeling 1454 for (int i = 0; i < 100_000; ++i) { 1455 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) { 1456 // Uncommon trap 1457 throw new RuntimeException("test58 failed"); 1458 } 1459 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0); 1460 v2 = MyValue1.createWithFieldsInline(i+2, i+2); 1461 } 1462 } 1463 1464 @DontCompile 1465 public void test58_verifier(boolean warmup) { 1466 test58(); 1467 } 1468 1469 // When calling a method on __Value, passing fields as arguments is impossible 1470 @Test(failOn = ALLOC + STORE + LOAD) 1471 public String test59(MyValue1 v) { 1472 return v.toString(); 1473 } 1474 1475 @DontCompile 1476 public void test59_verifier(boolean warmup) { 1477 boolean failed = false; 1478 try { 1479 test59(val1); 1480 failed = true; 1481 } catch (UnsupportedOperationException uoe) { 1482 } 1483 Asserts.assertFalse(failed); 1484 } 1485 1486 // Same as above, but the method on __Value is inlined 1487 // hashCode allocates an exception so can't really check the graph shape 1488 @Test() 1489 public int test60(MyValue1 v) { 1490 return v.hashCode(); 1491 } 1492 1493 @DontCompile 1494 public void test60_verifier(boolean warmup) { 1495 boolean failed = false; 1496 try { 1497 test60(val1); 1498 failed = true; 1499 } catch (UnsupportedOperationException uoe) { 1500 } 1501 Asserts.assertFalse(failed); 1502 } 1503 1504 /* The compiler is supposed to determine that the value to be 1505 * unboxed in nullcvvUnboxLoadLong is always null. Therefore, the 1506 * compiler generates only the path leading to the corresponding 1507 * uncommon trap. */ 1508 @Test(valid = AlwaysIncrementalInlineOff, failOn = RETURN) 1509 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1510 public long test61() throws Throwable { 1511 return (long)nullvccUnboxLoadLongMH.invokeExact(); 1512 } 1513 1514 @DontCompile 1515 public void test61_verifier(boolean warmup) throws Throwable { 1516 try { 1517 long result = test61(); 1518 throw new RuntimeException("Test failed because no exception was thrown"); 1519 } catch (NullPointerException e) { 1520 } 1521 } 1522 1523 public static MethodHandle generateNullVCCUnboxLoadLongMH() { 1524 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1525 "nullvccUnboxLoadLong", 1526 MethodType.methodType(long.class), 1527 CODE -> { 1528 CODE. 1529 aconst_null(). 1530 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1531 vgetfield(ValueCapableClass1.class, "t", "J"). 1532 lreturn(); 1533 } 1534 ); 1535 } 1536 1537 /* The compiler is supposed to determine that the allocated 1538 * ValueCapableClass1 instance is never null (and therefore not 1539 * generate a null check). Also, the source and target type match 1540 * (known at compile time), so no type check is needed either.*/ 1541 @Test(valid = AlwaysIncrementalInlineOff, failOn = NPE) 1542 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1543 public long test62() throws Throwable { 1544 return (long)checkedvccUnboxLoadLongMH.invokeExact(); 1545 } 1546 1547 @DontCompile 1548 public void test62_verifier(boolean warmup) throws Throwable { 1549 long result = test62(); 1550 Asserts.assertEQ(result, 17L); 1551 } 1552 1553 public static MethodHandle generateCheckedVCCUnboxLoadLongMH() { 1554 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1555 "checkedVCCUnboxLoadLongMH", 1556 MethodType.methodType(long.class), 1557 CODE -> { 1558 CODE. 1559 invokestatic(ValueCapableClass1.class, "createInline", "()Lcompiler/valhalla/valuetypes/ValueCapableClass1;", false). 1560 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1561 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1562 lreturn(); 1563 } 1564 ); 1565 } 1566 1567 /* The compiler is supposed to emit a runtime null check because 1568 * it does not have enough information to determine that the value 1569 * to be unboxed is not null (and either that it is null). The 1570 * declared type of the */ 1571 @Test(valid = AlwaysIncrementalInlineOff, match = {NPE}, matchCount = {1}) 1572 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1573 public long test63(ValueCapableClass1 vcc) throws Throwable { 1574 return (long)vccUnboxLoadLongMH.invokeExact(vcc); 1575 } 1576 1577 @DontCompile 1578 public void test63_verifier(boolean warmup) throws Throwable { 1579 try { 1580 long result = test63(null); 1581 throw new RuntimeException("Test failed because no exception was thrown"); 1582 } catch (NullPointerException e) { 1583 } 1584 } 1585 1586 /* Attempt to unbox an object that is not a subclass of the 1587 * value-capable class derived from the value type specified in 1588 * the vunbox bytecode. */ 1589 @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {1,1}) 1590 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1591 public long test64(Object vcc) throws Throwable { 1592 return (long)objectUnboxLoadLongMH.invokeExact(vcc); 1593 } 1594 1595 @DontCompile 1596 public void test64_verifier(boolean warmup) throws Throwable { 1597 try { 1598 long result = test64(new Object()); 1599 throw new RuntimeException("Test failed because no exception was thrown"); 1600 } catch (ClassCastException e) { 1601 } 1602 1603 try { 1604 long result = test64(vcc2); 1605 throw new RuntimeException("Test failed because no exception was thrown"); 1606 } catch (ClassCastException e) { 1607 } 1608 1609 Asserts.assertEQ(test64(vcc), rL); 1610 } 1611 1612 private static MethodHandle generateObjectUnboxLoadLongMH() { 1613 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1614 "ObjectUnboxLoadLong", 1615 MethodType.methodType(long.class, Object.class), 1616 CODE -> { 1617 CODE. 1618 aload_0(). 1619 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1620 vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J"). 1621 lreturn(); 1622 } 1623 ); 1624 } 1625 1626 /* Generate an if-then-else construct with one path that contains 1627 * an invalid boxing operation (boxing of a value-type to a 1628 * non-matching value-capable class).*/ 1629 @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {2,3}) 1630 @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1}) 1631 public long test65(Object obj, boolean warmup) throws Throwable { 1632 return (long)objectBoxMH.invokeExact(obj, warmup); 1633 } 1634 1635 @DontCompile 1636 public void test65_verifier(boolean warmup) throws Throwable { 1637 try { 1638 long result = test65(vcc2, true); 1639 throw new RuntimeException("Test failed because no exception was thrown"); 1640 } catch (ClassCastException e) { 1641 } 1642 1643 Asserts.assertEQ(test65(vcc, true), rL); 1644 1645 try { 1646 long result = test65(vcc2, false); 1647 throw new RuntimeException("Test failed because no exception was thrown"); 1648 } catch (ClassCastException e) { 1649 } 1650 1651 try { 1652 long result = test65(vcc, false); 1653 throw new RuntimeException("Test failed because no exception was thrown"); 1654 } catch (ClassCastException e) { 1655 } 1656 } 1657 1658 private static MethodHandle generateObjectBoxMH() { 1659 return MethodHandleBuilder.loadCode(MethodHandles.lookup(), 1660 "ObjectBox", 1661 MethodType.methodType(long.class, Object.class, boolean.class), 1662 CODE -> { 1663 CODE. 1664 iload_1(). 1665 iconst_1(). 1666 if_icmpne((short)14). 1667 aload_0(). 1668 vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()). 1669 vbox(ValueCapableClass1.class). 1670 getfield(ValueCapableClass1.class, "t", "J"). 1671 lreturn(). 1672 aload_0(). 1673 vunbox(ValueType.forClass(ValueCapableClass2.class).valueClass()). 1674 vbox(ValueCapableClass1.class). 1675 getfield(ValueCapableClass1.class, "t", "J"). 1676 lreturn(); 1677 } 1678 ); 1679 } 1680 1681 // ========== Test infrastructure ========== 1682 1683 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 1684 private static final int ValueTypePassFieldsAsArgsOn = 0x1; 1685 private static final int ValueTypePassFieldsAsArgsOff = 0x2; 1686 private static final int ValueTypeArrayFlattenOn = 0x4; 1687 private static final int ValueTypeArrayFlattenOff = 0x8; 1688 private static final int AlwaysIncrementalInlineOff = 0x10; 1689 private static final int AlwaysIncrementalInlineOn = 0x20; 1690 static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | AlwaysIncrementalInlineOff | AlwaysIncrementalInlineOn; 1691 private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs"); 1692 private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten"); 1693 private static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline"); 1694 private static final int COMP_LEVEL_ANY = -1; 1695 private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; 1696 private static final Hashtable<String, Method> tests = new Hashtable<String, Method>(); 1697 private static final int WARMUP = 251; 1698 private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler"); 1699 private static boolean PRINT_IDEAL = WHITE_BOX.getBooleanVMFlag("PrintIdeal"); 1700 private static boolean XCOMP = Platform.isComp(); 1701 1702 // Regular expressions used to match nodes in the PrintIdeal output 1703 private static final String START = "(\\d+\\t(.*"; 1704 private static final String MID = ".*)+\\t===.*"; 1705 private static final String END = ")|"; 1706 private static final String ALLOC = "(.*precise klass compiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_instance_Java" + END; 1707 private static final String ALLOCA = "(.*precise klass \\[Qcompiler/valhalla/valuetypes/MyValue.*\\R(.*(nop|spill).*\\R)*.*_new_array_Java" + END; 1708 private static final String LOAD = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1709 private static final String LOADP = START + "Load(P|N)" + MID + "valuetype\\*" + END; 1710 private static final String STORE = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END; 1711 private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END; 1712 private static final String LOOP = START + "Loop" + MID + "" + END; 1713 private static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END; 1714 private static final String RETURN = START + "Return" + MID + "returns" + END; 1715 private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END; 1716 private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END; 1717 private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END; 1718 private static final String SCOBJ = "(.*# ScObj.*" + END; 1719 1720 static { 1721 // Gather all test methods and put them in Hashtable 1722 for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) { 1723 Test[] annos = m.getAnnotationsByType(Test.class); 1724 if (annos.length != 0) { 1725 tests.put("ValueTypeTestBench::" + m.getName(), m); 1726 } 1727 } 1728 } 1729 1730 private static void execute_vm(String... args) throws Throwable { 1731 Asserts.assertFalse(tests.isEmpty(), "no tests to execute"); 1732 ArrayList<String> all_args = new ArrayList(List.of(args)); 1733 // Run tests in own process and verify output 1734 all_args.add(ValueTypeTestBench.class.getName()); 1735 all_args.add("run"); 1736 // Spawn process with default JVM options from the test's run command 1737 String[] vmInputArgs = InputArguments.getVmInputArgs(); 1738 String[] cmds = Arrays.copyOf(vmInputArgs, vmInputArgs.length + all_args.size()); 1739 System.arraycopy(all_args.toArray(), 0, cmds, vmInputArgs.length, all_args.size()); 1740 OutputAnalyzer oa = ProcessTools.executeTestJvm(cmds); 1741 // If ideal graph printing is enabled/supported, verify output 1742 String output = oa.getOutput(); 1743 oa.shouldHaveExitValue(0); 1744 boolean verifyIR = output.contains("PrintIdeal enabled") && 1745 !output.contains("ValueTypePassFieldsAsArgs is not supported on this platform"); 1746 if (verifyIR) { 1747 parseOutput(output); 1748 } else { 1749 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?"); 1750 } 1751 } 1752 1753 public static void main(String[] args) throws Throwable { 1754 //tests.values().removeIf(p -> !p.getName().equals("test64")); // Run single test 1755 if (args.length == 0) { 1756 execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation", 1757 "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly", 1758 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*", 1759 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*", 1760 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*", 1761 "-XX:CompileCommand=compileonly,java.lang.Object::<init>", 1762 "-XX:CompileCommand=inline,java.lang.__Value::hashCode"); 1763 } else { 1764 // Execute tests 1765 ValueTypeTestBench bench = new ValueTypeTestBench(); 1766 bench.run(); 1767 } 1768 } 1769 1770 public static void parseOutput(String output) throws Exception { 1771 String split = "b compiler.valhalla.valuetypes."; 1772 String[] compilations = output.split(split); 1773 // Print header 1774 System.out.println(compilations[0]); 1775 // Iterate over compilation output 1776 for (String graph : compilations) { 1777 String[] lines = graph.split("\\n"); 1778 if (lines[0].contains("@")) { 1779 continue; // Ignore OSR compilations 1780 } 1781 String testName = lines[0].split(" ")[0]; 1782 Method test = tests.get(testName); 1783 if (test == null) { 1784 // Skip helper methods 1785 continue; 1786 } 1787 if (PRINT_GRAPH) { 1788 System.out.println("\nGraph for " + graph); 1789 } 1790 // Parse graph using regular expressions to determine if it contains forbidden nodes 1791 Test[] annos = test.getAnnotationsByType(Test.class); 1792 Test anno = null; 1793 for (Test a : annos) { 1794 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) { 1795 assert anno == null; 1796 anno = a; 1797 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) { 1798 assert anno == null; 1799 anno = a; 1800 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) { 1801 assert anno == null; 1802 anno = a; 1803 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) { 1804 assert anno == null; 1805 anno = a; 1806 } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) { 1807 assert anno == null; 1808 anno = a; 1809 } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) { 1810 assert anno == null; 1811 anno = a; 1812 } 1813 } 1814 assert anno != null; 1815 String regexFail = anno.failOn(); 1816 if (!regexFail.isEmpty()) { 1817 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1)); 1818 Matcher matcher = pattern.matcher(graph); 1819 boolean found = matcher.find(); 1820 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : "")); 1821 } 1822 String[] regexMatch = anno.match(); 1823 int[] matchCount = anno.matchCount(); 1824 for (int i = 0; i < regexMatch.length; ++i) { 1825 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1)); 1826 Matcher matcher = pattern.matcher(graph); 1827 int count = 0; 1828 String nodes = ""; 1829 while (matcher.find()) { 1830 count++; 1831 nodes += matcher.group() + "\n"; 1832 } 1833 if (matchCount[i] < 0) { 1834 Asserts.assertLTE(Math.abs(matchCount[i]), count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 1835 } else { 1836 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes); 1837 } 1838 } 1839 tests.remove(testName); 1840 System.out.println(testName + " passed"); 1841 } 1842 // Check if all tests were compiled 1843 if (tests.size() != 0) { 1844 for (String name : tests.keySet()) { 1845 System.out.println("Test '" + name + "' not compiled!"); 1846 } 1847 throw new RuntimeException("Not all tests were compiled"); 1848 } 1849 } 1850 1851 public void setup(Method[] methods) { 1852 if (XCOMP) { 1853 // Don't control compilation if -Xcomp is enabled 1854 return; 1855 } 1856 for (Method m : methods) { 1857 if (m.isAnnotationPresent(Test.class)) { 1858 // Don't inline tests 1859 WHITE_BOX.testSetDontInlineMethod(m, true); 1860 } 1861 if (m.isAnnotationPresent(DontCompile.class)) { 1862 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true); 1863 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false); 1864 WHITE_BOX.testSetDontInlineMethod(m, true); 1865 } 1866 if (m.isAnnotationPresent(ForceInline.class)) { 1867 WHITE_BOX.testSetForceInlineMethod(m, true); 1868 } else if (m.isAnnotationPresent(DontInline.class)) { 1869 WHITE_BOX.testSetDontInlineMethod(m, true); 1870 } 1871 } 1872 } 1873 1874 public void run() throws Exception { 1875 if (USE_COMPILER && PRINT_IDEAL && !XCOMP) { 1876 System.out.println("PrintIdeal enabled"); 1877 } 1878 System.out.format("rI = %d, rL = %d\n", rI, rL); 1879 setup(this.getClass().getDeclaredMethods()); 1880 setup(MyValue1.class.getDeclaredMethods()); 1881 setup(MyValue2.class.getDeclaredMethods()); 1882 1883 // Compile class initializers 1884 WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION); 1885 WHITE_BOX.enqueueInitializerForCompilation(MyValue1.class, COMP_LEVEL_FULL_OPTIMIZATION); 1886 WHITE_BOX.enqueueInitializerForCompilation(MyValue2.class, COMP_LEVEL_FULL_OPTIMIZATION); 1887 1888 // Execute tests 1889 for (Method test : tests.values()) { 1890 Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class); 1891 // Warmup using verifier method 1892 for (int i = 0; i < WARMUP; ++i) { 1893 verifier.invoke(this, true); 1894 } 1895 // Trigger compilation 1896 WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION); 1897 Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled"); 1898 // Check result 1899 verifier.invoke(this, false); 1900 } 1901 } 1902 } 1903 1904 // Mark method as test 1905 @Retention(RetentionPolicy.RUNTIME) 1906 @Repeatable(Tests.class) 1907 @interface Test { 1908 // Regular expression used to match forbidden IR nodes 1909 // in the C2 IR emitted for this test. 1910 String failOn() default ""; 1911 // Regular expressions used to match and count IR nodes. 1912 String[] match() default { }; 1913 int[] matchCount() default { }; 1914 int valid() default ValueTypeTestBench.AllFlags; 1915 } 1916 1917 @Retention(RetentionPolicy.RUNTIME) 1918 @interface Tests { 1919 Test[] value(); 1920 } 1921 1922 // Force method inlining during compilation 1923 @Retention(RetentionPolicy.RUNTIME) 1924 @interface ForceInline { } 1925 1926 // Prevent method inlining during compilation 1927 @Retention(RetentionPolicy.RUNTIME) 1928 @interface DontInline { } 1929 1930 // Prevent method compilation 1931 @Retention(RetentionPolicy.RUNTIME) 1932 @interface DontCompile { }