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