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