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