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