rev 54670 : Port of valuetypes to aarch64
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 java.lang.invoke.*;
27 import java.lang.reflect.Method;
28
29 import jdk.test.lib.Asserts;
30
31 /*
32 * @test
33 * @summary Test method handle support for value types
34 * @library /testlibrary /test/lib /compiler/whitebox /
35 * @requires os.simpleArch == "x64"
36 * @compile -XDallowWithFieldOperator TestMethodHandles.java
37 * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
38 * @run main/othervm/timeout=120 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
39 * -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla
40 * compiler.valhalla.valuetypes.ValueTypeTest
41 * compiler.valhalla.valuetypes.TestMethodHandles
42 */
43 public class TestMethodHandles extends ValueTypeTest {
44 // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters()
45 @Override
46 public String[] getExtraVMParameters(int scenario) {
47 switch (scenario) {
48 // Prevent inlining through MethodHandle linkTo adapters to stress the calling convention
49 case 2: return new String[] {"-XX:CompileCommand=dontinline,java.lang.invoke.DirectMethodHandle::internalMemberName"};
50 case 3: return new String[] {"-XX:ValueArrayElemMaxFlatSize=0"};
51 case 4: return new String[] {"-XX:CompileCommand=dontinline,java.lang.invoke.DirectMethodHandle::internalMemberName"};
52 }
53 return null;
54 }
55
56 static {
57 try {
58 Class<?> clazz = TestMethodHandles.class;
59 ClassLoader loader = clazz.getClassLoader();
60 MethodHandles.Lookup lookup = MethodHandles.lookup();
61
62 MethodType mt = MethodType.methodType(MyValue3.class.asValueType());
63 test1_mh = lookup.findVirtual(clazz, "test1_target", mt);
64 test2_mh = lookup.findVirtual(clazz, "test2_target", mt);
65 test3_mh = lookup.findVirtual(clazz, "test3_target", mt);
66
67 MethodType test4_mt1 = MethodType.methodType(int.class, MyValue1.class.asValueType());
68 MethodType test4_mt2 = MethodType.methodType(MyValue1.class.asValueType());
69 MethodHandle test4_mh1 = lookup.findStatic(clazz, "test4_helper1", test4_mt1);
70 MethodHandle test4_mh2 = lookup.findStatic(clazz, "test4_helper2", test4_mt2);
71 test4_mh = MethodHandles.filterReturnValue(test4_mh2, test4_mh1);
72
73 MethodType test5_mt = MethodType.methodType(int.class, MyValue1.class.asValueType());
74 test5_mh = lookup.findVirtual(clazz, "test5_target", test5_mt);
75
76 MethodType test6_mt = MethodType.methodType(MyValue3.class.asValueType());
77 MethodHandle test6_mh1 = lookup.findVirtual(clazz, "test6_target1", test6_mt);
78 MethodHandle test6_mh2 = lookup.findVirtual(clazz, "test6_target2", test6_mt);
79 MethodType boolean_mt = MethodType.methodType(boolean.class);
80 MethodHandle test6_mh_test = lookup.findVirtual(clazz, "test6_test", boolean_mt);
81 test6_mh = MethodHandles.guardWithTest(test6_mh_test, test6_mh1, test6_mh2);
82
83 MethodType myvalue2_mt = MethodType.methodType(MyValue2.class.asValueType());
84 test7_mh1 = lookup.findStatic(clazz, "test7_target1", myvalue2_mt);
85 MethodHandle test7_mh2 = lookup.findStatic(clazz, "test7_target2", myvalue2_mt);
86 MethodHandle test7_mh_test = lookup.findStatic(clazz, "test7_test", boolean_mt);
87 test7_mh = MethodHandles.guardWithTest(test7_mh_test,
88 MethodHandles.invoker(myvalue2_mt),
89 MethodHandles.dropArguments(test7_mh2, 0, MethodHandle.class));
90
91 MethodHandle test8_mh1 = lookup.findStatic(clazz, "test8_target1", myvalue2_mt);
92 test8_mh2 = lookup.findStatic(clazz, "test8_target2", myvalue2_mt);
93 MethodHandle test8_mh_test = lookup.findStatic(clazz, "test8_test", boolean_mt);
94 test8_mh = MethodHandles.guardWithTest(test8_mh_test,
95 MethodHandles.dropArguments(test8_mh1, 0, MethodHandle.class),
96 MethodHandles.invoker(myvalue2_mt));
97
98 MethodType test9_mt = MethodType.methodType(MyValue3.class.asValueType());
99 MethodHandle test9_mh1 = lookup.findVirtual(clazz, "test9_target1", test9_mt);
100 MethodHandle test9_mh2 = lookup.findVirtual(clazz, "test9_target2", test9_mt);
101 MethodHandle test9_mh3 = lookup.findVirtual(clazz, "test9_target3", test9_mt);
102 MethodType test9_mt2 = MethodType.methodType(boolean.class);
103 MethodHandle test9_mh_test1 = lookup.findVirtual(clazz, "test9_test1", test9_mt2);
104 MethodHandle test9_mh_test2 = lookup.findVirtual(clazz, "test9_test2", test9_mt2);
105 test9_mh = MethodHandles.guardWithTest(test9_mh_test1,
106 test9_mh1,
107 MethodHandles.guardWithTest(test9_mh_test2, test9_mh2, test9_mh3));
108
109 MethodType test10_mt = MethodType.methodType(MyValue2.class.asValueType());
110 MethodHandle test10_mh1 = lookup.findStatic(clazz, "test10_target1", test10_mt);
111 test10_mh2 = lookup.findStatic(clazz, "test10_target2", test10_mt);
112 test10_mh3 = lookup.findStatic(clazz, "test10_target3", test10_mt);
113 MethodType test10_mt2 = MethodType.methodType(boolean.class);
114 MethodType test10_mt3 = MethodType.methodType(MyValue2.class.asValueType());
115 MethodHandle test10_mh_test1 = lookup.findStatic(clazz, "test10_test1", test10_mt2);
116 MethodHandle test10_mh_test2 = lookup.findStatic(clazz, "test10_test2", test10_mt2);
117 test10_mh = MethodHandles.guardWithTest(test10_mh_test1,
118 MethodHandles.dropArguments(test10_mh1, 0, MethodHandle.class, MethodHandle.class),
119 MethodHandles.guardWithTest(test10_mh_test2,
120 MethodHandles.dropArguments(MethodHandles.invoker(test10_mt3), 1, MethodHandle.class),
121 MethodHandles.dropArguments(MethodHandles.invoker(test10_mt3), 0, MethodHandle.class))
122 );
123
124 MethodHandle test11_mh1 = lookup.findStatic(clazz, "test11_target1", myvalue2_mt);
125 test11_mh2 = lookup.findStatic(clazz, "test11_target2", myvalue2_mt);
126 MethodHandle test11_mh_test = lookup.findStatic(clazz, "test11_test", boolean_mt);
127 test11_mh = MethodHandles.guardWithTest(test11_mh_test,
128 MethodHandles.dropArguments(test11_mh1, 0, MethodHandle.class),
129 MethodHandles.invoker(myvalue2_mt));
130 } catch (NoSuchMethodException | IllegalAccessException e) {
131 e.printStackTrace();
132 throw new RuntimeException("Method handle lookup failed");
133 }
134 }
135
136 public static void main(String[] args) throws Throwable {
137 TestMethodHandles test = new TestMethodHandles();
138 test.run(args, MyValue1.class.asValueType(), MyValue2.class.asValueType(), MyValue2Inline.class.asValueType(), MyValue3.class.asValueType(), MyValue3Inline.class.asValueType());
139 }
140
141 // Everything inlined
142 final MyValue3 test1_vt = MyValue3.create();
143
144 @ForceInline
145 MyValue3 test1_target() {
146 return test1_vt;
147 }
148
149 static final MethodHandle test1_mh;
150
151 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + CALL)
152 @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 14 })
153 public MyValue3 test1() throws Throwable {
154 return (MyValue3)test1_mh.invokeExact(this);
155 }
156
157 @DontCompile
158 public void test1_verifier(boolean warmup) throws Throwable {
159 MyValue3 vt = test1();
160 test1_vt.verify(vt);
161 }
162
163 // Leaf method not inlined but returned type is known
164 final MyValue3 test2_vt = MyValue3.create();
165 @DontInline
166 MyValue3 test2_target() {
167 return test2_vt;
168 }
169
170 static final MethodHandle test2_mh;
171
172 @Test
173 public MyValue3 test2() throws Throwable {
174 return (MyValue3)test2_mh.invokeExact(this);
175 }
176
177 @DontCompile
178 public void test2_verifier(boolean warmup) throws Throwable {
179 Method helper_m = getClass().getDeclaredMethod("test2_target");
180 if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
181 WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
182 Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test2_target not compiled");
183 }
184 MyValue3 vt = test2();
185 test2_vt.verify(vt);
186 }
187
188 // Leaf method not inlined and returned type not known
189 final MyValue3 test3_vt = MyValue3.create();
190 @DontInline
191 MyValue3 test3_target() {
192 return test3_vt;
193 }
194
195 static final MethodHandle test3_mh;
196
197 @Test
198 public MyValue3 test3() throws Throwable {
199 return (MyValue3)test3_mh.invokeExact(this);
200 }
201
202 @DontCompile
203 public void test3_verifier(boolean warmup) throws Throwable {
204 // hack so C2 doesn't know the target of the invoke call
205 Class c = Class.forName("java.lang.invoke.DirectMethodHandle");
206 Method m = c.getDeclaredMethod("internalMemberName", Object.class);
207 WHITE_BOX.testSetDontInlineMethod(m, warmup);
208 MyValue3 vt = test3();
209 test3_vt.verify(vt);
210 }
211
212 // When test75_helper1 is inlined in test75, the method handle
213 // linker that called it is passed a pointer to a copy of vt
214 // stored in memory. The method handle linker needs to load the
215 // fields from memory before it inlines test75_helper1.
216 static public int test4_helper1(MyValue1 vt) {
217 return vt.x;
218 }
219
220 static MyValue1 test4_vt = MyValue1.createWithFieldsInline(rI, rL);
221 static public MyValue1 test4_helper2() {
222 return test4_vt;
223 }
224
225 static final MethodHandle test4_mh;
226
227 @Test
228 public int test4() throws Throwable {
229 return (int)test4_mh.invokeExact();
230 }
231
232 @DontCompile
233 public void test4_verifier(boolean warmup) throws Throwable {
234 int i = test4();
235 Asserts.assertEQ(i, test4_vt.x);
236 }
237
238 // Test method handle call with value type argument
239 public int test5_target(MyValue1 vt) {
240 return vt.x;
241 }
242
243 static final MethodHandle test5_mh;
244 MyValue1 test5_vt = MyValue1.createWithFieldsInline(rI, rL);
245
246 @Test
247 public int test5() throws Throwable {
248 return (int)test5_mh.invokeExact(this, test5_vt);
249 }
250
251 @DontCompile
252 public void test5_verifier(boolean warmup) throws Throwable {
253 int i = test5();
254 Asserts.assertEQ(i, test5_vt.x);
255 }
256
257 // Return of target1 and target2 merged in a Lambda Form as an
258 // Object. Shouldn't cause any allocation
259 final MyValue3 test6_vt1 = MyValue3.create();
260 @ForceInline
261 MyValue3 test6_target1() {
262 return test6_vt1;
263 }
264
265 final MyValue3 test6_vt2 = MyValue3.create();
266 @ForceInline
267 MyValue3 test6_target2() {
268 return test6_vt2;
269 }
270
271 boolean test6_bool = true;
272 @ForceInline
273 boolean test6_test() {
274 return test6_bool;
275 }
276
277 static final MethodHandle test6_mh;
278
279 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS)
280 @Test(valid = ValueTypeReturnedAsFieldsOff)
281 public MyValue3 test6() throws Throwable {
282 return (MyValue3)test6_mh.invokeExact(this);
283 }
284
285 @DontCompile
286 public void test6_verifier(boolean warmup) throws Throwable {
287 test6_bool = !test6_bool;
288 MyValue3 vt = test6();
289 vt.verify(test6_bool ? test6_vt1 : test6_vt2);
290 }
291
292 // Similar as above but with the method handle for target1 not
293 // constant. Shouldn't cause any allocation.
294 @ForceInline
295 static MyValue2 test7_target1() {
296 return MyValue2.createWithFieldsInline(rI, true);
297 }
298
299 @ForceInline
300 static MyValue2 test7_target2() {
301 return MyValue2.createWithFieldsInline(rI+1, false);
302 }
303
304 static boolean test7_bool = true;
305 @ForceInline
306 static boolean test7_test() {
307 return test7_bool;
308 }
309
310 static final MethodHandle test7_mh;
311 static MethodHandle test7_mh1;
312
313 @Test
314 public long test7() throws Throwable {
315 return ((MyValue2)test7_mh.invokeExact(test7_mh1)).hash();
316 }
317
318 @DontCompile
319 public void test7_verifier(boolean warmup) throws Throwable {
320 test7_bool = !test7_bool;
321 long hash = test7();
322 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+(test7_bool ? 0 : 1), test7_bool).hash());
323 }
324
325 // Same as above but with the method handle for target2 not
326 // constant. Shouldn't cause any allocation.
327 @ForceInline
328 static MyValue2 test8_target1() {
329 return MyValue2.createWithFieldsInline(rI, true);
330 }
331
332 @ForceInline
333 static MyValue2 test8_target2() {
334 return MyValue2.createWithFieldsInline(rI+1, false);
335 }
336
337 static boolean test8_bool = true;
338 @ForceInline
339 static boolean test8_test() {
340 return test8_bool;
341 }
342
343 static final MethodHandle test8_mh;
344 static MethodHandle test8_mh2;
345
346 @Test
347 public long test8() throws Throwable {
348 return ((MyValue2)test8_mh.invokeExact(test8_mh2)).hash();
349 }
350
351 @DontCompile
352 public void test8_verifier(boolean warmup) throws Throwable {
353 test8_bool = !test8_bool;
354 long hash = test8();
355 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+(test8_bool ? 0 : 1), test8_bool).hash());
356 }
357
358 // Return of target1, target2 and target3 merged in Lambda Forms
359 // as an Object. Shouldn't cause any allocation
360 final MyValue3 test9_vt1 = MyValue3.create();
361 @ForceInline
362 MyValue3 test9_target1() {
363 return test9_vt1;
364 }
365
366 final MyValue3 test9_vt2 = MyValue3.create();
367 @ForceInline
368 MyValue3 test9_target2() {
369 return test9_vt2;
370 }
371
372 final MyValue3 test9_vt3 = MyValue3.create();
373 @ForceInline
374 MyValue3 test9_target3() {
375 return test9_vt3;
376 }
377
378 boolean test9_bool1 = true;
379 @ForceInline
380 boolean test9_test1() {
381 return test9_bool1;
382 }
383
384 boolean test9_bool2 = true;
385 @ForceInline
386 boolean test9_test2() {
387 return test9_bool2;
388 }
389
390 static final MethodHandle test9_mh;
391
392 @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS)
393 @Test(valid = ValueTypeReturnedAsFieldsOff)
394 public MyValue3 test9() throws Throwable {
395 return (MyValue3)test9_mh.invokeExact(this);
396 }
397
398 static int test9_i = 0;
399 @DontCompile
400 public void test9_verifier(boolean warmup) throws Throwable {
401 test9_i++;
402 test9_bool1 = (test9_i % 2) == 0;
403 test9_bool2 = (test9_i % 3) == 0;
404 MyValue3 vt = test9();
405 vt.verify(test9_bool1 ? test9_vt1 : (test9_bool2 ? test9_vt2 : test9_vt3));
406 }
407
408 // Same as above but with non constant target2 and target3
409 @ForceInline
410 static MyValue2 test10_target1() {
411 return MyValue2.createWithFieldsInline(rI, true);
412 }
413
414 @ForceInline
415 static MyValue2 test10_target2() {
416 return MyValue2.createWithFieldsInline(rI+1, false);
417 }
418
419 @ForceInline
420 static MyValue2 test10_target3() {
421 return MyValue2.createWithFieldsInline(rI+2, true);
422 }
423
424 static boolean test10_bool1 = true;
425 @ForceInline
426 static boolean test10_test1() {
427 return test10_bool1;
428 }
429
430 static boolean test10_bool2 = true;
431 @ForceInline
432 static boolean test10_test2() {
433 return test10_bool2;
434 }
435
436 static final MethodHandle test10_mh;
437 static MethodHandle test10_mh2;
438 static MethodHandle test10_mh3;
439
440 @Test
441 public long test10() throws Throwable {
442 return ((MyValue2)test10_mh.invokeExact(test10_mh2, test10_mh3)).hash();
443 }
444
445 static int test10_i = 0;
446
447 @DontCompile
448 public void test10_verifier(boolean warmup) throws Throwable {
449 test10_i++;
450 test10_bool1 = (test10_i % 2) == 0;
451 test10_bool2 = (test10_i % 3) == 0;
452 long hash = test10();
453 int i = rI+(test10_bool1 ? 0 : (test10_bool2 ? 1 : 2));
454 boolean b = test10_bool1 ? true : (test10_bool2 ? false : true);
455 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(i, b).hash());
456 }
457
458 static int test11_i = 0;
459
460 @ForceInline
461 static MyValue2 test11_target1() {
462 return MyValue2.createWithFieldsInline(rI+test11_i, true);
463 }
464
465 @ForceInline
466 static MyValue2 test11_target2() {
467 return MyValue2.createWithFieldsInline(rI-test11_i, false);
468 }
469
470 @ForceInline
471 static boolean test11_test() {
472 return (test11_i % 100) == 0;
473 }
474
475 static final MethodHandle test11_mh;
476 static MethodHandle test11_mh2;
477
478 // Check that a buffered value returned by a compiled lambda form
479 // is properly handled by the caller.
480 @Test
481 @Warmup(11000)
482 public long test11() throws Throwable {
483 return ((MyValue2)test11_mh.invokeExact(test11_mh2)).hash();
484 }
485
486 @DontCompile
487 public void test11_verifier(boolean warmup) throws Throwable {
488 test11_i++;
489 long hash = test11();
490 boolean b = (test11_i % 100) == 0;
491 Asserts.assertEQ(hash, MyValue2.createWithFieldsInline(rI+test11_i * (b ? 1 : -1), b).hash());
492 }
493 }
--- EOF ---