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 import java.lang.reflect.Method; 29 30 /* 31 * @test 32 * @summary Test value type calling convention optimizations 33 * @library /testlibrary /test/lib /compiler/whitebox / 34 * @compile -XDallowWithFieldOperator TestCallingConvention.java 35 * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform 36 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions 37 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla 38 * compiler.valhalla.valuetypes.ValueTypeTest 39 * compiler.valhalla.valuetypes.TestCallingConvention 40 */ 41 public class TestCallingConvention extends ValueTypeTest { 42 // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters() 43 @Override 44 public String[] getExtraVMParameters(int scenario) { 45 switch (scenario) { 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 TestCallingConvention test = new TestCallingConvention(); 53 test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, MyValue4.class, Test27Value1.class, Test27Value2.class, Test27Value3.class); 54 } 55 56 // Test interpreter to compiled code with various signatures 57 @Test(failOn = ALLOC + STORE + TRAP) 58 public long test1(MyValue2 v) { 59 return v.hash(); 60 } 61 62 @DontCompile 63 public void test1_verifier(boolean warmup) { 64 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 65 long result = test1(v); 66 Asserts.assertEQ(result, v.hashInterpreted()); 67 } 68 69 @Test(failOn = ALLOC + STORE + TRAP) 70 public long test2(int i1, MyValue2 v, int i2) { 71 return v.hash() + i1 - i2; 72 } 73 74 @DontCompile 75 public void test2_verifier(boolean warmup) { 76 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 77 long result = test2(rI, v, 2*rI); 78 Asserts.assertEQ(result, v.hashInterpreted() - rI); 79 } 80 81 @Test(failOn = ALLOC + STORE + TRAP) 82 public long test3(long l1, MyValue2 v, long l2) { 83 return v.hash() + l1 - l2; 84 } 85 86 @DontCompile 87 public void test3_verifier(boolean warmup) { 88 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 89 long result = test3(rL, v, 2*rL); 90 Asserts.assertEQ(result, v.hashInterpreted() - rL); 91 } 92 93 @Test(failOn = ALLOC + STORE + TRAP) 94 public long test4(int i, MyValue2 v, long l) { 95 return v.hash() + i + l; 96 } 97 98 @DontCompile 99 public void test4_verifier(boolean warmup) { 100 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 101 long result = test4(rI, v, rL); 102 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 103 } 104 105 @Test(failOn = ALLOC + STORE + TRAP) 106 public long test5(long l, MyValue2 v, int i) { 107 return v.hash() + i + l; 108 } 109 110 @DontCompile 111 public void test5_verifier(boolean warmup) { 112 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 113 long result = test5(rL, v, rI); 114 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 115 } 116 117 @Test(failOn = ALLOC + STORE + TRAP) 118 public long test6(long l, MyValue1 v1, int i, MyValue2 v2) { 119 return v1.hash() + i + l + v2.hash(); 120 } 121 122 @DontCompile 123 public void test6_verifier(boolean warmup) { 124 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 125 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 126 long result = test6(rL, v1, rI, v2); 127 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 128 } 129 130 // Test compiled code to interpreter with various signatures 131 @DontCompile 132 public long test7_interp(MyValue2 v) { 133 return v.hash(); 134 } 135 136 @Test(failOn = ALLOC + STORE + TRAP) 137 public long test7(MyValue2 v) { 138 return test7_interp(v); 139 } 140 141 @DontCompile 142 public void test7_verifier(boolean warmup) { 143 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 144 long result = test7(v); 145 Asserts.assertEQ(result, v.hashInterpreted()); 146 } 147 148 @DontCompile 149 public long test8_interp(int i1, MyValue2 v, int i2) { 150 return v.hash() + i1 - i2; 151 } 152 153 @Test(failOn = ALLOC + STORE + TRAP) 154 public long test8(int i1, MyValue2 v, int i2) { 155 return test8_interp(i1, v, i2); 156 } 157 158 @DontCompile 159 public void test8_verifier(boolean warmup) { 160 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 161 long result = test8(rI, v, 2*rI); 162 Asserts.assertEQ(result, v.hashInterpreted() - rI); 163 } 164 165 @DontCompile 166 public long test9_interp(long l1, MyValue2 v, long l2) { 167 return v.hash() + l1 - l2; 168 } 169 170 @Test(failOn = ALLOC + STORE + TRAP) 171 public long test9(long l1, MyValue2 v, long l2) { 172 return test9_interp(l1, v, l2); 173 } 174 175 @DontCompile 176 public void test9_verifier(boolean warmup) { 177 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 178 long result = test9(rL, v, 2*rL); 179 Asserts.assertEQ(result, v.hashInterpreted() - rL); 180 } 181 182 @DontCompile 183 public long test10_interp(int i, MyValue2 v, long l) { 184 return v.hash() + i + l; 185 } 186 187 @Test(failOn = ALLOC + STORE + TRAP) 188 public long test10(int i, MyValue2 v, long l) { 189 return test10_interp(i, v, l); 190 } 191 192 @DontCompile 193 public void test10_verifier(boolean warmup) { 194 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 195 long result = test10(rI, v, rL); 196 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 197 } 198 199 @DontCompile 200 public long test11_interp(long l, MyValue2 v, int i) { 201 return v.hash() + i + l; 202 } 203 204 @Test(failOn = ALLOC + STORE + TRAP) 205 public long test11(long l, MyValue2 v, int i) { 206 return test11_interp(l, v, i); 207 } 208 209 @DontCompile 210 public void test11_verifier(boolean warmup) { 211 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 212 long result = test11(rL, v, rI); 213 Asserts.assertEQ(result, v.hashInterpreted() + rL + rI); 214 } 215 216 @DontCompile 217 public long test12_interp(long l, MyValue1 v1, int i, MyValue2 v2) { 218 return v1.hash() + i + l + v2.hash(); 219 } 220 221 @Test(failOn = ALLOC + STORE + TRAP) 222 public long test12(long l, MyValue1 v1, int i, MyValue2 v2) { 223 return test12_interp(l, v1, i, v2); 224 } 225 226 @DontCompile 227 public void test12_verifier(boolean warmup) { 228 MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL); 229 MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true); 230 long result = test12(rL, v1, rI, v2); 231 Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted()); 232 } 233 234 // Test that debug info at a call is correct 235 @DontCompile 236 public long test13_interp(MyValue2 v, MyValue1[] va, boolean deopt) { 237 if (deopt) { 238 // uncommon trap 239 WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test13")); 240 } 241 return v.hash() + va[0].hash() + va[1].hash(); 242 } 243 244 @Test(failOn = ALLOC + STORE + TRAP) 245 public long test13(MyValue2 v, MyValue1[] va, boolean flag, long l) { 246 return test13_interp(v, va, flag) + l; 247 } 248 249 @DontCompile 250 public void test13_verifier(boolean warmup) { 251 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 252 MyValue1[] va = new MyValue1[2]; 253 va[0] = MyValue1.createWithFieldsDontInline(rI, rL); 254 va[1] = MyValue1.createWithFieldsDontInline(rI, rL); 255 long result = test13(v, va, !warmup, rL); 256 Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL); 257 } 258 259 // Test deoptimization at call return with return value in registers 260 @DontCompile 261 public MyValue2 test14_interp(boolean deopt) { 262 if (deopt) { 263 // uncommon trap 264 WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test14")); 265 } 266 return MyValue2.createWithFieldsInline(rI, true); 267 } 268 269 @Test() 270 public MyValue2 test14(boolean flag) { 271 return test14_interp(flag); 272 } 273 274 @DontCompile 275 public void test14_verifier(boolean warmup) { 276 MyValue2 result = test14(!warmup); 277 MyValue2 v = MyValue2.createWithFieldsInline(rI, true); 278 Asserts.assertEQ(result.hash(), v.hash()); 279 } 280 281 // Return value types in registers from interpreter -> compiled 282 final MyValue3 test15_vt = MyValue3.create(); 283 @DontCompile 284 public MyValue3 test15_interp() { 285 return test15_vt; 286 } 287 288 MyValue3 test15_vt2; 289 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP) 290 @Test(valid = ValueTypeReturnedAsFieldsOff) 291 public void test15() { 292 test15_vt2 = test15_interp(); 293 } 294 295 @DontCompile 296 public void test15_verifier(boolean warmup) { 297 test15(); 298 test15_vt.verify(test15_vt2); 299 } 300 301 // Return value types in registers from compiled -> interpreter 302 final MyValue3 test16_vt = MyValue3.create(); 303 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + TRAP) 304 @Test(valid = ValueTypeReturnedAsFieldsOff) 305 public MyValue3 test16() { 306 return test16_vt; 307 } 308 309 @DontCompile 310 public void test16_verifier(boolean warmup) { 311 MyValue3 vt = test16(); 312 test16_vt.verify(vt); 313 } 314 315 // Return value types in registers from compiled -> compiled 316 final MyValue3 test17_vt = MyValue3.create(); 317 @DontInline 318 public MyValue3 test17_comp() { 319 return test17_vt; 320 } 321 322 MyValue3 test17_vt2; 323 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP) 324 @Test(valid = ValueTypeReturnedAsFieldsOff) 325 public void test17() { 326 test17_vt2 = test17_comp(); 327 } 328 329 @DontCompile 330 public void test17_verifier(boolean warmup) throws Exception { 331 Method helper_m = getClass().getDeclaredMethod("test17_comp"); 332 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 333 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 334 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test17_comp not compiled"); 335 } 336 test17(); 337 test17_vt.verify(test17_vt2); 338 } 339 340 // Same tests as above but with a value type that cannot be returned in registers 341 342 // Return value types in registers from interpreter -> compiled 343 final MyValue4 test18_vt = MyValue4.create(); 344 @DontCompile 345 public MyValue4 test18_interp() { 346 return test18_vt; 347 } 348 349 MyValue4 test18_vt2; 350 @Test 351 public void test18() { 352 test18_vt2 = test18_interp(); 353 } 354 355 @DontCompile 356 public void test18_verifier(boolean warmup) { 357 test18(); 358 test18_vt.verify(test18_vt2); 359 } 360 361 // Return value types in registers from compiled -> interpreter 362 final MyValue4 test19_vt = MyValue4.create(); 363 @Test 364 public MyValue4 test19() { 365 return test19_vt; 366 } 367 368 @DontCompile 369 public void test19_verifier(boolean warmup) { 370 MyValue4 vt = test19(); 371 test19_vt.verify(vt); 372 } 373 374 // Return value types in registers from compiled -> compiled 375 final MyValue4 test20_vt = MyValue4.create(); 376 @DontInline 377 public MyValue4 test20_comp() { 378 return test20_vt; 379 } 380 381 MyValue4 test20_vt2; 382 @Test 383 public void test20() { 384 test20_vt2 = test20_comp(); 385 } 386 387 @DontCompile 388 public void test20_verifier(boolean warmup) throws Exception { 389 Method helper_m = getClass().getDeclaredMethod("test20_comp"); 390 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) { 391 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION); 392 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test20_comp not compiled"); 393 } 394 test20(); 395 test20_vt.verify(test20_vt2); 396 } 397 398 // Test no result from inlined method for incremental inlining 399 final MyValue3 test21_vt = MyValue3.create(); 400 public MyValue3 test21_inlined() { 401 throw new RuntimeException(); 402 } 403 404 @Test 405 public MyValue3 test21() { 406 try { 407 return test21_inlined(); 408 } catch (RuntimeException ex) { 409 return test21_vt; 410 } 411 } 412 413 @DontCompile 414 public void test21_verifier(boolean warmup) { 415 MyValue3 vt = test21(); 416 test21_vt.verify(vt); 417 } 418 419 // Test returning a non-flattened value type as fields 420 MyValue3.box test22_vt = MyValue3.create(); 421 422 @Test 423 public MyValue3 test22() { 424 return test22_vt; 425 } 426 427 @DontCompile 428 public void test22_verifier(boolean warmup) { 429 MyValue3 vt = test22(); 430 test22_vt.verify(vt); 431 } 432 433 // Test calling a method that has circular register/stack dependencies when unpacking value type arguments 434 value class TestValue23 { 435 final double f1; 436 TestValue23(double val) { 437 f1 = val; 438 } 439 } 440 441 static double test23Callee(int i1, int i2, int i3, int i4, int i5, int i6, 442 TestValue23 v1, TestValue23 v2, TestValue23 v3, TestValue23 v4, TestValue23 v5, TestValue23 v6, TestValue23 v7, TestValue23 v8, 443 double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8) { 444 return i1 + i2 + i3 + i4 + i5 + i6 + v1.f1 + v2.f1 + v3.f1 + v4.f1 + v5.f1 + v6.f1 + v7.f1 + v8.f1 + d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8; 445 } 446 447 @Test 448 public double test23(int i1, int i2, int i3, int i4, int i5, int i6, 449 TestValue23 v1, TestValue23 v2, TestValue23 v3, TestValue23 v4, TestValue23 v5, TestValue23 v6, TestValue23 v7, TestValue23 v8, 450 double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8) { 451 return test23Callee(i1, i2, i3, i4, i5, i6, 452 v1, v2, v3, v4, v5, v6, v7, v8, 453 d1, d2, d3, d4, d5, d6, d7, d8); 454 } 455 456 @DontCompile 457 public void test23_verifier(boolean warmup) { 458 TestValue23 vt = new TestValue23(rI); 459 double res1 = test23(rI, rI, rI, rI, rI, rI, 460 vt, vt, vt, vt, vt, vt, vt, vt, 461 rI, rI, rI, rI, rI, rI, rI, rI); 462 double res2 = test23Callee(rI, rI, rI, rI, rI, rI, 463 vt, vt, vt, vt, vt, vt, vt, vt, 464 rI, rI, rI, rI, rI, rI, rI, rI); 465 double res3 = 6*rI + 8*rI + 8*rI; 466 Asserts.assertEQ(res1, res2); 467 Asserts.assertEQ(res2, res3); 468 } 469 470 // Should not return a nullable value type as fields 471 @Test 472 public MyValue2.box test24() { 473 return null; 474 } 475 476 @DontCompile 477 public void test24_verifier(boolean warmup) { 478 MyValue2.box vt = test24(); 479 Asserts.assertEQ(vt, null); 480 } 481 482 // Same as test24 but with control flow and inlining 483 @ForceInline 484 public MyValue2.box test26_callee(boolean b) { 485 if (b) { 486 return null; 487 } else { 488 return MyValue2.createWithFieldsInline(rI, true); 489 } 490 } 491 492 @Test 493 public MyValue2.box test26(boolean b) { 494 return test26_callee(b); 495 } 496 497 @DontCompile 498 public void test26_verifier(boolean warmup) { 499 MyValue2.box vt = test26(true); 500 Asserts.assertEQ(vt, null); 501 vt = test26(false); 502 Asserts.assertEQ(vt.hash(), MyValue2.createWithFieldsInline(rI, true).hash()); 503 } 504 505 // Test calling convention with deep hierarchy of flattened fields 506 value final class Test27Value1 { 507 final Test27Value2.val valueField; 508 509 private Test27Value1(Test27Value2 val2) { 510 valueField = val2; 511 } 512 513 @DontInline 514 public int test(Test27Value1 val1) { 515 return valueField.test(valueField) + val1.valueField.test(valueField); 516 } 517 } 518 519 value final class Test27Value2 { 520 final Test27Value3.val valueField; 521 522 private Test27Value2(Test27Value3 val3) { 523 valueField = val3; 524 } 525 526 @DontInline 527 public int test(Test27Value2 val2) { 528 return valueField.test(valueField) + val2.valueField.test(valueField); 529 } 530 } 531 532 value final class Test27Value3 { 533 final int x; 534 535 private Test27Value3(int x) { 536 this.x = x; 537 } 538 539 @DontInline 540 public int test(Test27Value3 val3) { 541 return x + val3.x; 542 } 543 } 544 545 @Test 546 public int test27(Test27Value1 val) { 547 return val.test(val); 548 } 549 550 @DontCompile 551 public void test27_verifier(boolean warmup) { 552 Test27Value3 val3 = new Test27Value3(rI); 553 Test27Value2 val2 = new Test27Value2(val3); 554 Test27Value1 val1 = new Test27Value1(val2); 555 int result = test27(val1); 556 Asserts.assertEQ(result, 8*rI); 557 } 558 559 static final MyValue1.box test28Val = MyValue1.createWithFieldsDontInline(rI, rL); 560 561 @Test 562 @Warmup(0) 563 public String test28() { 564 return test28Val.toString(); 565 } 566 567 @DontCompile 568 public void test28_verifier(boolean warmup) { 569 String result = test28(); 570 } 571 }