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