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