1 /*
   2  * Copyright (c) 2021, 2024, 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.inlinetypes;
  25 
  26 import compiler.lib.ir_framework.*;
  27 import jdk.test.lib.Asserts;
  28 
  29 import java.lang.reflect.Method;
  30 
  31 import jdk.internal.value.ValueClass;
  32 import jdk.internal.vm.annotation.ImplicitlyConstructible;
  33 import jdk.internal.vm.annotation.LooselyConsistentValue;
  34 import jdk.internal.vm.annotation.NullRestricted;
  35 
  36 import static compiler.valhalla.inlinetypes.InlineTypeIRNode.*;
  37 import static compiler.valhalla.inlinetypes.InlineTypes.*;
  38 
  39 /*
  40  * @test
  41  * @key randomness
  42  * @bug 8327695
  43  * @summary Test the basic value class implementation in C2.
  44  * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64")
  45  * @library /test/lib /
  46  * @enablePreview
  47  * @modules java.base/jdk.internal.value
  48  *          java.base/jdk.internal.vm.annotation
  49  * @run main/othervm/timeout=300 compiler.valhalla.inlinetypes.TestBasicFunctionality
  50  */
  51 
  52 @ForceCompileClassInitializer
  53 public class TestBasicFunctionality {
  54 
  55     public static void main(String[] args) {
  56         InlineTypes.getFramework()
  57                    .addScenarios(InlineTypes.DEFAULT_SCENARIOS)
  58                    .addHelperClasses(MyValue1.class,
  59                                      MyValue2.class,
  60                                      MyValue2Inline.class,
  61                                      MyValue3.class,
  62                                      MyValue3Inline.class)
  63                    .start();
  64     }
  65 
  66     protected long hash() {
  67         return hash(rI, rL);
  68     }
  69 
  70     protected long hash(int x, long y) {
  71         return MyValue1.createWithFieldsInline(x, y).hash();
  72     }
  73 
  74     // Receive value class through call to interpreter
  75     @Test
  76     @IR(failOn = {ALLOC, STORE, TRAP})
  77     public long test1() {
  78         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
  79         return v.hash();
  80     }
  81 
  82     @Run(test = "test1")
  83     public void test1_verifier() {
  84         long result = test1();
  85         Asserts.assertEQ(result, hash());
  86     }
  87 
  88     // Receive value object from interpreter via parameter
  89     @Test
  90     @IR(failOn = {ALLOC, STORE, TRAP})
  91     public long test2(MyValue1 v) {
  92         return v.hash();
  93     }
  94 
  95     @Run(test = "test2")
  96     public void test2_verifier() {
  97         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
  98         long result = test2(v);
  99         Asserts.assertEQ(result, hash());
 100     }
 101 
 102     // Return incoming value object without accessing fields
 103     @Test
 104     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 105         counts = {ALLOC, "= 1", STORE, "= 19"},
 106         failOn = {LOAD, TRAP})
 107     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 108         failOn = {ALLOC, LOAD, STORE, TRAP})
 109     public MyValue1 test3(MyValue1 v) {
 110         return v;
 111     }
 112 
 113     @Run(test = "test3")
 114     public void test3_verifier() {
 115         MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL);
 116         MyValue1 v2 = test3(v1);
 117         Asserts.assertEQ(v1.x, v2.x);
 118         Asserts.assertEQ(v1.y, v2.y);
 119     }
 120 
 121     // Create a value object in compiled code and only use fields.
 122     // Allocation should go away because value object does not escape.
 123     @Test
 124     @IR(failOn = {ALLOC, LOAD, STORE, TRAP})
 125     public long test4() {
 126         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 127         return v.hash();
 128     }
 129 
 130     @Run(test = "test4")
 131     public void test4_verifier() {
 132         long result = test4();
 133         Asserts.assertEQ(result, hash());
 134     }
 135 
 136     // Create a value object in compiled code and pass it to
 137     // an inlined compiled method via a call.
 138     @Test
 139     @IR(failOn = {ALLOC, LOAD, STORE, TRAP})
 140     public long test5() {
 141         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 142         return test5Inline(v);
 143     }
 144 
 145     @ForceInline
 146     public long test5Inline(MyValue1 v) {
 147         return v.hash();
 148     }
 149 
 150     @Run(test = "test5")
 151     public void test5_verifier() {
 152         long result = test5();
 153         Asserts.assertEQ(result, hash());
 154     }
 155 
 156     // Create a value object in compiled code and pass it to
 157     // the interpreter via a call.
 158     @Test
 159     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 160         counts = {ALLOC, "<= 1"}, // 1 MyValue2 allocation (if not the default value)
 161         failOn = {LOAD, TRAP})
 162     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 163         counts = {ALLOC, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the default value)
 164         failOn = {LOAD, TRAP})
 165     public long test6() {
 166         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 167         // Pass to interpreter
 168         return v.hashInterpreted();
 169     }
 170 
 171     @Run(test = "test6")
 172     public void test6_verifier() {
 173         long result = test6();
 174         Asserts.assertEQ(result, hash());
 175     }
 176 
 177     // Create a value object in compiled code and pass it to
 178     // the interpreter by returning.
 179     @Test
 180     @IR(counts = {ALLOC, "<= 2"},
 181         failOn = {LOAD, TRAP})
 182     public MyValue1 test7(int x, long y) {
 183         return MyValue1.createWithFieldsInline(x, y);
 184     }
 185 
 186     @Run(test = "test7")
 187     public void test7_verifier() {
 188         MyValue1 v = test7(rI, rL);
 189         Asserts.assertEQ(v.hash(), hash());
 190     }
 191 
 192     // Merge value objects created from two branches
 193     @Test
 194     @IR(failOn = {ALLOC, STORE, TRAP})
 195     public long test8(boolean b) {
 196         MyValue1 v;
 197         if (b) {
 198             v = MyValue1.createWithFieldsInline(rI, rL);
 199         } else {
 200             v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1);
 201         }
 202         return v.hash();
 203     }
 204 
 205     @Run(test = "test8")
 206     public void test8_verifier() {
 207         Asserts.assertEQ(test8(true), hash());
 208         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 209     }
 210 
 211 static MyValue1 tmp = null;
 212     // Merge value objects created from two branches
 213     @Test
 214     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 215         counts = {ALLOC, "= 1", LOAD, "= 19",
 216                   STORE, "= 3"}, // InitializeNode::coalesce_subword_stores merges stores
 217         failOn = {TRAP})
 218     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 219         counts = {ALLOC, "= 2", STORE, "= 19"},
 220         failOn = {LOAD, TRAP})
 221     public MyValue1 test9(boolean b, int localrI, long localrL) {
 222         MyValue1 v;
 223         if (b) {
 224             // Value object is not allocated
 225             // Do not use rI/rL directly here as null values may cause
 226             // some redundant null initializations to be optimized out
 227             // and matching to fail.
 228             v = MyValue1.createWithFieldsInline(localrI, localrL);
 229             v.hashInterpreted();
 230         } else {
 231             // Value object is allocated by the callee
 232             v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1);
 233         }
 234         // Need to allocate value object if 'b' is true
 235         long sum = v.hashInterpreted();
 236         if (b) {
 237             v = MyValue1.createWithFieldsDontInline(rI, sum);
 238         } else {
 239             v = MyValue1.createWithFieldsDontInline(rI, sum + 1);
 240         }
 241         // Don't need to allocate value object because both branches allocate
 242         return v;
 243     }
 244 
 245     @Run(test = "test9")
 246     public void test9_verifier() {
 247         MyValue1 v = test9(true, rI, rL);
 248         Asserts.assertEQ(v.x, rI);
 249         Asserts.assertEQ(v.y, hash());
 250         v = test9(false, rI, rL);
 251         Asserts.assertEQ(v.x, rI);
 252         Asserts.assertEQ(v.y, hash(rI + 1, rL + 1) + 1);
 253     }
 254 
 255     // Merge value objects created in a loop (not inlined)
 256     @Test
 257     @IR(failOn = {ALLOC, STORE, TRAP})
 258     public long test10(int x, long y) {
 259         MyValue1 v = MyValue1.createWithFieldsDontInline(x, y);
 260         for (int i = 0; i < 10; ++i) {
 261             v = MyValue1.createWithFieldsDontInline(v.x + 1, v.y + 1);
 262         }
 263         return v.hash();
 264     }
 265 
 266     @Run(test = "test10")
 267     public void test10_verifier() {
 268         long result = test10(rI, rL);
 269         Asserts.assertEQ(result, hash(rI + 10, rL + 10));
 270     }
 271 
 272     // Merge value objects created in a loop (inlined)
 273     @Test
 274     @IR(failOn = {ALLOC, LOAD, STORE, TRAP})
 275     public long test11(int x, long y) {
 276         MyValue1 v = MyValue1.createWithFieldsInline(x, y);
 277         for (int i = 0; i < 10; ++i) {
 278             v = MyValue1.createWithFieldsInline(v.x + 1, v.y + 1);
 279         }
 280         return v.hash();
 281     }
 282 
 283     @Run(test = "test11")
 284     public void test11_verifier() {
 285         long result = test11(rI, rL);
 286         Asserts.assertEQ(result, hash(rI + 10, rL + 10));
 287     }
 288 
 289     // Test loop with uncommon trap referencing a value object
 290     // TODO 8315003 Re-enable
 291     /*
 292     @Test
 293     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 294         counts = {SCOBJ, ">= 1", LOAD, "<= 12"}) // TODO 8227588 (loads should be removed)
 295     public long test12(boolean b) {
 296         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 297         MyValue1[] va = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, Math.abs(rI) % 10);
 298         for (int i = 0; i < va.length; ++i) {
 299             va[i] = MyValue1.createWithFieldsInline(rI, rL);
 300         }
 301         long result = rL;
 302         for (int i = 0; i < 1000; ++i) {
 303             if (b) {
 304                 result += v.x;
 305             } else {
 306                 // Uncommon trap referencing v. We delegate allocation to the
 307                 // interpreter by adding a SafePointScalarObjectNode.
 308                 result = v.hashInterpreted();
 309                 for (int j = 0; j < va.length; ++j) {
 310                     result += va[j].hash();
 311                 }
 312             }
 313         }
 314         return result;
 315     }
 316 
 317     @Run(test = "test12")
 318     public void test12_verifier(RunInfo info) {
 319         long result = test12(info.isWarmUp());
 320         Asserts.assertEQ(result, info.isWarmUp() ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 321     }
 322     */
 323 
 324     // Test loop with uncommon trap referencing a value object
 325     @Test
 326     public long test13(boolean b) {
 327         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 328         MyValue1[] va = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, Math.abs(rI) % 10);
 329         for (int i = 0; i < va.length; ++i) {
 330             va[i] = MyValue1.createWithFieldsDontInline(rI, rL);
 331         }
 332         long result = rL;
 333         for (int i = 0; i < 1000; ++i) {
 334             if (b) {
 335                 result += v.x;
 336             } else {
 337                 // Uncommon trap referencing v. Should not allocate
 338                 // but just pass the existing oop to the uncommon trap.
 339                 result = v.hashInterpreted();
 340                 for (int j = 0; j < va.length; ++j) {
 341                     result += va[j].hashInterpreted();
 342                 }
 343             }
 344         }
 345         return result;
 346     }
 347 
 348     @Run(test = "test13")
 349     public void test13_verifier(RunInfo info) {
 350         long result = test13(info.isWarmUp());
 351         Asserts.assertEQ(result, info.isWarmUp() ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 352     }
 353 
 354     // Create a value object in a non-inlined method and then call a
 355     // non-inlined method on that value object.
 356     @Test
 357     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 358         failOn = {ALLOC, STORE, TRAP},
 359         counts = {LOAD, "= 19"})
 360     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 361         failOn = {ALLOC, LOAD, STORE, TRAP})
 362     public long test14() {
 363         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 364         return v.hashInterpreted();
 365     }
 366 
 367     @Run(test = "test14")
 368     public void test14_verifier() {
 369         long result = test14();
 370         Asserts.assertEQ(result, hash());
 371     }
 372 
 373     // Create a value object in an inlined method and then call a
 374     // non-inlined method on that value object.
 375     @Test
 376     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 377         failOn = {LOAD, TRAP},
 378         counts = {ALLOC, "<= 1"}) // 1 MyValue2 allocation (if not the default value)
 379     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 380         failOn = {LOAD, TRAP},
 381         counts = {ALLOC, "<= 2"}) // 1 MyValue1 and 1 MyValue2 allocation (if not the default value)
 382     public long test15() {
 383         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 384         return v.hashInterpreted();
 385     }
 386 
 387     @Run(test = "test15")
 388     public void test15_verifier() {
 389         long result = test15();
 390         Asserts.assertEQ(result, hash());
 391     }
 392 
 393     // Create a value object in a non-inlined method and then call an
 394     // inlined method on that value object.
 395     @Test
 396     @IR(failOn = {ALLOC, STORE, TRAP})
 397     public long test16() {
 398         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 399         return v.hash();
 400     }
 401 
 402     @Run(test = "test16")
 403     public void test16_verifier() {
 404         long result = test16();
 405         Asserts.assertEQ(result, hash());
 406     }
 407 
 408     // Create a value object in an inlined method and then call an
 409     // inlined method on that value object.
 410     @Test
 411     @IR(failOn = {ALLOC, LOAD, STORE, TRAP})
 412     public long test17() {
 413         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 414         return v.hash();
 415     }
 416 
 417     @Run(test = "test17")
 418     public void test17_verifier() {
 419         long result = test17();
 420         Asserts.assertEQ(result, hash());
 421     }
 422 
 423     // Create a value object in compiled code and pass it to the
 424     // interpreter via a call. The value object is live at the first call so
 425     // debug info should include a reference to all its fields.
 426     @Test
 427     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 428         counts = {ALLOC, "<= 1"}, // 1 MyValue2 allocation (if not the default value)
 429         failOn = {LOAD, TRAP})
 430     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 431         counts = {ALLOC, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the default value)
 432         failOn = {LOAD, TRAP})
 433     public long test18() {
 434         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 435         v.hashInterpreted();
 436         return v.hashInterpreted();
 437     }
 438 
 439     @Run(test = "test18")
 440     public void test18_verifier() {
 441         long result = test18();
 442         Asserts.assertEQ(result, hash());
 443     }
 444 
 445     // Create a value object in compiled code and pass it to the
 446     // interpreter via a call. The value object is passed twice but
 447     // should only be allocated once.
 448     @Test
 449     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 450         counts = {ALLOC, "<= 1"}, // 1 MyValue2 allocation (if not the default value)
 451         failOn = {LOAD, TRAP})
 452     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 453         counts = {ALLOC, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the default value)
 454         failOn = {LOAD, TRAP})
 455     public long test19() {
 456         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 457         return sumValue(v, v);
 458     }
 459 
 460     @DontCompile
 461     public long sumValue(MyValue1 v, MyValue1 dummy) {
 462         return v.hash();
 463     }
 464 
 465     @Run(test = "test19")
 466     public void test19_verifier() {
 467         long result = test19();
 468         Asserts.assertEQ(result, hash());
 469     }
 470 
 471     // Create a value type (array) in compiled code and pass it to the
 472     // interpreter via a call. The value object is live at the uncommon
 473     // trap: verify that deoptimization causes the value object to be
 474     // correctly allocated.
 475     @Test
 476     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 477         counts = {ALLOC, "<= 1"}, // 1 MyValue2 allocation (if not the default value)
 478         failOn = {LOAD})
 479     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 480         counts = {ALLOC, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the default value)
 481         failOn = LOAD)
 482     public long test20(boolean deopt, Method m) {
 483         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 484         MyValue2[] va = (MyValue2[])ValueClass.newNullRestrictedArray(MyValue2.class, 3);
 485         if (deopt) {
 486             // uncommon trap
 487             TestFramework.deoptimize(m);
 488         }
 489 
 490         return v.hashInterpreted() + va[0].hashInterpreted() +
 491                va[1].hashInterpreted() + va[2].hashInterpreted();
 492     }
 493 
 494     @Run(test = "test20")
 495     public void test20_verifier(RunInfo info) {
 496         MyValue2[] va = (MyValue2[])ValueClass.newNullRestrictedArray(MyValue2.class, 42);
 497         long result = test20(!info.isWarmUp(), info.getTest());
 498         Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash());
 499     }
 500 
 501     // Value class fields in regular object
 502     @NullRestricted
 503     MyValue1 val1;
 504     @NullRestricted
 505     MyValue2 val2;
 506     @NullRestricted
 507     final MyValue1 val3 = MyValue1.createWithFieldsInline(rI, rL);
 508     @NullRestricted
 509     static MyValue1 val4;
 510     @NullRestricted
 511     static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL);
 512 
 513     // Test value class fields in objects
 514     @Test
 515     // TODO 8332886 Re-enable this
 516     // @IR(counts = {ALLOC, "= 2"},
 517     //     failOn = TRAP)
 518     public long test21(int x, long y) {
 519         // Compute hash of value class fields
 520         long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 521         // Update fields
 522         val1 = MyValue1.createWithFieldsInline(x, y);
 523         val2 = MyValue2.createWithFieldsInline(x, rD);
 524         val4 = MyValue1.createWithFieldsInline(x, y);
 525         return result;
 526     }
 527 
 528     @Run(test = "test21")
 529     public void test21_verifier() {
 530         // Check if hash computed by test18 is correct
 531         val1 = MyValue1.createWithFieldsInline(rI, rL);
 532         val2 = val1.v2;
 533         // val3 is initialized in the constructor
 534         val4 = val1;
 535         // val5 is initialized in the static initializer
 536         long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 537         long result = test21(rI + 1, rL + 1);
 538         Asserts.assertEQ(result, hash);
 539         // Check if value class fields were updated
 540         Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
 541         Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, rD).hash());
 542         Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
 543     }
 544 
 545     // Test folding of constant value class fields
 546     @Test
 547     @IR(failOn = {ALLOC, LOAD, STORE, LOOP, TRAP})
 548     public long test22() {
 549         // This should be constant folded
 550         return val5.hash() + val5.v3.hash();
 551     }
 552 
 553     @Run(test = "test22")
 554     public void test22_verifier() {
 555         long result = test22();
 556         Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
 557     }
 558 
 559     // Test aconst_init
 560     @Test
 561     @IR(failOn = {ALLOC, LOAD, STORE, LOOP, TRAP})
 562     public long test23() {
 563         MyValue2 v = MyValue2.createDefaultInline();
 564         return v.hash();
 565     }
 566 
 567     @Run(test = "test23")
 568     public void test23_verifier() {
 569         long result = test23();
 570         Asserts.assertEQ(result, MyValue2.createDefaultInline().hash());
 571     }
 572 
 573     // Test aconst_init
 574     @Test
 575     @IR(failOn = {ALLOC, STORE, LOOP, TRAP})
 576     public long test24() {
 577         MyValue1 v1 = MyValue1.createDefaultInline();
 578         MyValue1 v2 = MyValue1.createDefaultDontInline();
 579         return v1.hashPrimitive() + v2.hashPrimitive();
 580     }
 581 
 582     @Run(test = "test24")
 583     public void test24_verifier() {
 584         long result = test24();
 585         Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive());
 586     }
 587 
 588     // Test field initialization
 589     @Test
 590     @IR(failOn = {ALLOC, LOAD, STORE, LOOP, TRAP})
 591     public long test25() {
 592         MyValue2 v = MyValue2.createWithFieldsInline(rI, rD);
 593         return v.hash();
 594     }
 595 
 596     @Run(test = "test25")
 597     public void test25_verifier() {
 598         long result = test25();
 599         Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, rD).hash());
 600     }
 601 
 602     // Test field initialization
 603     @Test
 604     @IR(failOn = {ALLOC, STORE, LOOP, TRAP})
 605     public long test26() {
 606         MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL);
 607         MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL);
 608         return v1.hash() + v2.hash();
 609     }
 610 
 611     @Run(test = "test26")
 612     public void test26_verifier() {
 613         long result = test26();
 614         Asserts.assertEQ(result, 2 * hash());
 615     }
 616 
 617     class TestClass27 {
 618         @NullRestricted
 619         public MyValue1 v;
 620     }
 621 
 622     // Test allocation elimination of unused object with initialized value class field
 623     @Test
 624     @IR(failOn = {ALLOC, LOAD, STORE, LOOP})
 625     public void test27(boolean deopt, Method m) {
 626         TestClass27 unused = new TestClass27();
 627         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 628         unused.v = v;
 629         if (deopt) {
 630             // uncommon trap
 631             TestFramework.deoptimize(m);
 632         }
 633     }
 634 
 635     @Run(test = "test27")
 636     public void test27_verifier(RunInfo info) {
 637         test27(!info.isWarmUp(), info.getTest());
 638     }
 639 
 640     @NullRestricted
 641     static MyValue3 staticVal3;
 642     @NullRestricted
 643     static MyValue3 staticVal3_copy;
 644 
 645     // Check elimination of redundant value class allocations
 646     @Test
 647     // TODO 8332886 Remove the AlwaysIncrementalInline=false condition
 648     @IR(applyIf = {"AlwaysIncrementalInline", "false"},
 649         counts = {ALLOC, "= 1"})
 650     public MyValue3 test28(MyValue3[] va) {
 651         // Create value object and force allocation
 652         MyValue3 vt = MyValue3.create();
 653         va[0] = vt;
 654         staticVal3 = vt;
 655         vt.verify(staticVal3);
 656 
 657         // Value object is now allocated, make a copy and force allocation.
 658         // Because copy is equal to vt, C2 should remove this redundant allocation.
 659         MyValue3 copy = MyValue3.setC(vt, vt.c);
 660         va[0] = copy;
 661         staticVal3_copy = copy;
 662         copy.verify(staticVal3_copy);
 663         return copy;
 664     }
 665 
 666     @Run(test = "test28")
 667     public void test28_verifier() {
 668         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 669         MyValue3 vt = test28(va);
 670         staticVal3.verify(vt);
 671         staticVal3.verify(va[0]);
 672         staticVal3_copy.verify(vt);
 673         staticVal3_copy.verify(va[0]);
 674     }
 675 
 676     // Verify that only dominating allocations are re-used
 677     @Test
 678     public MyValue3 test29(boolean warmup) {
 679         MyValue3 vt = MyValue3.create();
 680         if (warmup) {
 681             staticVal3 = vt; // Force allocation
 682         }
 683         // Force allocation to verify that above
 684         // non-dominating allocation is not re-used
 685         MyValue3 copy = MyValue3.setC(vt, vt.c);
 686         staticVal3_copy = copy;
 687         copy.verify(vt);
 688         return copy;
 689     }
 690 
 691     @Run(test = "test29")
 692     public void test29_verifier(RunInfo info) {
 693         MyValue3 vt = test29(info.isWarmUp());
 694         if (info.isWarmUp()) {
 695             staticVal3.verify(vt);
 696         }
 697     }
 698 
 699     // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations
 700     @Test
 701     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 702         failOn = {ALLOC, ALLOCA, STORE})
 703     public MyValue3 test30() {
 704         // C2 can re-use the oop of staticVal3 because staticVal3 is equal to copy
 705         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 706         MyValue3 copy = MyValue3.copy(staticVal3);
 707         va[0] = copy;
 708         copy.verify(va[0]);
 709         staticVal3 = copy;
 710         copy.verify(staticVal3);
 711         return copy;
 712     }
 713 
 714     @Run(test = "test30")
 715     public void test30_verifier() {
 716         staticVal3 = MyValue3.create();
 717         MyValue3 vt = test30();
 718         staticVal3.verify(vt);
 719     }
 720 
 721     // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations
 722     @Test
 723     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 724         failOn = {ALLOC, ALLOCA, STORE})
 725     public MyValue3 test31() {
 726         // C2 can re-use the oop returned by createDontInline()
 727         // because the corresponding value object is equal to 'copy'.
 728         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 729         MyValue3 copy = MyValue3.copy(MyValue3.createDontInline());
 730         va[0] = copy;
 731         copy.verify(va[0]);
 732         staticVal3 = copy;
 733         copy.verify(staticVal3);
 734         return copy;
 735     }
 736 
 737     @Run(test = "test31")
 738     public void test31_verifier() {
 739         MyValue3 vt = test31();
 740         staticVal3.verify(vt);
 741     }
 742 
 743     // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations
 744     @Test
 745     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 746         failOn = {ALLOC, ALLOCA, STORE})
 747     public MyValue3 test32(MyValue3 vt) {
 748         // C2 can re-use the oop of vt because vt is equal to 'copy'.
 749         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 750         MyValue3 copy = MyValue3.copy(vt);
 751         va[0] = copy;
 752         copy.verify(vt);
 753         staticVal3 = copy;
 754         copy.verify(staticVal3);
 755         return copy;
 756     }
 757 
 758     @Run(test = "test32")
 759     public void test32_verifier() {
 760         MyValue3 vt = MyValue3.create();
 761         MyValue3 result = test32(vt);
 762         staticVal3.verify(vt);
 763         result.verify(vt);
 764     }
 765 
 766     // Test correct identification of value object copies
 767     @Test
 768     public MyValue3 test33() {
 769         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 770         MyValue3 vt = MyValue3.copy(staticVal3);
 771         vt = MyValue3.setI(vt, vt.c);
 772         // vt is not equal to staticVal3, so C2 should not re-use the oop
 773         va[0] = vt;
 774         Asserts.assertEQ(va[0].i, (int)vt.c);
 775         staticVal3 = vt;
 776         vt.verify(staticVal3);
 777         return vt;
 778     }
 779 
 780     @Run(test = "test33")
 781     public void test33_verifier() {
 782         staticVal3 = MyValue3.create();
 783         MyValue3 vt = test33();
 784         Asserts.assertEQ(staticVal3.i, (int)staticVal3.c);
 785         Asserts.assertEQ(vt.i, (int)staticVal3.c);
 786     }
 787 
 788     static final MyValue3[] test34Array = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 2);
 789 
 790     // Verify that the default value class is never allocated.
 791     // C2 code should load and use the default oop from the java mirror.
 792     @Test
 793     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 794         failOn = {ALLOC, ALLOCA, LOAD, STORE, LOOP, TRAP})
 795     public MyValue3 test34() {
 796         // Explicitly create default value
 797         MyValue3 vt = MyValue3.createDefault();
 798         test34Array[0] = vt;
 799         staticVal3 = vt;
 800         vt.verify(vt);
 801 
 802         // Load default value from uninitialized value class array
 803         MyValue3[] dva = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 804         staticVal3_copy = dva[0];
 805         test34Array[1] = dva[0];
 806         dva[0].verify(dva[0]);
 807         return vt;
 808     }
 809 
 810     @Run(test = "test34")
 811     public void test34_verifier() {
 812         MyValue3 vt = MyValue3.createDefault();
 813         test34Array[0] = MyValue3.create();
 814         test34Array[1] = MyValue3.create();
 815         MyValue3 res = test34();
 816         res.verify(vt);
 817         staticVal3.verify(vt);
 818         staticVal3_copy.verify(vt);
 819         test34Array[0].verify(vt);
 820         test34Array[1].verify(vt);
 821     }
 822 
 823     static final MyValue3[] test35Array = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 824 
 825     // Same as above but manually initialize value class fields to default.
 826     @Test
 827     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 828         failOn = {ALLOC, ALLOCA, LOAD, STORE, LOOP, TRAP})
 829     public MyValue3 test35(MyValue3 vt) {
 830         vt = MyValue3.setC(vt, (char)0);
 831         vt = MyValue3.setBB(vt, (byte)0);
 832         vt = MyValue3.setS(vt, (short)0);
 833         vt = MyValue3.setI(vt, 0);
 834         vt = MyValue3.setL(vt, 0);
 835         vt = MyValue3.setO(vt, null);
 836         vt = MyValue3.setF1(vt, 0);
 837         vt = MyValue3.setF2(vt, 0);
 838         vt = MyValue3.setF3(vt, 0);
 839         vt = MyValue3.setF4(vt, 0);
 840         vt = MyValue3.setF5(vt, 0);
 841         vt = MyValue3.setF6(vt, 0);
 842         vt = MyValue3.setV1(vt, MyValue3Inline.createDefault());
 843         test35Array[0] = vt;
 844         staticVal3 = vt;
 845         vt.verify(vt);
 846         return vt;
 847     }
 848 
 849     @Run(test = "test35")
 850     public void test35_verifier() {
 851         MyValue3 vt = MyValue3.createDefault();
 852         test35Array[0] = MyValue3.create();
 853         MyValue3 res = test35(test35Array[0]);
 854         res.verify(vt);
 855         staticVal3.verify(vt);
 856         test35Array[0].verify(vt);
 857     }
 858 
 859     // Merge value objects created from two branches
 860 
 861     private Object test36_helper(Object v) {
 862         return v;
 863     }
 864 
 865     @Test
 866     @IR(failOn = {ALLOC, STORE, TRAP})
 867     public long test36(boolean b) {
 868         Object o;
 869         if (b) {
 870             o = test36_helper(MyValue1.createWithFieldsInline(rI, rL));
 871         } else {
 872             o = test36_helper(MyValue1.createWithFieldsDontInline(rI + 1, rL + 1));
 873         }
 874         MyValue1 v = (MyValue1)o;
 875         return v.hash();
 876     }
 877 
 878     @Run(test = "test36")
 879     public void test36_verifier() {
 880         Asserts.assertEQ(test36(true), hash());
 881         Asserts.assertEQ(test36(false), hash(rI + 1, rL + 1));
 882     }
 883 
 884     // Test correct loading of flattened fields
 885     @ImplicitlyConstructible
 886     @LooselyConsistentValue
 887     value class Test37Value2 {
 888         int x = 0;
 889         int y = 0;
 890     }
 891 
 892     @ImplicitlyConstructible
 893     @LooselyConsistentValue
 894     value class Test37Value1 {
 895         double d = 0;
 896         float f = 0;
 897         @NullRestricted
 898         Test37Value2 v = new Test37Value2();
 899     }
 900 
 901     @Test
 902     public Test37Value1 test37(Test37Value1 vt) {
 903         return vt;
 904     }
 905 
 906     @Run(test = "test37")
 907     public void test37_verifier() {
 908         Test37Value1 vt = new Test37Value1();
 909         Asserts.assertEQ(test37(vt), vt);
 910     }
 911 
 912     // Test elimination of value class allocations without a unique CheckCastPP
 913     @ImplicitlyConstructible
 914     @LooselyConsistentValue
 915     value class Test38Value {
 916         public int i;
 917         public Test38Value(int i) { this.i = i; }
 918     }
 919 
 920     @NullRestricted
 921     static Test38Value test38Field;
 922 
 923     @Test
 924     public void test38() {
 925         for (int i = 3; i < 100; ++i) {
 926             int j = 1;
 927             while (++j < 11) {
 928                 try {
 929                     test38Field = new Test38Value(i);
 930                 } catch (ArithmeticException ae) { }
 931             }
 932         }
 933     }
 934 
 935     @Run(test = "test38")
 936     public void test38_verifier() {
 937         test38Field = new Test38Value(0);
 938         test38();
 939         Asserts.assertEQ(test38Field, new Test38Value(99));
 940     }
 941 
 942     // Tests split if with value class Phi users
 943     @ImplicitlyConstructible
 944     @LooselyConsistentValue
 945     static value class Test39Value {
 946         public int iFld1;
 947         public int iFld2;
 948 
 949         public Test39Value(int i1, int i2) { iFld1 = i1; iFld2 = i2; }
 950     }
 951 
 952     static int test39A1[][] = new int[400][400];
 953     static double test39A2[] = new double[400];
 954     @NullRestricted
 955     static Test39Value test39Val = new Test39Value(0, 0);
 956 
 957     @DontInline
 958     public int[] getArray() {
 959         return new int[400];
 960     }
 961 
 962     @Test
 963     public int test39() {
 964         int result = 0;
 965         for (int i = 0; i < 100; ++i) {
 966             switch ((i >>> 1) % 3) {
 967                 case 0:
 968                     test39A1[i][i] = i;
 969                     break;
 970                 case 1:
 971                     for (int j = 0; j < 100; ++j) {
 972                         test39A1[i] = getArray();
 973                         test39Val = new Test39Value(j, test39Val.iFld2);
 974                     }
 975                     break;
 976                 case 2:
 977                     for (float f = 142; f > i; f--) {
 978                         test39A2[i + 1] += 3;
 979                     }
 980                     result += test39Val.iFld1;
 981                     break;
 982             }
 983             double d1 = 1;
 984             while (++d1 < 142) {
 985                 test39A1[(i >>> 1) % 400][i + 1] = result;
 986                 test39Val = new Test39Value(i, test39Val.iFld2);
 987             }
 988         }
 989         return result;
 990     }
 991 
 992     @Run(test = "test39")
 993     @Warmup(10)
 994     public void test39_verifier() {
 995         int result = test39();
 996         Asserts.assertEQ(result, 1552);
 997     }
 998 
 999     // Test scalar replacement of value class array containing value class with oop fields
