Mercurial > hg > graal-compiler
comparison test/compiler/types/TypeSpeculation.java @ 12966:b2ee5dc63353
8024070: C2 needs some form of type speculation
Summary: record unused type profile information with type system, propagate and use it.
Reviewed-by: kvn, twisti
author | roland |
---|---|
date | Wed, 23 Oct 2013 12:40:23 +0200 |
parents | |
children | 1891b98ded49 |
comparison
equal
deleted
inserted
replaced
12965:8b4bbba322d3 | 12966:b2ee5dc63353 |
---|---|
1 /* | |
2 * Copyright (c) 2013, 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 /* | |
25 * @test | |
26 * @bug 8024070 | |
27 * @summary Test that type speculation doesn't cause incorrect execution | |
28 * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 TypeSpeculation | |
29 * | |
30 */ | |
31 | |
32 public class TypeSpeculation { | |
33 | |
34 interface I { | |
35 } | |
36 | |
37 static class A { | |
38 int m() { | |
39 return 1; | |
40 } | |
41 } | |
42 | |
43 static class B extends A implements I { | |
44 int m() { | |
45 return 2; | |
46 } | |
47 } | |
48 | |
49 static class C extends B { | |
50 int m() { | |
51 return 3; | |
52 } | |
53 } | |
54 | |
55 static int test1_invokevirtual(A a) { | |
56 return a.m(); | |
57 } | |
58 | |
59 static int test1_1(A a) { | |
60 return test1_invokevirtual(a); | |
61 } | |
62 | |
63 static boolean test1() { | |
64 A a = new A(); | |
65 B b = new B(); | |
66 C c = new C(); | |
67 | |
68 // pollute profile at test1_invokevirtual to make sure the | |
69 // compiler cannot rely on it | |
70 for (int i = 0; i < 5000; i++) { | |
71 test1_invokevirtual(a); | |
72 test1_invokevirtual(b); | |
73 test1_invokevirtual(c); | |
74 } | |
75 | |
76 // profiling + speculation should make test1_invokevirtual | |
77 // inline A.m() with a guard | |
78 for (int i = 0; i < 20000; i++) { | |
79 int res = test1_1(b); | |
80 if (res != b.m()) { | |
81 System.out.println("test1 failed with class B"); | |
82 return false; | |
83 } | |
84 } | |
85 // check that the guard works as expected by passing a | |
86 // different type | |
87 int res = test1_1(a); | |
88 if (res != a.m()) { | |
89 System.out.println("test1 failed with class A"); | |
90 return false; | |
91 } | |
92 return true; | |
93 } | |
94 | |
95 static int test2_invokevirtual(A a) { | |
96 return a.m(); | |
97 } | |
98 | |
99 static int test2_1(A a, boolean t) { | |
100 A aa; | |
101 if (t) { | |
102 aa = (B)a; | |
103 } else { | |
104 aa = a; | |
105 } | |
106 // if a of type B is passed to test2_1, the static type of aa | |
107 // here is no better than A but the profiled type is B so this | |
108 // should inline | |
109 return test2_invokevirtual(aa); | |
110 } | |
111 | |
112 static boolean test2() { | |
113 A a = new A(); | |
114 B b = new B(); | |
115 C c = new C(); | |
116 | |
117 // pollute profile at test2_invokevirtual to make sure the | |
118 // compiler cannot rely on it | |
119 for (int i = 0; i < 5000; i++) { | |
120 test2_invokevirtual(a); | |
121 test2_invokevirtual(b); | |
122 test2_invokevirtual(c); | |
123 } | |
124 | |
125 // profiling + speculation should make test2_invokevirtual | |
126 // inline A.m() with a guard | |
127 for (int i = 0; i < 20000; i++) { | |
128 int res = test2_1(b, (i % 2) == 0); | |
129 if (res != b.m()) { | |
130 System.out.println("test2 failed with class B"); | |
131 return false; | |
132 } | |
133 } | |
134 // check that the guard works as expected by passing a | |
135 // different type | |
136 int res = test2_1(a, false); | |
137 if (res != a.m()) { | |
138 System.out.println("test2 failed with class A"); | |
139 return false; | |
140 } | |
141 return true; | |
142 } | |
143 | |
144 static int test3_invokevirtual(A a) { | |
145 return a.m(); | |
146 } | |
147 | |
148 static void test3_2(A a) { | |
149 } | |
150 | |
151 static int test3_1(A a, int i) { | |
152 if (i == 0) { | |
153 return 0; | |
154 } | |
155 // If we come here and a is of type B but parameter profiling | |
156 // is polluted, both branches of the if below should have | |
157 // profiling that tell us and inlining of the virtual call | |
158 // should happen | |
159 if (i == 1) { | |
160 test3_2(a); | |
161 } else { | |
162 test3_2(a); | |
163 } | |
164 return test3_invokevirtual(a); | |
165 } | |
166 | |
167 static boolean test3() { | |
168 A a = new A(); | |
169 B b = new B(); | |
170 C c = new C(); | |
171 | |
172 // pollute profile at test3_invokevirtual and test3_1 to make | |
173 // sure the compiler cannot rely on it | |
174 for (int i = 0; i < 3000; i++) { | |
175 test3_invokevirtual(a); | |
176 test3_invokevirtual(b); | |
177 test3_invokevirtual(c); | |
178 test3_1(a, 0); | |
179 test3_1(b, 0); | |
180 } | |
181 | |
182 // profiling + speculation should make test3_invokevirtual | |
183 // inline A.m() with a guard | |
184 for (int i = 0; i < 20000; i++) { | |
185 int res = test3_1(b, (i % 2) + 1); | |
186 if (res != b.m()) { | |
187 System.out.println("test3 failed with class B"); | |
188 return false; | |
189 } | |
190 } | |
191 // check that the guard works as expected by passing a | |
192 // different type | |
193 int res = test3_1(a, 1); | |
194 if (res != a.m()) { | |
195 System.out.println("test3 failed with class A"); | |
196 return false; | |
197 } | |
198 return true; | |
199 } | |
200 | |
201 // Mix 2 incompatible profiled types | |
202 static int test4_invokevirtual(A a) { | |
203 return a.m(); | |
204 } | |
205 | |
206 static void test4_2(A a) { | |
207 } | |
208 | |
209 static int test4_1(A a, boolean b) { | |
210 if (b) { | |
211 test4_2(a); | |
212 } else { | |
213 test4_2(a); | |
214 } | |
215 // shouldn't inline | |
216 return test4_invokevirtual(a); | |
217 } | |
218 | |
219 static boolean test4() { | |
220 A a = new A(); | |
221 B b = new B(); | |
222 C c = new C(); | |
223 | |
224 // pollute profile at test3_invokevirtual and test3_1 to make | |
225 // sure the compiler cannot rely on it | |
226 for (int i = 0; i < 3000; i++) { | |
227 test4_invokevirtual(a); | |
228 test4_invokevirtual(b); | |
229 test4_invokevirtual(c); | |
230 } | |
231 | |
232 for (int i = 0; i < 20000; i++) { | |
233 if ((i % 2) == 0) { | |
234 int res = test4_1(a, true); | |
235 if (res != a.m()) { | |
236 System.out.println("test4 failed with class A"); | |
237 return false; | |
238 } | |
239 } else { | |
240 int res = test4_1(b, false); | |
241 if (res != b.m()) { | |
242 System.out.println("test4 failed with class B"); | |
243 return false; | |
244 } | |
245 } | |
246 } | |
247 return true; | |
248 } | |
249 | |
250 // Mix one profiled type with an incompatible type | |
251 static int test5_invokevirtual(A a) { | |
252 return a.m(); | |
253 } | |
254 | |
255 static void test5_2(A a) { | |
256 } | |
257 | |
258 static int test5_1(A a, boolean b) { | |
259 if (b) { | |
260 test5_2(a); | |
261 } else { | |
262 A aa = (B)a; | |
263 } | |
264 // shouldn't inline | |
265 return test5_invokevirtual(a); | |
266 } | |
267 | |
268 static boolean test5() { | |
269 A a = new A(); | |
270 B b = new B(); | |
271 C c = new C(); | |
272 | |
273 // pollute profile at test3_invokevirtual and test3_1 to make | |
274 // sure the compiler cannot rely on it | |
275 for (int i = 0; i < 3000; i++) { | |
276 test5_invokevirtual(a); | |
277 test5_invokevirtual(b); | |
278 test5_invokevirtual(c); | |
279 } | |
280 | |
281 for (int i = 0; i < 20000; i++) { | |
282 if ((i % 2) == 0) { | |
283 int res = test5_1(a, true); | |
284 if (res != a.m()) { | |
285 System.out.println("test5 failed with class A"); | |
286 return false; | |
287 } | |
288 } else { | |
289 int res = test5_1(b, false); | |
290 if (res != b.m()) { | |
291 System.out.println("test5 failed with class B"); | |
292 return false; | |
293 } | |
294 } | |
295 } | |
296 return true; | |
297 } | |
298 | |
299 // Mix incompatible profiled types | |
300 static void test6_2(Object o) { | |
301 } | |
302 | |
303 static Object test6_1(Object o, boolean b) { | |
304 if (b) { | |
305 test6_2(o); | |
306 } else { | |
307 test6_2(o); | |
308 } | |
309 return o; | |
310 } | |
311 | |
312 static boolean test6() { | |
313 A a = new A(); | |
314 A[] aa = new A[10]; | |
315 | |
316 for (int i = 0; i < 20000; i++) { | |
317 if ((i % 2) == 0) { | |
318 test6_1(a, true); | |
319 } else { | |
320 test6_1(aa, false); | |
321 } | |
322 } | |
323 return true; | |
324 } | |
325 | |
326 // Mix a profiled type with an incompatible type | |
327 static void test7_2(Object o) { | |
328 } | |
329 | |
330 static Object test7_1(Object o, boolean b) { | |
331 if (b) { | |
332 test7_2(o); | |
333 } else { | |
334 Object oo = (A[])o; | |
335 } | |
336 return o; | |
337 } | |
338 | |
339 static boolean test7() { | |
340 A a = new A(); | |
341 A[] aa = new A[10]; | |
342 | |
343 for (int i = 0; i < 20000; i++) { | |
344 if ((i % 2) == 0) { | |
345 test7_1(a, true); | |
346 } else { | |
347 test7_1(aa, false); | |
348 } | |
349 } | |
350 return true; | |
351 } | |
352 | |
353 // Mix a profiled type with an interface | |
354 static void test8_2(Object o) { | |
355 } | |
356 | |
357 static I test8_1(Object o) { | |
358 test8_2(o); | |
359 return (I)o; | |
360 } | |
361 | |
362 static boolean test8() { | |
363 A a = new A(); | |
364 B b = new B(); | |
365 C c = new C(); | |
366 | |
367 for (int i = 0; i < 20000; i++) { | |
368 test8_1(b); | |
369 } | |
370 return true; | |
371 } | |
372 | |
373 // Mix a profiled type with a constant | |
374 static void test9_2(Object o) { | |
375 } | |
376 | |
377 static Object test9_1(Object o, boolean b) { | |
378 Object oo; | |
379 if (b) { | |
380 test9_2(o); | |
381 oo = o; | |
382 } else { | |
383 oo = "some string"; | |
384 } | |
385 return oo; | |
386 } | |
387 | |
388 static boolean test9() { | |
389 A a = new A(); | |
390 | |
391 for (int i = 0; i < 20000; i++) { | |
392 if ((i % 2) == 0) { | |
393 test9_1(a, true); | |
394 } else { | |
395 test9_1(a, false); | |
396 } | |
397 } | |
398 return true; | |
399 } | |
400 | |
401 static public void main(String[] args) { | |
402 boolean success = true; | |
403 | |
404 success = test1() && success; | |
405 | |
406 success = test2() && success; | |
407 | |
408 success = test3() && success; | |
409 | |
410 success = test4() && success; | |
411 | |
412 success = test5() && success; | |
413 | |
414 success = test6() && success; | |
415 | |
416 success = test7() && success; | |
417 | |
418 success = test8() && success; | |
419 | |
420 success = test9() && success; | |
421 | |
422 if (success) { | |
423 System.out.println("TEST PASSED"); | |
424 } else { | |
425 throw new RuntimeException("TEST FAILED: erroneous bound check elimination"); | |
426 } | |
427 } | |
428 } |