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