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