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