1000     @Test
1001     public long test40(boolean b) {
1002         MyValue1[] va = {MyValue1.createWithFieldsInline(rI, rL)};
1003         long result = 0;
1004         for (int i = 0; i < 1000; ++i) {
1005             if (!b) {
1006                 result = va[0].hash();
1007             }
1008         }
1009         return result;
1010     }
1011 
1012     @Run(test = "test40")
1013     public void test40_verifier(RunInfo info) {
1014         long result = test40(info.isWarmUp());
1015         Asserts.assertEQ(result, info.isWarmUp() ? 0 : hash());
1016     }
1017 
1018     static value class MyValue41 {
1019         int x;
1020 
1021         public MyValue41(int x) {
1022             this.x = x;
1023         }
1024 
1025         static MyValue41 make() {
1026             return new MyValue41(0);
1027         }
1028     }
1029 
1030     static MyValue41 field41;
1031 
1032     // Test detection of value object copies and removal of the MemBarRelease following the value buffer initialization
1033     @Test
1034     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
1035         failOn = {ALLOC, ALLOCA, STORE})
1036     public void test41(MyValue41 val) {
1037         field41 = new MyValue41(val.x);
1038     }
1039 
1040     @Run(test = "test41")
1041     public void test41_verifier() {
1042         MyValue41 val = new MyValue41(rI);
1043         test41(val);
1044         Asserts.assertEQ(field41, val);
1045     }
1046 
1047     @DontInline
1048     public void test42_helper(MyValue41 val) {
1049         Asserts.assertEQ(val, new MyValue41(rI));
1050     }
1051 
1052     // Same as test41 but with call argument requiring buffering
1053     @Test
1054     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
1055         failOn = {ALLOC, ALLOCA, STORE})
1056     public void test42(MyValue41 val) {
1057         test42_helper(new MyValue41(val.x));
1058     }
1059 
1060     @Run(test = "test42")
1061     public void test42_verifier() {
1062         MyValue41 val = new MyValue41(rI);
1063         test42(val);
1064     }
1065 }