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