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