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