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