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 -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 __NotFlattened MyValue3 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 }