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"},
 161         failOn = {LOAD, TRAP})
 162     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 163         counts = {ALLOC, "= 2"},
 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     // TODO 8325106 We are hitting 8314999 here and sometimes fail to detect two allocations although there are two.
 181     @IR(counts = {ALLOC, "<= 2"},
 182         failOn = {LOAD, TRAP})
 183     public MyValue1 test7(int x, long y) {
 184         return MyValue1.createWithFieldsInline(x, y);
 185     }
 186 
 187     @Run(test = "test7")
 188     public void test7_verifier() {
 189         MyValue1 v = test7(rI, rL);
 190         Asserts.assertEQ(v.hash(), hash());
 191     }
 192 
 193     // Merge value objects created from two branches
 194     @Test
 195     @IR(failOn = {ALLOC, STORE, TRAP})
 196     public long test8(boolean b) {
 197         MyValue1 v;
 198         if (b) {
 199             v = MyValue1.createWithFieldsInline(rI, rL);
 200         } else {
 201             v = MyValue1.createWithFieldsDontInline(rI + 1, rL + 1);
 202         }
 203         return v.hash();
 204     }
 205 
 206     @Run(test = "test8")
 207     public void test8_verifier() {
 208         Asserts.assertEQ(test8(true), hash());
 209         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 210     }
 211 
 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     // TODO 8325106
 219     // @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 220     //     counts = {ALLOC, "= 2", STORE, "= 19"},
 221     //     failOn = {LOAD, TRAP})
 222     public MyValue1 test9(boolean b, int localrI, long localrL) {
 223         MyValue1 v;
 224         if (b) {
 225             // Value object is not allocated
 226             // Do not use rI/rL directly here as null values may cause
 227             // some redundant null initializations to be optimized out
 228             // and matching to fail.
 229             v = MyValue1.createWithFieldsInline(localrI, localrL);
 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     @Test
 291     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 292         counts = {SCOBJ, ">= 1", LOAD, "<= 12"}) // TODO 8227588 (loads should be removed)
 293     public long test12(boolean b) {
 294         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 295         MyValue1[] va = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, Math.abs(rI) % 10);
 296         for (int i = 0; i < va.length; ++i) {
 297             va[i] = MyValue1.createWithFieldsInline(rI, rL);
 298         }
 299         long result = rL;
 300         for (int i = 0; i < 1000; ++i) {
 301             if (b) {
 302                 result += v.x;
 303             } else {
 304                 // Uncommon trap referencing v. We delegate allocation to the
 305                 // interpreter by adding a SafePointScalarObjectNode.
 306                 result = v.hashInterpreted();
 307                 for (int j = 0; j < va.length; ++j) {
 308                     result += va[j].hash();
 309                 }
 310             }
 311         }
 312         return result;
 313     }
 314 
 315     @Run(test = "test12")
 316     public void test12_verifier(RunInfo info) {
 317         long result = test12(info.isWarmUp());
 318         Asserts.assertEQ(result, info.isWarmUp() ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 319     }
 320 
 321     // Test loop with uncommon trap referencing a value object
 322     @Test
 323     public long test13(boolean b) {
 324         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 325         MyValue1[] va = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, Math.abs(rI) % 10);
 326         for (int i = 0; i < va.length; ++i) {
 327             va[i] = MyValue1.createWithFieldsDontInline(rI, rL);
 328         }
 329         long result = rL;
 330         for (int i = 0; i < 1000; ++i) {
 331             if (b) {
 332                 result += v.x;
 333             } else {
 334                 // Uncommon trap referencing v. Should not allocate
 335                 // but just pass the existing oop to the uncommon trap.
 336                 result = v.hashInterpreted();
 337                 for (int j = 0; j < va.length; ++j) {
 338                     result += va[j].hashInterpreted();
 339                 }
 340             }
 341         }
 342         return result;
 343     }
 344 
 345     @Run(test = "test13")
 346     public void test13_verifier(RunInfo info) {
 347         long result = test13(info.isWarmUp());
 348         Asserts.assertEQ(result, info.isWarmUp() ? rL + (1000 * rI) : ((Math.abs(rI) % 10) + 1) * hash());
 349     }
 350 
 351     // Create a value object in a non-inlined method and then call a
 352     // non-inlined method on that value object.
 353     @Test
 354     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 355         failOn = {ALLOC, STORE, TRAP},
 356         counts = {LOAD, "= 19"})
 357     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 358         failOn = {ALLOC, LOAD, STORE, TRAP})
 359     public long test14() {
 360         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 361         return v.hashInterpreted();
 362     }
 363 
 364     @Run(test = "test14")
 365     public void test14_verifier() {
 366         long result = test14();
 367         Asserts.assertEQ(result, hash());
 368     }
 369 
 370     // Create a value object in an inlined method and then call a
 371     // non-inlined method on that value object.
 372     @Test
 373     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 374         failOn = {LOAD, TRAP},
 375         counts = {ALLOC, "= 1"})
 376     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 377         failOn = {LOAD, TRAP},
 378         counts = {ALLOC, "= 2"})
 379     public long test15() {
 380         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 381         return v.hashInterpreted();
 382     }
 383 
 384     @Run(test = "test15")
 385     public void test15_verifier() {
 386         long result = test15();
 387         Asserts.assertEQ(result, hash());
 388     }
 389 
 390     // Create a value object in a non-inlined method and then call an
 391     // inlined method on that value object.
 392     @Test
 393     @IR(failOn = {ALLOC, STORE, TRAP})
 394     public long test16() {
 395         MyValue1 v = MyValue1.createWithFieldsDontInline(rI, rL);
 396         return v.hash();
 397     }
 398 
 399     @Run(test = "test16")
 400     public void test16_verifier() {
 401         long result = test16();
 402         Asserts.assertEQ(result, hash());
 403     }
 404 
 405     // Create a value object in an inlined method and then call an
 406     // inlined method on that value object.
 407     @Test
 408     @IR(failOn = {ALLOC, LOAD, STORE, TRAP})
 409     public long test17() {
 410         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 411         return v.hash();
 412     }
 413 
 414     @Run(test = "test17")
 415     public void test17_verifier() {
 416         long result = test17();
 417         Asserts.assertEQ(result, hash());
 418     }
 419 
 420     // Create a value object in compiled code and pass it to the
 421     // interpreter via a call. The value object is live at the first call so
 422     // debug info should include a reference to all its fields.
 423     @Test
 424     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 425         counts = {ALLOC, "= 1"},
 426         failOn = {LOAD, TRAP})
 427     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 428         counts = {ALLOC, "= 2"},
 429         failOn = {LOAD, TRAP})
 430     public long test18() {
 431         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 432         v.hashInterpreted();
 433         return v.hashInterpreted();
 434     }
 435 
 436     @Run(test = "test18")
 437     public void test18_verifier() {
 438         long result = test18();
 439         Asserts.assertEQ(result, hash());
 440     }
 441 
 442     // Create a value object in compiled code and pass it to the
 443     // interpreter via a call. The value object is passed twice but
 444     // should only be allocated once.
 445     @Test
 446     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 447         counts = {ALLOC, "= 1"},
 448         failOn = {LOAD, TRAP})
 449     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 450         counts = {ALLOC, "= 2"},
 451         failOn = {LOAD, TRAP})
 452     public long test19() {
 453         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 454         return sumValue(v, v);
 455     }
 456 
 457     @DontCompile
 458     public long sumValue(MyValue1 v, MyValue1 dummy) {
 459         return v.hash();
 460     }
 461 
 462     @Run(test = "test19")
 463     public void test19_verifier() {
 464         long result = test19();
 465         Asserts.assertEQ(result, hash());
 466     }
 467 
 468     // Create a value type (array) in compiled code and pass it to the
 469     // interpreter via a call. The value object is live at the uncommon
 470     // trap: verify that deoptimization causes the value object to be
 471     // correctly allocated.
 472     @Test
 473     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "true"},
 474         counts = {ALLOC, "= 1"},
 475         failOn = {LOAD})
 476     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 477         counts = {ALLOC, "= 2"},
 478         failOn = LOAD)
 479     public long test20(boolean deopt, Method m) {
 480         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 481         MyValue2[] va = (MyValue2[])ValueClass.newNullRestrictedArray(MyValue2.class, 3);
 482         if (deopt) {
 483             // uncommon trap
 484             TestFramework.deoptimize(m);
 485         }
 486 
 487         return v.hashInterpreted() + va[0].hashInterpreted() +
 488                va[1].hashInterpreted() + va[2].hashInterpreted();
 489     }
 490 
 491     @Run(test = "test20")
 492     public void test20_verifier(RunInfo info) {
 493         MyValue2[] va = (MyValue2[])ValueClass.newNullRestrictedArray(MyValue2.class, 42);
 494         long result = test20(!info.isWarmUp(), info.getTest());
 495         Asserts.assertEQ(result, hash() + va[0].hash() + va[1].hash() + va[2].hash());
 496     }
 497 
 498     // Value class fields in regular object
 499     @NullRestricted
 500     MyValue1 val1;
 501     @NullRestricted
 502     MyValue2 val2;
 503     @NullRestricted
 504     final MyValue1 val3 = MyValue1.createWithFieldsInline(rI, rL);
 505     @NullRestricted
 506     static MyValue1 val4;
 507     @NullRestricted
 508     static final MyValue1 val5 = MyValue1.createWithFieldsInline(rI, rL);
 509 
 510     // Test value class fields in objects
 511     @Test
 512     // TODO 8325106 We already buffer the larval and we had to disable InlineTypeNode::remove_redundant_allocations for larvals
 513 //    @IR(counts = {ALLOC, "= 2"},
 514 //        failOn = TRAP)
 515     public long test21(int x, long y) {
 516         // Compute hash of value class fields
 517         long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 518         // Update fields
 519         val1 = MyValue1.createWithFieldsInline(x, y);
 520         val2 = MyValue2.createWithFieldsInline(x, rD);
 521         val4 = MyValue1.createWithFieldsInline(x, y);
 522         return result;
 523     }
 524 
 525     @Run(test = "test21")
 526     public void test21_verifier() {
 527         // Check if hash computed by test18 is correct
 528         val1 = MyValue1.createWithFieldsInline(rI, rL);
 529         val2 = val1.v2;
 530         // val3 is initialized in the constructor
 531         val4 = val1;
 532         // val5 is initialized in the static initializer
 533         long hash = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 534         long result = test21(rI + 1, rL + 1);
 535         Asserts.assertEQ(result, hash);
 536         // Check if value class fields were updated
 537         Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
 538         Asserts.assertEQ(val2.hash(), MyValue2.createWithFieldsInline(rI + 1, rD).hash());
 539         Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
 540     }
 541 
 542     // Test folding of constant value class fields
 543     @Test
 544     @IR(failOn = {ALLOC, LOAD, STORE, LOOP, TRAP})
 545     public long test22() {
 546         // This should be constant folded
 547         return val5.hash() + val5.v3.hash();
 548     }
 549 
 550     @Run(test = "test22")
 551     public void test22_verifier() {
 552         long result = test22();
 553         Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
 554     }
 555 
 556     // Test aconst_init
 557     @Test
 558     @IR(failOn = {ALLOC, LOAD, STORE, LOOP, TRAP})
 559     public long test23() {
 560         MyValue2 v = MyValue2.createDefaultInline();
 561         return v.hash();
 562     }
 563 
 564     @Run(test = "test23")
 565     public void test23_verifier() {
 566         long result = test23();
 567         Asserts.assertEQ(result, MyValue2.createDefaultInline().hash());
 568     }
 569 
 570     // Test aconst_init
 571     @Test
 572     @IR(failOn = {ALLOC, STORE, LOOP, TRAP})
 573     public long test24() {
 574         MyValue1 v1 = MyValue1.createDefaultInline();
 575         MyValue1 v2 = MyValue1.createDefaultDontInline();
 576         return v1.hashPrimitive() + v2.hashPrimitive();
 577     }
 578 
 579     @Run(test = "test24")
 580     public void test24_verifier() {
 581         long result = test24();
 582         Asserts.assertEQ(result, 2 * MyValue1.createDefaultInline().hashPrimitive());
 583     }
 584 
 585     // Test field initialization
 586     @Test
 587     @IR(failOn = {ALLOC, LOAD, STORE, LOOP, TRAP})
 588     public long test25() {
 589         MyValue2 v = MyValue2.createWithFieldsInline(rI, rD);
 590         return v.hash();
 591     }
 592 
 593     @Run(test = "test25")
 594     public void test25_verifier() {
 595         long result = test25();
 596         Asserts.assertEQ(result, MyValue2.createWithFieldsInline(rI, rD).hash());
 597     }
 598 
 599     // Test field initialization
 600     @Test
 601     @IR(failOn = {ALLOC, STORE, LOOP, TRAP})
 602     public long test26() {
 603         MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL);
 604         MyValue1 v2 = MyValue1.createWithFieldsDontInline(rI, rL);
 605         return v1.hash() + v2.hash();
 606     }
 607 
 608     @Run(test = "test26")
 609     public void test26_verifier() {
 610         long result = test26();
 611         Asserts.assertEQ(result, 2 * hash());
 612     }
 613 
 614     class TestClass27 {
 615         @NullRestricted
 616         public MyValue1 v;
 617     }
 618 
 619     // Test allocation elimination of unused object with initialized value class field
 620     @Test
 621     @IR(failOn = {ALLOC, LOAD, STORE, LOOP})
 622     public void test27(boolean deopt, Method m) {
 623         TestClass27 unused = new TestClass27();
 624         MyValue1 v = MyValue1.createWithFieldsInline(rI, rL);
 625         unused.v = v;
 626         if (deopt) {
 627             // uncommon trap
 628             TestFramework.deoptimize(m);
 629         }
 630     }
 631 
 632     @Run(test = "test27")
 633     public void test27_verifier(RunInfo info) {
 634         test27(!info.isWarmUp(), info.getTest());
 635     }
 636 
 637     @NullRestricted
 638     static MyValue3 staticVal3;
 639     @NullRestricted
 640     static MyValue3 staticVal3_copy;
 641 
 642     // Check elimination of redundant value class allocations
 643     @Test
 644     // TODO 8325106 With incremental inlining, we already buffer the larval and we had to disable InlineTypeNode::remove_redundant_allocations for larvals
 645     @IR(applyIf = {"AlwaysIncrementalInline", "false"},
 646         counts = {ALLOC, "= 1"})
 647     public MyValue3 test28(MyValue3[] va) {
 648         // Create value object and force allocation
 649         MyValue3 vt = MyValue3.create();
 650         va[0] = vt;
 651         staticVal3 = vt;
 652         vt.verify(staticVal3);
 653 
 654         // Value object is now allocated, make a copy and force allocation.
 655         // Because copy is equal to vt, C2 should remove this redundant allocation.
 656         MyValue3 copy = MyValue3.setC(vt, vt.c);
 657         va[0] = copy;
 658         staticVal3_copy = copy;
 659         copy.verify(staticVal3_copy);
 660         return copy;
 661     }
 662 
 663     @Run(test = "test28")
 664     public void test28_verifier() {
 665         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 666         MyValue3 vt = test28(va);
 667         staticVal3.verify(vt);
 668         staticVal3.verify(va[0]);
 669         staticVal3_copy.verify(vt);
 670         staticVal3_copy.verify(va[0]);
 671     }
 672 
 673     // Verify that only dominating allocations are re-used
 674     @Test
 675     public MyValue3 test29(boolean warmup) {
 676         MyValue3 vt = MyValue3.create();
 677         if (warmup) {
 678             staticVal3 = vt; // Force allocation
 679         }
 680         // Force allocation to verify that above
 681         // non-dominating allocation is not re-used
 682         MyValue3 copy = MyValue3.setC(vt, vt.c);
 683         staticVal3_copy = copy;
 684         copy.verify(vt);
 685         return copy;
 686     }
 687 
 688     @Run(test = "test29")
 689     public void test29_verifier(RunInfo info) {
 690         MyValue3 vt = test29(info.isWarmUp());
 691         if (info.isWarmUp()) {
 692             staticVal3.verify(vt);
 693         }
 694     }
 695 
 696     // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations
 697     @Test
 698     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 699         failOn = {ALLOC, ALLOCA, STORE})
 700     public MyValue3 test30() {
 701         // C2 can re-use the oop of staticVal3 because staticVal3 is equal to copy
 702         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 703         MyValue3 copy = MyValue3.copy(staticVal3);
 704         va[0] = copy;
 705         copy.verify(va[0]);
 706         staticVal3 = copy;
 707         copy.verify(staticVal3);
 708         return copy;
 709     }
 710 
 711     @Run(test = "test30")
 712     public void test30_verifier() {
 713         staticVal3 = MyValue3.create();
 714         MyValue3 vt = test30();
 715         staticVal3.verify(vt);
 716     }
 717 
 718     // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations
 719     @Test
 720     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 721         failOn = {ALLOC, ALLOCA, STORE})
 722     public MyValue3 test31() {
 723         // C2 can re-use the oop returned by createDontInline()
 724         // because the corresponding value object is equal to 'copy'.
 725         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 726         MyValue3 copy = MyValue3.copy(MyValue3.createDontInline());
 727         va[0] = copy;
 728         copy.verify(va[0]);
 729         staticVal3 = copy;
 730         copy.verify(staticVal3);
 731         return copy;
 732     }
 733 
 734     @Run(test = "test31")
 735     public void test31_verifier() {
 736         MyValue3 vt = test31();
 737         staticVal3.verify(vt);
 738     }
 739 
 740     // Verify that C2 recognizes value class loads and re-uses the oop to avoid allocations
 741     @Test
 742     @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"},
 743         failOn = {ALLOC, ALLOCA, STORE})
 744     public MyValue3 test32(MyValue3 vt) {
 745         // C2 can re-use the oop of vt because vt is equal to 'copy'.
 746         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 747         MyValue3 copy = MyValue3.copy(vt);
 748         va[0] = copy;
 749         copy.verify(vt);
 750         staticVal3 = copy;
 751         copy.verify(staticVal3);
 752         return copy;
 753     }
 754 
 755     @Run(test = "test32")
 756     public void test32_verifier() {
 757         MyValue3 vt = MyValue3.create();
 758         MyValue3 result = test32(vt);
 759         staticVal3.verify(vt);
 760         result.verify(vt);
 761     }
 762 
 763     // Test correct identification of value object copies
 764     @Test
 765     public MyValue3 test33() {
 766         MyValue3[] va = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 767         MyValue3 vt = MyValue3.copy(staticVal3);
 768         vt = MyValue3.setI(vt, vt.c);
 769         // vt is not equal to staticVal3, so C2 should not re-use the oop
 770         va[0] = vt;
 771         Asserts.assertEQ(va[0].i, (int)vt.c);
 772         staticVal3 = vt;
 773         vt.verify(staticVal3);
 774         return vt;
 775     }
 776 
 777     @Run(test = "test33")
 778     public void test33_verifier() {
 779         staticVal3 = MyValue3.create();
 780         MyValue3 vt = test33();
 781         Asserts.assertEQ(staticVal3.i, (int)staticVal3.c);
 782         Asserts.assertEQ(vt.i, (int)staticVal3.c);
 783     }
 784 
 785     static final MyValue3[] test34Array = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 2);
 786 
 787     // Verify that the default value class is never allocated.
 788     // C2 code should load and use the default oop from the java mirror.
 789     @Test
 790     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 791         failOn = {ALLOC, ALLOCA, LOAD, STORE, LOOP, TRAP})
 792     public MyValue3 test34() {
 793         // Explicitly create default value
 794         MyValue3 vt = MyValue3.createDefault();
 795         test34Array[0] = vt;
 796         staticVal3 = vt;
 797         vt.verify(vt);
 798 
 799         // Load default value from uninitialized value class array
 800         MyValue3[] dva = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 801         staticVal3_copy = dva[0];
 802         test34Array[1] = dva[0];
 803         dva[0].verify(dva[0]);
 804         return vt;
 805     }
 806 
 807     @Run(test = "test34")
 808     public void test34_verifier() {
 809         MyValue3 vt = MyValue3.createDefault();
 810         test34Array[0] = MyValue3.create();
 811         test34Array[1] = MyValue3.create();
 812         MyValue3 res = test34();
 813         res.verify(vt);
 814         staticVal3.verify(vt);
 815         staticVal3_copy.verify(vt);
 816         test34Array[0].verify(vt);
 817         test34Array[1].verify(vt);
 818     }
 819 
 820     static final MyValue3[] test35Array = (MyValue3[])ValueClass.newNullRestrictedArray(MyValue3.class, 1);
 821 
 822     // Same as above but manually initialize value class fields to default.
 823     @Test
 824     @IR(applyIf = {"FlatArrayElementMaxSize", "= -1"},
 825         failOn = {ALLOC, ALLOCA, LOAD, STORE, LOOP, TRAP})
 826     public MyValue3 test35(MyValue3 vt) {
 827         vt = MyValue3.setC(vt, (char)0);
 828         vt = MyValue3.setBB(vt, (byte)0);
 829         vt = MyValue3.setS(vt, (short)0);
 830         vt = MyValue3.setI(vt, 0);
 831         vt = MyValue3.setL(vt, 0);
 832         vt = MyValue3.setO(vt, null);
 833         vt = MyValue3.setF1(vt, 0);
 834         vt = MyValue3.setF2(vt, 0);
 835         vt = MyValue3.setF3(vt, 0);
 836         vt = MyValue3.setF4(vt, 0);
 837         vt = MyValue3.setF5(vt, 0);
 838         vt = MyValue3.setF6(vt, 0);
 839         vt = MyValue3.setV1(vt, MyValue3Inline.createDefault());
 840         test35Array[0] = vt;
 841         staticVal3 = vt;
 842         vt.verify(vt);
 843         return vt;
 844     }
 845 
 846     @Run(test = "test35")
 847     public void test35_verifier() {
 848         MyValue3 vt = MyValue3.createDefault();
 849         test35Array[0] = MyValue3.create();
 850         MyValue3 res = test35(test35Array[0]);
 851         res.verify(vt);
 852         staticVal3.verify(vt);
 853         test35Array[0].verify(vt);
 854     }
 855 
 856     // Merge value objects created from two branches
 857 
 858     private Object test36_helper(Object v) {
 859         return v;
 860     }
 861 
 862     @Test
 863     @IR(failOn = {ALLOC, STORE, TRAP})
 864     public long test36(boolean b) {
 865         Object o;
 866         if (b) {
 867             o = test36_helper(MyValue1.createWithFieldsInline(rI, rL));
 868         } else {
 869             o = test36_helper(MyValue1.createWithFieldsDontInline(rI + 1, rL + 1));
 870         }
 871         MyValue1 v = (MyValue1)o;
 872         return v.hash();
 873     }
 874 
 875     @Run(test = "test36")
 876     public void test36_verifier() {
 877         Asserts.assertEQ(test36(true), hash());
 878         Asserts.assertEQ(test36(false), hash(rI + 1, rL + 1));
 879     }
 880 
 881     // Test correct loading of flattened fields
 882     @ImplicitlyConstructible
 883     @LooselyConsistentValue
 884     value class Test37Value2 {
 885         int x = 0;
 886         int y = 0;
 887     }
 888 
 889 // TODO 8325106: Re-enable once JDK-8327695 is fixed
 890 /*
 891     @ImplicitlyConstructible
 892     @LooselyConsistentValue
 893     value class Test37Value1 {
 894         double d = 0;
 895         float f = 0;
 896         @NullRestricted
 897         Test37Value2 v = new Test37Value2();
 898     }
 899 
 900     @Test
 901     public Test37Value1 test37(Test37Value1 vt) {
 902         return vt;
 903     }
 904 
 905     @Run(test = "test37")
 906     public void test37_verifier() {
 907         Test37Value1 vt = new Test37Value1();
 908         Asserts.assertEQ(test37(vt), vt);
 909     }
 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 }