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