1 /*
   2  * Copyright (c) 2017, 2019, 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 TestBasicFunctionality.java
  34  * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
  35  * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  36  *                               -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI
  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:ValueArrayElemMaxFlatSize=0"};
  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, 14}, 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(failOn = ALLOC + STORE + TRAP)
 170     public long test8(boolean b) {
 171         MyValue1 v;
 172         if (b) {
 173             v = MyValue1.createWithFieldsInline(rI, rL);
 174         } else {
 175             v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1);
 176         }
 177         return v.hash();
 178     }
 179 
 180     @DontCompile
 181     public void test8_verifier(boolean warmup) {
 182         Asserts.assertEQ(test8(true), hash());
 183         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 184     }
 185 
 186     // Merge value types created from two branches
 187     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {12}, failOn = TRAP + ALLOC + STORE)
 188     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 12}, failOn = LOAD + TRAP)
 189     public MyValue1 test9(boolean b, int localrI, long localrL) {
 190         MyValue1 v;
 191         if (b) {
 192             // Value type is not allocated
 193             // Do not use rI/rL directly here as null values may cause
 194             // some redundant null initializations to be optimized out
 195             // and matching to fail.
 196             v = MyValue1.createWithFieldsInline(localrI, localrL);
 197         } else {
 198             // Value type is allocated by the callee
 199             v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1);
 200         }
 201         // Need to allocate value type if 'b' is true
 202         long sum = v.hashInterpreted();
 203         if (b) {
 204             v = MyValue1.createWithFieldsDontInline(rI, sum);
 205         } else {
 206             v = MyValue1.createWithFieldsDontInline(rI, sum + 1);
 207         }
 208         // Don't need to allocate value type because both branches allocate
 209         return v;
 210     }
 211 
 212     @DontCompile
 213     public void test9_verifier(boolean warmup) {
 214         MyValue1 v = test9(true, rI, rL);
 215         Asserts.assertEQ(v.x, rI);
 216         Asserts.assertEQ(v.y, hash());
 217         v = test9(false, rI, rL);
 218         Asserts.assertEQ(v.x, rI);
 219         Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1);
 220     }
 221 
 222     // Merge value types created in a loop (not inlined)
 223     @Test(failOn = ALLOC + STORE + TRAP)
 224     public long test10(int x, long y) {
 225         MyValue1 v = MyValue1.createWithFieldsDontInline(x, y);
 226         for (int i = 0; i < 10; ++i) {
 227             v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1);
 228         }
 229         return v.hash();
 230     }
 231 
 232     @DontCompile
 233     public void test10_verifier(boolean warmup) {
 234         long result = test10(rI, rL);
 235         Asserts.assertEQ(result, hash(rI + 10, rL + 10));
 236     }
 237 
 238     // Merge value types created in a loop (inlined)
 239     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 240     public long test11(int x, long y) {
 241         MyValue1 v = MyValue1.createWithFieldsInline(x, y);
 242         for (int i = 0; i < 10; ++i) {
 243             v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1);
 244         }
 245         return v.hash();
 246     }
 247 
 248     @DontCompile
 249     public void test11_verifier(boolean warmup) {
 250         long result = test11(rI, rL);
 251         Asserts.assertEQ(result, hash(rI + 10, rL + 10));
 252     }
 253 
 254     // Test loop with uncommon trap referencing a value type
 255     @Test(match = {SCOBJ}, matchCount = {-1 /* at least 1 */}, failOn = LOAD)
 256     public long test12(boolean b) {
 257         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 258         MyValue1[] va = new MyValue1[Math.abs(rI) % 10];
 259         for (int i = 0; i < va.length; ++i) {
 260             va[i] = MyValue1.createWithFieldsInline(rI, rL);
 261         }
 262         long result = rL;
 263         for (int i = 0; i < 1000; ++i) {
 264             if (b) {
 265                 result += v.x;
 266             } else {
 267                 // Uncommon trap referencing v. We delegate allocation to the
 268                 // interpreter by adding a SafePointScalarObjectNode.
 269                 result = v.hashInterpreted();
 270                 for (int j = 0; j < va.length; ++j) {
 271                     result += va[j].hash();
 272                 }
 273             }
 274         }
 275         return result;
 276     }
 277 
 278     @DontCompile
 279     public void test12_verifier(boolean warmup) {
 280         long result = test12(warmup);
 281         Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 282     }
 283 
 284     // Test loop with uncommon trap referencing a value type
 285     @Test
 286     public long test13(boolean b) {
 287         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 288         MyValue1[] va = new MyValue1[Math.abs(rI) % 10];
 289         for (int i = 0; i < va.length; ++i) {
 290             va[i] = MyValue1.createWithFieldsDontInline(rI, rL);
 291         }
 292         long result = rL;
 293         for (int i = 0; i < 1000; ++i) {
 294             if (b) {
 295                 result += v.x;
 296             } else {
 297                 // Uncommon trap referencing v. Should not allocate
 298                 // but just pass the existing oop to the uncommon trap.
 299                 result = v.hashInterpreted();
 300                 for (int j = 0; j < va.length; ++j) {
 301                     result += va[j].hashInterpreted();
 302                 }
 303             }
 304         }
 305         return result;
 306     }
 307 
 308     @DontCompile
 309     public void test13_verifier(boolean warmup) {
 310         long result = test13(warmup);
 311         Asserts.assertEQ(result, warmup ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 312     }
 313 
 314     // Create a value type in a non-inlined method and then call a
 315     // non-inlined method on that value type.
 316     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {12})
 317     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP))
 318     public long test14() {
 319         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 320         return v.hashInterpreted();
 321     }
 322 
 323     @DontCompile
 324     public void test14_verifier(boolean b) {
 325         long result = test14();
 326         Asserts.assertEQ(result, hash());
 327     }
 328 
 329     // Create a value type in an inlined method and then call a
 330     // non-inlined method on that value type.
 331     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC))
 332     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})
 333     public long test15() {
 334         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 335         return v.hashInterpreted();
 336     }
 337 
 338     @DontCompile
 339     public void test15_verifier(boolean b) {
 340         long result = test15();
 341         Asserts.assertEQ(result, hash());
 342     }
 343 
 344     // Create a value type in a non-inlined method and then call an
 345     // inlined method on that value type.
 346     @Test(failOn = (ALLOC + STORE + TRAP))
 347     public long test16() {
 348         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 349         return v.hash();
 350     }
 351 
 352     @DontCompile
 353     public void test16_verifier(boolean b) {
 354         long result = test16();
 355         Asserts.assertEQ(result, hash());
 356     }
 357 
 358     // Create a value type in an inlined method and then call an
 359     // inlined method on that value type.
 360     @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
 361     public long test17() {
 362         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 363         return v.hash();
 364     }
 365 
 366     @DontCompile
 367     public void test17_verifier(boolean b) {
 368         long result = test17();
 369         Asserts.assertEQ(result, hash());
 370     }
 371 
 372     // Create a value type in compiled code and pass it to the
 373     // interpreter via a call. The value is live at the first call so
 374     // debug info should include a reference to all its fields.
 375     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 376     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 377     public long test18() {
 378         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 379         v.hashInterpreted();
 380         return v.hashInterpreted();
 381     }
 382 
 383     @DontCompile
 384     public void test18_verifier(boolean warmup) {
 385         long result = test18();
 386         Asserts.assertEQ(result, hash());
 387     }
 388 
 389     // Create a value type in compiled code and pass it to the
 390     // interpreter via a call. The value type is passed twice but
 391     // should only be allocated once.
 392     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 393     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 394     public long test19() {
 395         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 396         return sumValue(v, v);
 397     }
 398 
 399     @DontCompile
 400     public long sumValue(MyValue1 v, MyValue1 dummy) {
 401         return v.hash();
 402     }
 403 
 404     @DontCompile
 405     public void test19_verifier(boolean warmup) {
 406         long result = test19();
 407         Asserts.assertEQ(result, hash());
 408     }
 409 
 410     // Create a value type (array) in compiled code and pass it to the
 411     // interpreter via a call. The value type is live at the uncommon
 412     // trap: verify that deoptimization causes the value type to be
 413     // correctly allocated.
 414     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
 415     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD)
 416     public long test20(boolean deopt) {
 417         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 418         MyValue2[] va = new MyValue2[3];
 419         if (deopt) {
 420             // uncommon trap
 421             WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test20"));
 422         }
 423         return v.hashInterpreted() + va[0].hashInterpreted() +
 424                 va[1].hashInterpreted() + va[2].hashInterpreted();
 425     }
 426 
 427     @DontCompile
 428     public void test20_verifier(boolean warmup) {
 429         MyValue2[] va = new MyValue2[42];
 430         long result = test20(!warmup);
 431         Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash());
 432     }
 433 
 434     // Value type fields in regular object
 435     MyValue1 val1;
 436     MyValue2 val2;
 437     final MyValue1 val3 = MyValue1.createWithFieldsInline(rI, rL);
 438     static MyValue1 val4;
 439     static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL);
 440 
 441     // Test value type fields in objects
 442     @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP))
 443     public long test21(int x, long y) {
 444         // Compute hash of value type fields
 445         long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 446         // Update fields
 447         val1 = MyValue1.createWithFieldsInline(x, y);
 448         val2 = MyValue2.createWithFieldsInline(x, true);
 449         val4 = MyValue1.createWithFieldsInline(x, y);
 450         return result;
 451     }
 452 
 453     @DontCompile
 454     public void test21_verifier(boolean warmup) {
 455         // Check if hash computed by test18 is correct
 456         val1 = MyValue1.createWithFieldsInline(rI, rL);
 457         val2 = val1.v2;
 458         // val3 is initialized in the constructor
 459         val4 = val1;
 460         // val5 is initialized in the static initializer
 461         long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 462         long result = test21(rI + 1, rL + 1);
 463         Asserts.assertEQ(result, hash);
 464         // Check if value type fields were updated
 465         Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
 466         Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, true).hash());
 467         Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
 468     }
 469 
 470     // Test folding of constant value type fields
 471     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 472     public long test22() {
 473         // This should be constant folded
 474         return val5.hash() + val5.v3.hash();
 475     }
 476 
 477     @DontCompile
 478     public void test22_verifier(boolean warmup) {
 479         long result = test22();
 480         Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
 481     }
 482 
 483     // Test defaultvalue
 484     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 485     public long test23() {
 486         MyValue2 v = MyValue2.createDefaultInline();
 487         return v.hash();
 488     }
 489 
 490     @DontCompile
 491     public void test23_verifier(boolean warmup) {
 492         long result = test23();
 493         Asserts.assertEQ(result, MyValue2.createDefaultInline().hash());
 494     }
 495 
 496     // Test defaultvalue
 497     @Test(failOn = ALLOC + STORE + LOOP + TRAP)
 498     public long test24() {
 499         MyValue1 v1 = MyValue1.createDefaultInline();
 500         MyValue1 v2 = MyValue1.createDefaultDontInline();
 501         return v1.hashPrimitive() + v2.hashPrimitive();
 502     }
 503 
 504     @DontCompile
 505     public void test24_verifier(boolean warmup) {
 506         long result = test24();
 507         Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive());
 508     }
 509 
 510     // Test withfield
 511     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 512     public long test25() {
 513         MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 514         return v.hash();
 515     }
 516 
 517     @DontCompile
 518     public void test25_verifier(boolean warmup) {
 519         long result = test25();
 520         Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, true).hash());
 521     }
 522 
 523     // Test withfield
 524     @Test(failOn = ALLOC + STORE + LOOP + TRAP)
 525     public long test26() {
 526         MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL);
 527         MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL);
 528         return v1.hash() + v2.hash();
 529     }
 530 
 531     @DontCompile
 532     public void test26_verifier(boolean warmup) {
 533         long result = test26();
 534         Asserts.assertEQ(result, 2 * hash());
 535     }
 536 
 537     class TestClass27 {
 538         public MyValue1 v;
 539     }
 540 
 541     // Test allocation elimination of unused object with initialized value type field
 542     @Test(failOn = ALLOC + LOAD + STORE + LOOP)
 543     public void test27(boolean deopt) {
 544         TestClass27 unused = new TestClass27();
 545         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 546         unused.v = v;
 547         if (deopt) {
 548             // uncommon trap
 549             WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test27"));
 550         }
 551     }
 552 
 553     @DontCompile
 554     public void test27_verifier(boolean warmup) {
 555         test27(!warmup);
 556     }
 557 
 558     static MyValue3 staticVal3;
 559     static MyValue3 staticVal3_copy;
 560 
 561     // Check elimination of redundant value type allocations
 562     @Test(match = {ALLOC}, matchCount = {1})
 563     public MyValue3 test28(MyValue3[] va) {
 564         // Create value type and force allocation
 565         MyValue3 vt = MyValue3.create();
 566         va[0] = vt;
 567         staticVal3 = vt;
 568         vt.verify(staticVal3);
 569 
 570         // Value type is now allocated, make a copy and force allocation.
 571         // Because copy is equal to vt, C2 should remove this redundant allocation.
 572         MyValue3 copy = MyValue3.setC(vt, vt.c);
 573         va[0] = copy;
 574         staticVal3_copy = copy;
 575         copy.verify(staticVal3_copy);
 576         return copy;
 577     }
 578 
 579     @DontCompile
 580     public void test28_verifier(boolean warmup) {
 581         MyValue3[] va = new MyValue3[1];
 582         MyValue3 vt = test28(va);
 583         staticVal3.verify(vt);
 584         staticVal3.verify(va[0]);
 585         staticVal3_copy.verify(vt);
 586         staticVal3_copy.verify(va[0]);
 587     }
 588 
 589     // Verify that only dominating allocations are re-used
 590     @Test()
 591     public MyValue3 test29(boolean warmup) {
 592         MyValue3 vt = MyValue3.create();
 593         if (warmup) {
 594             staticVal3 = vt; // Force allocation
 595         }
 596         // Force allocation to verify that above
 597         // non-dominating allocation is not re-used
 598         MyValue3 copy = MyValue3.setC(vt, vt.c);
 599         staticVal3_copy = copy;
 600         copy.verify(vt);
 601         return copy;
 602     }
 603 
 604     @DontCompile
 605     public void test29_verifier(boolean warmup) {
 606         MyValue3 vt = test29(warmup);
 607         if (warmup) {
 608             staticVal3.verify(vt);
 609         }
 610     }
 611 
 612     // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
 613     @Test(failOn = ALLOC + ALLOCA + STORE)
 614     public MyValue3 test30(MyValue3[] va) {
 615         // C2 can re-use the oop of staticVal3 because staticVal3 is equal to copy
 616         MyValue3 copy = MyValue3.copy(staticVal3);
 617         va[0] = copy;
 618         staticVal3 = copy;
 619         copy.verify(staticVal3);
 620         return copy;
 621     }
 622 
 623     @DontCompile
 624     public void test30_verifier(boolean warmup) {
 625         staticVal3 = MyValue3.create();
 626         MyValue3[] va = new MyValue3[1];
 627         MyValue3 vt = test30(va);
 628         staticVal3.verify(vt);
 629         staticVal3.verify(va[0]);
 630     }
 631 
 632     // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
 633     @Test(valid = ValueTypeReturnedAsFieldsOn)
 634     @Test(valid = ValueTypeReturnedAsFieldsOff, failOn = ALLOC + ALLOCA + STORE)
 635     public MyValue3 test31(MyValue3[] va) {
 636         // C2 can re-use the oop returned by createDontInline()
 637         // because the corresponding value type is equal to 'copy'.
 638         MyValue3 copy = MyValue3.copy(MyValue3.createDontInline());
 639         va[0] = copy;
 640         staticVal3 = copy;
 641         copy.verify(staticVal3);
 642         return copy;
 643     }
 644 
 645     @DontCompile
 646     public void test31_verifier(boolean warmup) {
 647         MyValue3[] va = new MyValue3[1];
 648         MyValue3 vt = test31(va);
 649         staticVal3.verify(vt);
 650         staticVal3.verify(va[0]);
 651     }
 652 
 653     // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
 654     @Test(valid = ValueTypePassFieldsAsArgsOn)
 655     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + ALLOCA + STORE)
 656     public MyValue3 test32(MyValue3 vt, MyValue3[] va) {
 657         // C2 can re-use the oop of vt because vt is equal to 'copy'.
 658         MyValue3 copy = MyValue3.copy(vt);
 659         va[0] = copy;
 660         staticVal3 = copy;
 661         copy.verify(staticVal3);
 662         return copy;
 663     }
 664 
 665     @DontCompile
 666     public void test32_verifier(boolean warmup) {
 667         MyValue3 vt = MyValue3.create();
 668         MyValue3[] va = new MyValue3[1];
 669         MyValue3 result = test32(vt, va);
 670         staticVal3.verify(vt);
 671         va[0].verify(vt);
 672         result.verify(vt);
 673     }
 674 
 675     // Test correct identification of value type copies
 676     @Test()
 677     public MyValue3 test33(MyValue3[] va) {
 678         MyValue3 vt = MyValue3.copy(staticVal3);
 679         vt = MyValue3.setI(vt, vt.c);
 680         // vt is not equal to staticVal3, so C2 should not re-use the oop
 681         va[0] = vt;
 682         staticVal3 = vt;
 683         vt.verify(staticVal3);
 684         return vt;
 685     }
 686 
 687     @DontCompile
 688     public void test33_verifier(boolean warmup) {
 689         staticVal3 = MyValue3.create();
 690         MyValue3[] va = new MyValue3[1];
 691         MyValue3 vt = test33(va);
 692         Asserts.assertEQ(staticVal3.i, (int)staticVal3.c);
 693         Asserts.assertEQ(va[0].i, (int)staticVal3.c);
 694         Asserts.assertEQ(vt.i, (int)staticVal3.c);
 695     }
 696 
 697     // Verify that the default value type is never allocated.
 698     // C2 code should load and use the default oop from the java mirror.
 699     @Test(failOn = ALLOC + ALLOCA + LOAD + STORE + LOOP + TRAP)
 700     public MyValue3 test34(MyValue3[] va) {
 701         // Explicitly create default value
 702         MyValue3 vt = MyValue3.createDefault();
 703         va[0] = vt;
 704         staticVal3 = vt;
 705         vt.verify(vt);
 706 
 707         // Load default value from uninitialized value array
 708         MyValue3[] dva = new MyValue3[1];
 709         staticVal3_copy = dva[0];
 710         va[1] = dva[0];
 711         dva[0].verify(dva[0]);
 712         return vt;
 713     }
 714 
 715     @DontCompile
 716     public void test34_verifier(boolean warmup) {
 717         MyValue3 vt = MyValue3.createDefault();
 718         MyValue3[] va = new MyValue3[2];
 719         va[0] = MyValue3.create();
 720         va[1] = MyValue3.create();
 721         MyValue3 res = test34(va);
 722         res.verify(vt);
 723         staticVal3.verify(vt);
 724         staticVal3_copy.verify(vt);
 725         va[0].verify(vt);
 726         va[1].verify(vt);
 727     }
 728 
 729     // Same as above but manually initialize value type fields to default.
 730     @Test(failOn = ALLOC + ALLOCA + LOAD + STORE + LOOP + TRAP)
 731     public MyValue3 test35(MyValue3 vt, MyValue3[] va) {
 732         vt = MyValue3.setC(vt, (char)0);
 733         vt = MyValue3.setBB(vt, (byte)0);
 734         vt = MyValue3.setS(vt, (short)0);
 735         vt = MyValue3.setI(vt, 0);
 736         vt = MyValue3.setL(vt, 0);
 737         vt = MyValue3.setO(vt, null);
 738         vt = MyValue3.setF1(vt, 0);
 739         vt = MyValue3.setF2(vt, 0);
 740         vt = MyValue3.setF3(vt, 0);
 741         vt = MyValue3.setF4(vt, 0);
 742         vt = MyValue3.setF5(vt, 0);
 743         vt = MyValue3.setF6(vt, 0);
 744         vt = MyValue3.setV1(vt, MyValue3Inline.createDefault());
 745         va[0] = vt;
 746         staticVal3 = vt;
 747         vt.verify(vt);
 748         return vt;
 749     }
 750 
 751     @DontCompile
 752     public void test35_verifier(boolean warmup) {
 753         MyValue3 vt = MyValue3.createDefault();
 754         MyValue3[] va = new MyValue3[1];
 755         va[0] = MyValue3.create();
 756         MyValue3 res = test35(va[0], va);
 757         res.verify(vt);
 758         staticVal3.verify(vt);
 759         va[0].verify(vt);
 760     }
 761 
 762     // Merge value types created from two branches
 763 
 764     private Object test36_helper(Object v) {
 765         return v;
 766     }
 767 
 768     @Test(failOn = ALLOC + STORE + TRAP)
 769     public long test36(boolean b) {
 770         Object o;
 771         if (b) {
 772             o = test36_helper(MyValue1.createWithFieldsInline(rI, rL));
 773         } else {
 774             o = test36_helper(MyValue1.createWithFieldsDontInline(rI + 1, rL + 1));
 775         }
 776         MyValue1 v = (MyValue1)o;
 777         return v.hash();
 778     }
 779 
 780     @DontCompile
 781     public void test36_verifier(boolean warmup) {
 782         Asserts.assertEQ(test36(true), hash());
 783         Asserts.assertEQ(test36(false), hash(rI + 1, rL + 1));
 784     }
 785 
 786     // Test correct loading of flattened fields
 787     inline class Test37Value2 {
 788         final int x = 0;
 789         final int y = 0;
 790     }
 791 
 792     inline class Test37Value1 {
 793         final double d = 0;
 794         final float f = 0;
 795         final Test37Value2 v = new Test37Value2();
 796     }
 797 
 798     @Test
 799     public Test37Value1 test37(Test37Value1 vt) {
 800         return vt;
 801     }
 802 
 803     @DontCompile
 804     public void test37_verifier(boolean warmup) {
 805         Test37Value1 vt = new Test37Value1();
 806         Asserts.assertEQ(test37(vt), vt);
 807     }
 808 }