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