comparison test/compiler/rangechecks/TestRangeCheckSmearing.java @ 21830:eff80b90c3ad

Merge
author asaha
date Mon, 22 Dec 2014 09:27:29 -0800
parents e3d0aaab84aa
children
comparison
equal deleted inserted replaced
21829:02e2c04a3289 21830:eff80b90c3ad
1 /*
2 * Copyright (c) 2014, 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 8066103
27 * @summary C2's range check smearing allows out of bound array accesses
28 * @library /testlibrary /testlibrary/whitebox /compiler/whitebox /testlibrary/com/oracle/java/testlibrary
29 * @build TestRangeCheckSmearing
30 * @run main ClassFileInstaller sun.hotspot.WhiteBox
31 * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
32 * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
33 * -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearing
34 *
35 */
36
37 import java.lang.annotation.*;
38 import java.lang.reflect.*;
39 import java.util.*;
40 import sun.hotspot.WhiteBox;
41 import sun.hotspot.code.NMethod;
42 import com.oracle.java.testlibrary.Platform;
43
44 public class TestRangeCheckSmearing {
45 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
46
47 @Retention(RetentionPolicy.RUNTIME)
48 @interface Args { int[] value(); }
49
50 // first range check is i + max of all constants
51 @Args({0, 8})
52 static int m1(int[] array, int i, boolean allaccesses) {
53 int res = 0;
54 res += array[i+9];
55 if (allaccesses) {
56 res += array[i+8];
57 res += array[i+7];
58 res += array[i+6];
59 res += array[i+5];
60 res += array[i+4];
61 res += array[i+3];
62 res += array[i+2];
63 res += array[i+1];
64 }
65 return res;
66 }
67
68 // first range check is i + min of all constants
69 @Args({0, -9})
70 static int m2(int[] array, int i, boolean allaccesses) {
71 int res = 0;
72 res += array[i+1];
73 if (allaccesses) {
74 res += array[i+2];
75 res += array[i+3];
76 res += array[i+4];
77 res += array[i+5];
78 res += array[i+6];
79 res += array[i+7];
80 res += array[i+8];
81 res += array[i+9];
82 }
83 return res;
84 }
85
86 // first range check is not i + min/max of all constants
87 @Args({0, 8})
88 static int m3(int[] array, int i, boolean allaccesses) {
89 int res = 0;
90 res += array[i+3];
91 if (allaccesses) {
92 res += array[i+2];
93 res += array[i+1];
94 res += array[i+4];
95 res += array[i+5];
96 res += array[i+6];
97 res += array[i+7];
98 res += array[i+8];
99 res += array[i+9];
100 }
101 return res;
102 }
103
104 @Args({0, -9})
105 static int m4(int[] array, int i, boolean allaccesses) {
106 int res = 0;
107 res += array[i+3];
108 if (allaccesses) {
109 res += array[i+4];
110 res += array[i+1];
111 res += array[i+2];
112 res += array[i+5];
113 res += array[i+6];
114 res += array[i+7];
115 res += array[i+8];
116 res += array[i+9];
117 }
118 return res;
119 }
120
121 @Args({0, -3})
122 static int m5(int[] array, int i, boolean allaccesses) {
123 int res = 0;
124 res += array[i+3];
125 res += array[i+2];
126 if (allaccesses) {
127 res += array[i+1];
128 res += array[i+4];
129 res += array[i+5];
130 res += array[i+6];
131 res += array[i+7];
132 res += array[i+8];
133 res += array[i+9];
134 }
135 return res;
136 }
137
138 @Args({0, 6})
139 static int m6(int[] array, int i, boolean allaccesses) {
140 int res = 0;
141 res += array[i+3];
142 res += array[i+4];
143 if (allaccesses) {
144 res += array[i+2];
145 res += array[i+1];
146 res += array[i+5];
147 res += array[i+6];
148 res += array[i+7];
149 res += array[i+8];
150 res += array[i+9];
151 }
152 return res;
153 }
154
155 @Args({0, 6})
156 static int m7(int[] array, int i, boolean allaccesses) {
157 int res = 0;
158 res += array[i+3];
159 res += array[i+2];
160 res += array[i+4];
161 if (allaccesses) {
162 res += array[i+1];
163 res += array[i+5];
164 res += array[i+6];
165 res += array[i+7];
166 res += array[i+8];
167 res += array[i+9];
168 }
169 return res;
170 }
171
172 @Args({0, -3})
173 static int m8(int[] array, int i, boolean allaccesses) {
174 int res = 0;
175 res += array[i+3];
176 res += array[i+4];
177 res += array[i+2];
178 if (allaccesses) {
179 res += array[i+1];
180 res += array[i+5];
181 res += array[i+6];
182 res += array[i+7];
183 res += array[i+8];
184 res += array[i+9];
185 }
186 return res;
187 }
188
189 @Args({6, 15})
190 static int m9(int[] array, int i, boolean allaccesses) {
191 int res = 0;
192 res += array[i+3];
193 if (allaccesses) {
194 res += array[i-2];
195 res += array[i-1];
196 res += array[i-4];
197 res += array[i-5];
198 res += array[i-6];
199 }
200 return res;
201 }
202
203 @Args({3, 12})
204 static int m10(int[] array, int i, boolean allaccesses) {
205 int res = 0;
206 res += array[i+3];
207 if (allaccesses) {
208 res += array[i-2];
209 res += array[i-1];
210 res += array[i-3];
211 res += array[i+4];
212 res += array[i+5];
213 res += array[i+6];
214 }
215 return res;
216 }
217
218 @Args({3, -3})
219 static int m11(int[] array, int i, boolean allaccesses) {
220 int res = 0;
221 res += array[i+3];
222 res += array[i-2];
223 if (allaccesses) {
224 res += array[i+5];
225 res += array[i+6];
226 }
227 return res;
228 }
229
230 @Args({3, 6})
231 static int m12(int[] array, int i, boolean allaccesses) {
232 int res = 0;
233 res += array[i+3];
234 res += array[i+6];
235 if (allaccesses) {
236 res += array[i-2];
237 res += array[i-3];
238 }
239 return res;
240 }
241
242 // check that identical range check is replaced by dominating one
243 // only when correct
244 @Args({0})
245 static int m13(int[] array, int i, boolean ignore) {
246 int res = 0;
247 res += array[i+3];
248 res += array[i+3];
249 return res;
250 }
251
252 @Args({2, 0})
253 static int m14(int[] array, int i, boolean ignore) {
254 int res = 0;
255
256 res += array[i];
257 res += array[i-2];
258 res += array[i]; // If range check below were to be removed first this cannot be considered identical to first range check
259 res += array[i-1]; // range check removed so i-1 array access depends on previous check
260
261 return res;
262 }
263
264 static int[] m15_dummy = new int[10];
265 @Args({2, 0})
266 static int m15(int[] array, int i, boolean ignore) {
267 int res = 0;
268 res += array[i];
269
270 // When the loop is optimized out we don't want the
271 // array[i-1] access which is dependent on array[i]'s
272 // range check to become dependent on the identical range
273 // check above.
274
275 int[] array2 = m15_dummy;
276 int j = 0;
277 for (; j < 10; j++);
278 if (j == 10) {
279 array2 = array;
280 }
281
282 res += array2[i-2];
283 res += array2[i];
284 res += array2[i-1]; // range check removed so i-1 array access depends on previous check
285
286 return res;
287 }
288
289 @Args({2, 0})
290 static int m16(int[] array, int i, boolean ignore) {
291 int res = 0;
292
293 res += array[i];
294 res += array[i-1];
295 res += array[i-1];
296 res += array[i-2];
297
298 return res;
299 }
300
301 @Args({2, 0})
302 static int m17(int[] array, int i, boolean ignore) {
303 int res = 0;
304
305 res += array[i];
306 res += array[i-2];
307 res += array[i-2];
308 res += array[i+2];
309 res += array[i+2];
310 res += array[i-1];
311 res += array[i-1];
312
313 return res;
314 }
315
316 static public void main(String[] args) {
317 if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
318 throw new AssertionError("Background compilation enabled");
319 }
320 new TestRangeCheckSmearing().doTests();
321 }
322 boolean success = true;
323 boolean exception = false;
324 final int[] array = new int[10];
325 final HashMap<String,Method> tests = new HashMap<>();
326 {
327 final Class<?> TEST_PARAM_TYPES[] = { int[].class, int.class, boolean.class };
328 for (Method m : this.getClass().getDeclaredMethods()) {
329 if (m.getName().matches("m[0-9]+")) {
330 assert(Modifier.isStatic(m.getModifiers())) : m;
331 assert(m.getReturnType() == int.class) : m;
332 assert(Arrays.equals(m.getParameterTypes(), TEST_PARAM_TYPES)) : m;
333 tests.put(m.getName(), m);
334 }
335 }
336 }
337
338 void invokeTest(Method m, int[] array, int index, boolean z) {
339 try {
340 m.invoke(null, array, index, z);
341 } catch (ReflectiveOperationException roe) {
342 Throwable ex = roe.getCause();
343 if (ex instanceof ArrayIndexOutOfBoundsException)
344 throw (ArrayIndexOutOfBoundsException) ex;
345 throw new AssertionError(roe);
346 }
347 }
348
349 void doTest(String name) {
350 Method m = tests.get(name);
351 tests.remove(name);
352 int[] args = m.getAnnotation(Args.class).value();
353 int index0 = args[0], index1;
354 boolean exceptionRequired = true;
355 if (args.length == 2) {
356 index1 = args[1];
357 } else {
358 // no negative test for this one
359 assert(args.length == 1);
360 assert(name.equals("m13"));
361 exceptionRequired = false;
362 index1 = index0;
363 }
364 // Get the method compiled.
365 if (!WHITE_BOX.isMethodCompiled(m)) {
366 // If not, try to compile it with C2
367 if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
368 // C2 compiler not available, try to compile with C1
369 WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
370 }
371 }
372 if (!WHITE_BOX.isMethodCompiled(m)) {
373 throw new RuntimeException(m + " not compiled");
374 }
375
376 // valid access
377 invokeTest(m, array, index0, true);
378
379 if (!WHITE_BOX.isMethodCompiled(m)) {
380 throw new RuntimeException(m + " deoptimized on valid array access");
381 }
382
383 exception = false;
384 boolean test_success = true;
385 try {
386 invokeTest(m, array, index1, false);
387 } catch(ArrayIndexOutOfBoundsException aioob) {
388 exception = true;
389 System.out.println("ArrayIndexOutOfBoundsException thrown in "+name);
390 }
391 if (!exception) {
392 System.out.println("ArrayIndexOutOfBoundsException was not thrown in "+name);
393 }
394
395 if (Platform.isServer()) {
396 if (exceptionRequired == WHITE_BOX.isMethodCompiled(m)) {
397 System.out.println((exceptionRequired?"Didn't deoptimized":"deoptimized") + " in "+name);
398 test_success = false;
399 }
400 }
401
402 if (exception != exceptionRequired) {
403 System.out.println((exceptionRequired?"exception required but not thrown":"not exception required but thrown") + " in "+name);
404 test_success = false;
405 }
406
407 if (!test_success) {
408 success = false;
409 System.out.println("TEST FAILED: "+name);
410 }
411
412 }
413 void doTests() {
414 doTest("m1");
415 doTest("m2");
416 doTest("m3");
417 doTest("m4");
418 doTest("m5");
419 doTest("m6");
420 doTest("m7");
421 doTest("m8");
422 doTest("m9");
423 doTest("m10");
424 doTest("m11");
425 doTest("m12");
426 doTest("m13");
427 doTest("m14");
428 doTest("m15");
429 doTest("m16");
430 doTest("m17");
431 if (!success) {
432 throw new RuntimeException("Some tests failed");
433 }
434 assert(tests.isEmpty()) : tests;
435 }
436 }