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