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