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