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