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