1 /*
   2  * Copyright (c) 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 package compiler.valhalla.valuetypes;
  25 
  26 import jdk.test.lib.Asserts;
  27 
  28 /*
  29  * @test
  30  * @summary Test the basic value type implementation in C2
  31  * @library /testlibrary /test/lib /compiler/whitebox /
  32  * @requires os.simpleArch == "x64"
  33  * @modules java.base/jdk.experimental.bytecode
  34  *          java.base/jdk.experimental.value
  35  *          java.base/jdk.internal.misc:+open
  36  *          jdk.incubator.mvt
  37  * @compile -XDenableValueTypes TestBasicFunctionality.java
  38  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  39  * @run main ClassFileInstaller jdk.test.lib.Platform
  40  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  41  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+AlwaysIncrementalInline
  42  *                   -XX:+EnableValhalla -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  43  *                   -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
  44  *                   compiler.valhalla.valuetypes.TestBasicFunctionality
  45  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  46  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops
  47  *                   -XX:+EnableValhalla -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  48  *                   -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
  49  *                   compiler.valhalla.valuetypes.TestBasicFunctionality
  50  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  51  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops
  52  *                   -XX:+EnableValhalla -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  53  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
  54  *                   -DVerifyIR=false compiler.valhalla.valuetypes.TestBasicFunctionality
  55  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  56  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+AlwaysIncrementalInline
  57  *                   -XX:+EnableValhalla -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  58  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
  59  *                   -DVerifyIR=false compiler.valhalla.valuetypes.TestBasicFunctionality
  60  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  61  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI
  62  *                   -XX:+EnableValhalla -XX:+ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  63  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
  64  *                   -DVerifyIR=false compiler.valhalla.valuetypes.TestBasicFunctionality
  65  */
  66 public class TestBasicFunctionality extends ValueTypeTest {
  67 
  68     public static void main(String[] args) throws Throwable {
  69         TestBasicFunctionality test = new TestBasicFunctionality();
  70         test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, MyValue3.class, MyValue3Inline.class);
  71     }
  72 
  73     // Helper methods
  74 
  75     protected long hash() {
  76         return hash(rI, rL);
  77     }
  78 
  79     protected long hash(int x, long y) {
  80         return MyValue1.createWithFieldsInline(x, y).hash();
  81     }
  82 
  83     // Receive value type through call to interpreter
  84     @Test(failOn = ALLOC + STORE + TRAP)
  85     public long test1() {
  86         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
  87         return v.hash();
  88     }
  89 
  90     @DontCompile
  91     public void test1_verifier(boolean warmup) {
  92         long result = test1();
  93         Asserts.assertEQ(result, hash());
  94     }
  95 
  96     // Receive value type from interpreter via parameter
  97     @Test(failOn = ALLOC + STORE + TRAP)
  98     public long test2(MyValue1 v) {
  99         return v.hash();
 100     }
 101 
 102     @DontCompile
 103     public void test2_verifier(boolean warmup) {
 104         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 105         long result = test2(v);
 106         Asserts.assertEQ(result, hash());
 107     }
 108 
 109     // Return incoming value type without accessing fields
 110     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 11}, failOn = LOAD + TRAP)
 111     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP)
 112     public MyValue1 test3(MyValue1 v) {
 113         return v;
 114     }
 115 
 116     @DontCompile
 117     public void test3_verifier(boolean warmup) {
 118         MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL);
 119         MyValue1 v2 = test3(v1);
 120         Asserts.assertEQ(v1.x, v2.x);
 121         Asserts.assertEQ(v1.y, v2.y);
 122     }
 123 
 124     // Create a value type in compiled code and only use fields.
 125     // Allocation should go away because value type does not escape.
 126     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 127     public long test4() {
 128         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 129         return v.hash();
 130     }
 131 
 132     @DontCompile
 133     public void test4_verifier(boolean warmup) {
 134         long result = test4();
 135         Asserts.assertEQ(result, hash());
 136     }
 137 
 138     // Create a value type in compiled code and pass it to
 139     // an inlined compiled method via a call.
 140     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 141     public long test5() {
 142         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 143         return test5Inline(v);
 144     }
 145 
 146     @ForceInline
 147     public long test5Inline(MyValue1 v) {
 148         return v.hash();
 149     }
 150 
 151     @DontCompile
 152     public void test5_verifier(boolean warmup) {
 153         long result = test5();
 154         Asserts.assertEQ(result, hash());
 155     }
 156 
 157     // Create a value type in compiled code and pass it to
 158     // the interpreter via a call.
 159     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC)
 160     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 161     public long test6() {
 162         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 163         // Pass to interpreter
 164         return v.hashInterpreted();
 165     }
 166 
 167     @DontCompile
 168     public void test6_verifier(boolean warmup) {
 169         long result = test6();
 170         Asserts.assertEQ(result, hash());
 171     }
 172 
 173     // Create a value type in compiled code and pass it to
 174     // the interpreter by returning.
 175     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 176     public MyValue1 test7(int x, long y) {
 177         return MyValue1.createWithFieldsInline(x, y);
 178     }
 179 
 180     @DontCompile
 181     public void test7_verifier(boolean warmup) {
 182         MyValue1 v = test7(rI, rL);
 183         Asserts.assertEQ(v.hash(), hash());
 184     }
 185 
 186     // Merge value types created from two branches
 187     @Test(failOn = ALLOC + STORE + TRAP)
 188     public long test8(boolean b) {
 189         MyValue1 v;
 190         if (b) {
 191             v = MyValue1.createWithFieldsInline(rI, rL);
 192         } else {
 193             v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1);
 194         }
 195         return v.hash();
 196     }
 197 
 198     @DontCompile
 199     public void test8_verifier(boolean warmup) {
 200         Asserts.assertEQ(test8(true), hash());
 201         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 202     }
 203 
 204     // Merge value types created from two branches
 205     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {10}, failOn = TRAP + ALLOC + STORE)
 206     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP)
 207     public MyValue1 test9(boolean b) {
 208         MyValue1 v;
 209         if (b) {
 210             // Value type is not allocated
 211             v = MyValue1.createWithFieldsInline(rI, rL);
 212         } else {
 213             // Value type is allocated by the callee
 214             v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1);
 215         }
 216         // Need to allocate value type if 'b' is true
 217         long sum = v.hashInterpreted();
 218         if (b) {
 219             v = MyValue1.createWithFieldsDontInline(rI, sum);
 220         } else {
 221             v = MyValue1.createWithFieldsDontInline(rI, sum + 1);
 222         }
 223         // Don't need to allocate value type because both branches allocate
 224         return v;
 225     }
 226 
 227     @DontCompile
 228     public void test9_verifier(boolean warmup) {
 229         MyValue1 v = test9(true);
 230         Asserts.assertEQ(v.x, rI);
 231         Asserts.assertEQ(v.y, hash());
 232         v = test9(false);
 233         Asserts.assertEQ(v.x, rI);
 234         Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1);
 235     }
 236 
 237     // Merge value types created in a loop (not inlined)
 238     @Test(failOn = ALLOC + STORE + TRAP)
 239     public long test10(int x, long y) {
 240         MyValue1 v = MyValue1.createWithFieldsDontInline(x, y);
 241         for (int i = 0; i < 10; ++i) {
 242             v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1);
 243         }
 244         return v.hash();
 245     }
 246 
 247     @DontCompile
 248     public void test10_verifier(boolean warmup) {
 249         long result = test10(rI, rL);
 250         Asserts.assertEQ(result, hash(rI + 10, rL + 10));
 251     }
 252 
 253     // Merge value types created in a loop (inlined)
 254     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 255     public long test11(int x, long y) {
 256         MyValue1 v = MyValue1.createWithFieldsInline(x, y);
 257         for (int i = 0; i < 10; ++i) {
 258             v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1);
 259         }
 260         return v.hash();
 261     }
 262 
 263     @DontCompile
 264     public void test11_verifier(boolean warmup) {
 265         long result = test11(rI, rL);
 266         Asserts.assertEQ(result, hash(rI + 10, rL + 10));
 267     }
 268 
 269     // Test loop with uncommon trap referencing a value type
 270     @Test(match = {SCOBJ}, matchCount = {-1 /* at least 1 */}, failOn = LOAD)
 271     public long test12(boolean b) {
 272         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 273         MyValue1[] va = new MyValue1[Math.abs(rI) % 10];
 274         for (int i = 0; i < va.length; ++i) {
 275             va[i] = MyValue1.createWithFieldsInline(rI, rL);
 276         }
 277         long result = rL;
 278         for (int i = 0; i < 1000; ++i) {
 279             if (b) {
 280                 result += v.x;
 281             } else {
 282                 // Uncommon trap referencing v. We delegate allocation to the
 283                 // interpreter by adding a SafePointScalarObjectNode.
 284                 result = v.hashInterpreted();
 285                 for (int j = 0; j < va.length; ++j) {
 286                     result += va[j].hash();
 287                 }
 288             }
 289         }
 290         return result;
 291     }
 292 
 293     @DontCompile
 294     public void test12_verifier(boolean warmup) {
 295         long result = test12(warmup);
 296         Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 297     }
 298 
 299     // Test loop with uncommon trap referencing a value type
 300     @Test
 301     public long test13(boolean b) {
 302         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 303         MyValue1[] va = new MyValue1[Math.abs(rI) % 10];
 304         for (int i = 0; i < va.length; ++i) {
 305             va[i] = MyValue1.createWithFieldsDontInline(rI, rL);
 306         }
 307         long result = rL;
 308         for (int i = 0; i < 1000; ++i) {
 309             if (b) {
 310                 result += v.x;
 311             } else {
 312                 // Uncommon trap referencing v. Should not allocate
 313                 // but just pass the existing oop to the uncommon trap.
 314                 result = v.hashInterpreted();
 315                 for (int j = 0; j < va.length; ++j) {
 316                     result += va[j].hashInterpreted();
 317                 }
 318             }
 319         }
 320         return result;
 321     }
 322 
 323     @DontCompile
 324     public void test13_verifier(boolean warmup) {
 325         long result = test13(warmup);
 326         Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 327     }
 328 
 329     // Create a value type in a non-inlined method and then call a
 330     // non-inlined method on that value type.
 331     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {10})
 332     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP))
 333     public long test14() {
 334         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 335         return v.hashInterpreted();
 336     }
 337 
 338     @DontCompile
 339     public void test14_verifier(boolean b) {
 340         long result = test14();
 341         Asserts.assertEQ(result, hash());
 342     }
 343 
 344     // Create a value type in an inlined method and then call a
 345     // non-inlined method on that value type.
 346     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC))
 347     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})
 348     public long test15() {
 349         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 350         return v.hashInterpreted();
 351     }
 352 
 353     @DontCompile
 354     public void test15_verifier(boolean b) {
 355         long result = test15();
 356         Asserts.assertEQ(result, hash());
 357     }
 358 
 359     // Create a value type in a non-inlined method and then call an
 360     // inlined method on that value type.
 361     @Test(failOn = (ALLOC + STORE + TRAP))
 362     public long test16() {
 363         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 364         return v.hash();
 365     }
 366 
 367     @DontCompile
 368     public void test16_verifier(boolean b) {
 369         long result = test16();
 370         Asserts.assertEQ(result, hash());
 371     }
 372 
 373     // Create a value type in an inlined method and then call an
 374     // inlined method on that value type.
 375     @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
 376     public long test17() {
 377         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 378         return v.hash();
 379     }
 380 
 381     @DontCompile
 382     public void test17_verifier(boolean b) {
 383         long result = test17();
 384         Asserts.assertEQ(result, hash());
 385     }
 386 
 387     // Create a value type in compiled code and pass it to the
 388     // interpreter via a call. The value is live at the first call so
 389     // debug info should include a reference to all its fields.
 390     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 391     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 392     public long test18() {
 393         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 394         v.hashInterpreted();
 395         return v.hashInterpreted();
 396     }
 397 
 398     @DontCompile
 399     public void test18_verifier(boolean warmup) {
 400         long result = test18();
 401         Asserts.assertEQ(result, hash());
 402     }
 403 
 404     // Create a value type in compiled code and pass it to the
 405     // interpreter via a call. The value type is passed twice but
 406     // should only be allocated once.
 407     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 408     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 409     public long test19() {
 410         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 411         return sumValue(v, v);
 412     }
 413 
 414     @DontCompile
 415     public long sumValue(MyValue1 v, MyValue1 dummy) {
 416         return v.hash();
 417     }
 418 
 419     @DontCompile
 420     public void test19_verifier(boolean warmup) {
 421         long result = test19();
 422         Asserts.assertEQ(result, hash());
 423     }
 424 
 425     // Create a value type (array) in compiled code and pass it to the
 426     // interpreter via a call. The value type is live at the uncommon
 427     // trap: verify that deoptimization causes the value type to be
 428     // correctly allocated.
 429     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
 430     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD)
 431     public long test20(boolean deopt) {
 432         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 433         MyValue2[] va = new MyValue2[3];
 434         if (deopt) {
 435             // uncommon trap
 436             WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test20"));
 437         }
 438         return v.hashInterpreted() + va[0].hashInterpreted() +
 439                 va[1].hashInterpreted() + va[2].hashInterpreted();
 440     }
 441 
 442     @DontCompile
 443     public void test20_verifier(boolean warmup) {
 444         MyValue2[] va = new MyValue2[42];
 445         long result = test20(!warmup);
 446         Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash());
 447     }
 448 
 449     // Value type fields in regular object
 450     MyValue1 val1;
 451     MyValue2 val2;
 452     final MyValue1 val3 = MyValue1.createWithFieldsInline(rI, rL);
 453     static MyValue1 val4;
 454     static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL);
 455 
 456     // Test value type fields in objects
 457     @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP))
 458     public long test21(int x, long y) {
 459         // Compute hash of value type fields
 460         long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 461         // Update fields
 462         val1 = MyValue1.createWithFieldsInline(x, y);
 463         val2 = MyValue2.createWithFieldsInline(x, true);
 464         val4 = MyValue1.createWithFieldsInline(x, y);
 465         return result;
 466     }
 467 
 468     @DontCompile
 469     public void test21_verifier(boolean warmup) {
 470         // Check if hash computed by test18 is correct
 471         val1 = MyValue1.createWithFieldsInline(rI, rL);
 472         val2 = val1.v2;
 473         // val3 is initialized in the constructor
 474         val4 = val1;
 475         // val5 is initialized in the static initializer
 476         long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 477         long result = test21(rI + 1, rL + 1);
 478         Asserts.assertEQ(result, hash);
 479         // Check if value type fields were updated
 480         Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
 481         Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, true).hash());
 482         Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
 483     }
 484 
 485     // Test folding of constant value type fields
 486     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 487     public long test22() {
 488         // This should be constant folded
 489         return val5.hash() + val5.v3.hash();
 490     }
 491 
 492     @DontCompile
 493     public void test22_verifier(boolean warmup) {
 494         long result = test22();
 495         Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
 496     }
 497 
 498     // test vdefault
 499     @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP)
 500     public long test23() {
 501         MyValue2 v = MyValue2.createDefaultInline();
 502         return v.hash();
 503     }
 504 
 505     @DontCompile
 506     public void test23_verifier(boolean warmup) {
 507         long result = test23();
 508         Asserts.assertEQ(result, MyValue2.createDefaultInline().hash());
 509     }
 510 
 511     // test vdefault
 512     @Test(failOn = ALLOC + STORE + LOOP + TRAP)
 513     public long test24() {
 514         MyValue1 v1 = MyValue1.createDefaultInline();
 515         MyValue1 v2 = MyValue1.createDefaultDontInline();
 516         return v1.hashPrimitive() + v2.hashPrimitive();
 517     }
 518 
 519     @DontCompile
 520     public void test24_verifier(boolean warmup) {
 521         long result = test24();
 522         Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive());
 523     }
 524 
 525     // test vwithfield
 526     @Test(failOn = ALLOC + LOAD + LOADP + STORE + LOOP + TRAP)
 527     public long test25() {
 528         MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 529         return v.hash();
 530     }
 531 
 532     @DontCompile
 533     public void test25_verifier(boolean warmup) {
 534         long result = test25();
 535         Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash());
 536     }
 537 
 538     // test vwithfield
 539     @Test(failOn = ALLOC + STORE + LOOP + TRAP)
 540     public long test26() {
 541         MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL);
 542         MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL);
 543         return v1.hash() + v2.hash();
 544     }
 545 
 546     @DontCompile
 547     public void test26_verifier(boolean warmup) {
 548         long result = test26();
 549         Asserts.assertEQ(result, 2 * hash());
 550     }
 551 
 552     class TestClass27 {
 553         public MyValue1 v;
 554     }
 555 
 556     // Test allocation elimination of unused object with initialized value type field
 557     @Test(failOn = ALLOC + LOAD + STORE + LOOP)
 558     public void test27(boolean deopt) {
 559         TestClass27 unused = new TestClass27();
 560         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 561         unused.v = v;
 562         if (deopt) {
 563             // uncommon trap
 564             WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test27"));
 565         }
 566     }
 567 
 568     @DontCompile
 569     public void test27_verifier(boolean warmup) {
 570         test27(!warmup);
 571     }
 572 
 573     static MyValue3 staticVal3;
 574     static MyValue3 staticVal3_copy;
 575 
 576     // Check elimination of redundant value type allocations
 577     @Test(match = {ALLOC}, matchCount = {1})
 578     public MyValue3 test28(MyValue3[] va) {
 579         // Create value type and force allocation
 580         MyValue3 vt = MyValue3.create();
 581         va[0] = vt;
 582         staticVal3 = vt;
 583         vt.verify(staticVal3);
 584 
 585         // Value type is now allocated, make a copy and force allocation.
 586         // Because copy is equal to vt, C2 should remove this redundant allocation.
 587         MyValue3 copy = MyValue3.setC(vt, vt.c);
 588         va[0] = copy;
 589         staticVal3_copy = copy;
 590         copy.verify(staticVal3_copy);
 591         return copy;
 592     }
 593 
 594     @DontCompile
 595     public void test28_verifier(boolean warmup) {
 596         MyValue3[] va = new MyValue3[1];
 597         MyValue3 vt = test28(va);
 598         staticVal3.verify(vt);
 599         staticVal3.verify(va[0]);
 600         staticVal3_copy.verify(vt);
 601         staticVal3_copy.verify(va[0]);
 602     }
 603 
 604     // Verify that only dominating allocations are re-used
 605     @Test()
 606     public MyValue3 test29(boolean warmup) {
 607         MyValue3 vt = MyValue3.create();
 608         if (warmup) {
 609             staticVal3 = vt; // Force allocation
 610         }
 611         // Force allocation to verify that above
 612         // non-dominating allocation is not re-used
 613         MyValue3 copy = MyValue3.setC(vt, vt.c);
 614         staticVal3_copy = copy;
 615         copy.verify(vt);
 616         return copy;
 617     }
 618 
 619     @DontCompile
 620     public void test29_verifier(boolean warmup) {
 621         MyValue3 vt = test29(warmup);
 622         if (warmup) {
 623             staticVal3.verify(vt);
 624         }
 625     }
 626 
 627     // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
 628     @Test(failOn = ALLOC + ALLOCA + STORE)
 629     public MyValue3 test30(MyValue3[] va) {
 630         // C2 can re-use the oop of staticVal3 because staticVal3 is equal to copy
 631         MyValue3 copy = MyValue3.copy(staticVal3);
 632         va[0] = copy;
 633         staticVal3 = copy;
 634         copy.verify(staticVal3);
 635         return copy;
 636     }
 637 
 638     @DontCompile
 639     public void test30_verifier(boolean warmup) {
 640         staticVal3 = MyValue3.create();
 641         MyValue3[] va = new MyValue3[1];
 642         MyValue3 vt = test30(va);
 643         staticVal3.verify(vt);
 644         staticVal3.verify(va[0]);
 645     }
 646 
 647     // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
 648     @Test(valid = ValueTypeReturnedAsFieldsOff, failOn = ALLOC + ALLOCA + STORE)
 649     @Test(valid = ValueTypeReturnedAsFieldsOn)
 650     public MyValue3 test31(MyValue3[] va) {
 651         // C2 can re-use the oop returned by createDontInline()
 652         // because the corresponding value type is equal to 'copy'.
 653         MyValue3 copy = MyValue3.copy(MyValue3.createDontInline());
 654         va[0] = copy;
 655         staticVal3 = copy;
 656         copy.verify(staticVal3);
 657         return copy;
 658     }
 659 
 660     @DontCompile
 661     public void test31_verifier(boolean warmup) {
 662         MyValue3[] va = new MyValue3[1];
 663         MyValue3 vt = test31(va);
 664         staticVal3.verify(vt);
 665         staticVal3.verify(va[0]);
 666     }
 667 
 668     // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
 669     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + ALLOCA + STORE)
 670     @Test(valid = ValueTypePassFieldsAsArgsOn)
 671     public MyValue3 test32(MyValue3 vt, MyValue3[] va) {
 672         // C2 can re-use the oop of vt because vt is equal to 'copy'.
 673         MyValue3 copy = MyValue3.copy(vt);
 674         va[0] = copy;
 675         staticVal3 = copy;
 676         copy.verify(staticVal3);
 677         return copy;
 678     }
 679 
 680     @DontCompile
 681     public void test32_verifier(boolean warmup) {
 682         MyValue3 vt = MyValue3.create();
 683         MyValue3[] va = new MyValue3[1];
 684         MyValue3 result = test32(vt, va);
 685         staticVal3.verify(vt);
 686         va[0].verify(vt);
 687         result.verify(vt);
 688     }
 689 
 690     // Test correct identification of value type copies
 691     @Test()
 692     public MyValue3 test33(MyValue3[] va) {
 693         MyValue3 vt = MyValue3.copy(staticVal3);
 694         vt = MyValue3.setI(vt, vt.c);
 695         // vt is not equal to staticVal3, so C2 should not re-use the oop
 696         va[0] = vt;
 697         staticVal3 = vt;
 698         vt.verify(staticVal3);
 699         return vt;
 700     }
 701 
 702     @DontCompile
 703     public void test33_verifier(boolean warmup) {
 704         staticVal3 = MyValue3.create();
 705         MyValue3[] va = new MyValue3[1];
 706         MyValue3 vt = test33(va);
 707         Asserts.assertEQ(staticVal3.i, (int)staticVal3.c);
 708         Asserts.assertEQ(va[0].i, (int)staticVal3.c);
 709         Asserts.assertEQ(vt.i, (int)staticVal3.c);
 710     }
 711 
 712     // Test __Value in the method signature
 713     @DontInline
 714     public __Value test34_callee(__Value vt) {
 715         return vt;
 716     }
 717 
 718     @Test()
 719     public __Value test34(boolean b, __Value vt) throws Throwable {
 720         if (b) {
 721             return test34_callee(vt);
 722         } else {
 723             return MyValue1.createWithFieldsInline(rI + 1, rL + 1);
 724         }
 725     }
 726 
 727     @DontCompile
 728     public void test34_verifier(boolean warmup) throws Throwable {
 729         test34(true, MyValue1.createWithFieldsInline(rI, rL));
 730         test34(false, MyValue1.createWithFieldsInline(rI, rL));
 731     }
 732 
 733     // Verify that the default value type is never allocated.
 734     // C2 code should load and use the default oop from the java mirror.
 735     @Test(failOn = ALLOC + ALLOCA + LOAD + STORE + LOOP + TRAP)
 736     public MyValue3 test35(MyValue3[] va) {
 737         // Explicitly create default value
 738         MyValue3 vt = MyValue3.createDefault();
 739         va[0] = vt;
 740         staticVal3 = vt;
 741         vt.verify(vt);
 742 
 743         // Load default value from uninitialized value array
 744         MyValue3[] dva = new MyValue3[1];
 745         staticVal3_copy = dva[0];
 746         va[1] = dva[0];
 747         dva[0].verify(dva[0]);
 748         return vt;
 749     }
 750 
 751     @DontCompile
 752     public void test35_verifier(boolean warmup) {
 753         MyValue3 vt = MyValue3.createDefault();
 754         MyValue3[] va = new MyValue3[2];
 755         va[0] = MyValue3.create();
 756         va[1] = MyValue3.create();
 757         MyValue3 res = test35(va);
 758         res.verify(vt);
 759         staticVal3.verify(vt);
 760         staticVal3_copy.verify(vt);
 761         va[0].verify(vt);
 762         va[1].verify(vt);
 763     }
 764 
 765     // Same as above but manually initialize value type fields to default.
 766     @Test(failOn = ALLOC + ALLOCA + LOAD + STORE + LOOP + TRAP)
 767     public MyValue3 test36(MyValue3 vt, MyValue3[] va) {
 768         vt = MyValue3.setC(vt, (char)0);
 769         vt = MyValue3.setBB(vt, (byte)0);
 770         vt = MyValue3.setS(vt, (short)0);
 771         vt = MyValue3.setI(vt, 0);
 772         vt = MyValue3.setL(vt, 0);
 773         vt = MyValue3.setO(vt, null);
 774         vt = MyValue3.setF1(vt, 0);
 775         vt = MyValue3.setF2(vt, 0);
 776         vt = MyValue3.setF3(vt, 0);
 777         vt = MyValue3.setF4(vt, 0);
 778         vt = MyValue3.setF5(vt, 0);
 779         vt = MyValue3.setF6(vt, 0);
 780         vt = MyValue3.setV1(vt, MyValue3Inline.createDefault());
 781         va[0] = vt;
 782         staticVal3 = vt;
 783         vt.verify(vt);
 784         return vt;
 785     }
 786 
 787     @DontCompile
 788     public void test36_verifier(boolean warmup) {
 789         MyValue3 vt = MyValue3.createDefault();
 790         MyValue3[] va = new MyValue3[1];
 791         va[0] = MyValue3.create();
 792         MyValue3 res = test36(va[0], va);
 793         res.verify(vt);
 794         staticVal3.verify(vt);
 795         va[0].verify(vt);
 796     }
 797 }