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 @Test 291 @IR(applyIf = {"UseArrayFlattening", "true"}, 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"}) // 1 MyValue2 allocation (if not the default value) 376 @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, 377 failOn = {LOAD, TRAP}, 378 counts = {ALLOC, "<= 2"}) // 1 MyValue1 and 1 MyValue2 allocation (if not the default value) 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"}, // 1 MyValue2 allocation (if not the default value) 426 failOn = {LOAD, TRAP}) 427 @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, 428 counts = {ALLOC, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the default value) 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"}, // 1 MyValue2 allocation (if not the default value) 448 failOn = {LOAD, TRAP}) 449 @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, 450 counts = {ALLOC, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the default value) 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"}, // 1 MyValue2 allocation (if not the default value) 475 failOn = {LOAD}) 476 @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, 477 counts = {ALLOC, "<= 2"}, // 1 MyValue1 and 1 MyValue2 allocation (if not the default value) 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 8332886 Re-enable this 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 8332886 Remove the AlwaysIncrementalInline=false condition 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 = {"UseArrayFlattening", "true"}, 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 = {"UseArrayFlattening", "true"}, 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 = {"UseArrayFlattening", "true"}, 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 @ImplicitlyConstructible 890 @LooselyConsistentValue 891 value class Test37Value1 { 892 double d = 0; 893 float f = 0; 894 @NullRestricted 895 Test37Value2 v = new Test37Value2(); 896 } 897 898 @Test 899 public Test37Value1 test37(Test37Value1 vt) { 900 return vt; 901 } 902 903 @Run(test = "test37") 904 public void test37_verifier() { 905 Test37Value1 vt = new Test37Value1(); 906 Asserts.assertEQ(test37(vt), vt); 907 } 908 909 // Test elimination of value class allocations without a unique CheckCastPP 910 @ImplicitlyConstructible 911 @LooselyConsistentValue 912 value class Test38Value { 913 public int i; 914 public Test38Value(int i) { this.i = i; } 915 } 916 917 @NullRestricted 918 static Test38Value test38Field; 919 920 @Test 921 public void test38() { 922 for (int i = 3; i < 100; ++i) { 923 int j = 1; 924 while (++j < 11) { 925 try { 926 test38Field = new Test38Value(i); 927 } catch (ArithmeticException ae) { } 928 } 929 } 930 } 931 932 @Run(test = "test38") 933 public void test38_verifier() { 934 test38Field = new Test38Value(0); 935 test38(); 936 Asserts.assertEQ(test38Field, new Test38Value(99)); 937 } 938 939 // Tests split if with value class Phi users 940 @ImplicitlyConstructible 941 @LooselyConsistentValue 942 static value class Test39Value { 943 public int iFld1; 944 public int iFld2; 945 946 public Test39Value(int i1, int i2) { iFld1 = i1; iFld2 = i2; } 947 } 948 949 static int test39A1[][] = new int[400][400]; 950 static double test39A2[] = new double[400]; 951 @NullRestricted 952 static Test39Value test39Val = new Test39Value(0, 0); 953 954 @DontInline 955 public int[] getArray() { 956 return new int[400]; 957 } 958 959 @Test 960 public int test39() { 961 int result = 0; 962 for (int i = 0; i < 100; ++i) { 963 switch ((i >>> 1) % 3) { 964 case 0: 965 test39A1[i][i] = i; 966 break; 967 case 1: 968 for (int j = 0; j < 100; ++j) { 969 test39A1[i] = getArray(); 970 test39Val = new Test39Value(j, test39Val.iFld2); 971 } 972 break; 973 case 2: 974 for (float f = 142; f > i; f--) { 975 test39A2[i + 1] += 3; 976 } 977 result += test39Val.iFld1; 978 break; 979 } 980 double d1 = 1; 981 while (++d1 < 142) { 982 test39A1[(i >>> 1) % 400][i + 1] = result; 983 test39Val = new Test39Value(i, test39Val.iFld2); 984 } 985 } 986 return result; 987 } 988 989 @Run(test = "test39") 990 @Warmup(10) 991 public void test39_verifier() { 992 int result = test39(); 993 Asserts.assertEQ(result, 1552); 994 } 995 996 // Test scalar replacement of value class array containing value class with oop fields 997 @Test 998 public long test40(boolean b) { 999 MyValue1[] va = {MyValue1.createWithFieldsInline(rI, rL)}; 1000 long result = 0; 1001 for (int i = 0; i < 1000; ++i) { 1002 if (!b) { 1003 result = va[0].hash(); 1004 } 1005 } 1006 return result; 1007 } 1008 1009 @Run(test = "test40") 1010 public void test40_verifier(RunInfo info) { 1011 long result = test40(info.isWarmUp()); 1012 Asserts.assertEQ(result, info.isWarmUp() ? 0 : hash()); 1013 } 1014 1015 static value class MyValue41 { 1016 int x; 1017 1018 public MyValue41(int x) { 1019 this.x = x; 1020 } 1021 1022 static MyValue41 make() { 1023 return new MyValue41(0); 1024 } 1025 } 1026 1027 static MyValue41 field41; 1028 1029 // Test detection of value object copies and removal of the MemBarRelease following the value buffer initialization 1030 @Test 1031 @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, 1032 failOn = {ALLOC, ALLOCA, STORE}) 1033 public void test41(MyValue41 val) { 1034 field41 = new MyValue41(val.x); 1035 } 1036 1037 @Run(test = "test41") 1038 public void test41_verifier() { 1039 MyValue41 val = new MyValue41(rI); 1040 test41(val); 1041 Asserts.assertEQ(field41, val); 1042 } 1043 1044 @DontInline 1045 public void test42_helper(MyValue41 val) { 1046 Asserts.assertEQ(val, new MyValue41(rI)); 1047 } 1048 1049 // Same as test41 but with call argument requiring buffering 1050 @Test 1051 @IR(applyIf = {"InlineTypePassFieldsAsArgs", "false"}, 1052 failOn = {ALLOC, ALLOCA, STORE}) 1053 public void test42(MyValue41 val) { 1054 test42_helper(new MyValue41(val.x)); 1055 } 1056 1057 @Run(test = "test42") 1058 public void test42_verifier() { 1059 MyValue41 val = new MyValue41(rI); 1060 test42(val); 1061 } 1062 }