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