Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/compiler/rangechecks/TestExplicitRangeChecks.java
41152 views
1
/*
2
* Copyright (c) 2016, 2021, 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 8073480
27
* @summary explicit range checks should be recognized by C2
28
* @library /test/lib /
29
* @modules java.base/jdk.internal.misc:+open
30
* @build sun.hotspot.WhiteBox
31
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
32
* @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
33
* -XX:-BackgroundCompilation -XX:-UseOnStackReplacement
34
* -XX:CompileCommand=compileonly,compiler.rangechecks.TestExplicitRangeChecks::test*
35
* compiler.rangechecks.TestExplicitRangeChecks
36
*
37
*/
38
39
package compiler.rangechecks;
40
41
import compiler.whitebox.CompilerWhiteBoxTest;
42
import jdk.internal.misc.Unsafe;
43
import jdk.test.lib.Platform;
44
import sun.hotspot.WhiteBox;
45
46
import java.lang.annotation.Retention;
47
import java.lang.annotation.RetentionPolicy;
48
import java.lang.reflect.Field;
49
import java.lang.reflect.Method;
50
import java.lang.reflect.Modifier;
51
import java.util.HashMap;
52
53
public class TestExplicitRangeChecks {
54
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
55
private static final int TIERED_STOP_AT_LEVEL = WHITE_BOX.getIntxVMFlag("TieredStopAtLevel").intValue();
56
private static int[] array = new int[10];
57
private static boolean success = true;
58
59
@Retention(RetentionPolicy.RUNTIME)
60
@interface Args {
61
int[] compile();
62
int[] good();
63
int[] bad();
64
boolean deoptimize() default true;
65
}
66
67
// Should be compiled as a single unsigned comparison
68
// 0 <= index < array.length
69
@Args(compile = {5,}, good = {0, 9}, bad = {-1, 10})
70
static boolean test1_1(int index, int[] array) {
71
if (index < 0 || index >= array.length) {
72
return false;
73
}
74
return true;
75
}
76
77
// same test but so we can compile with same optimization after trap in test1_1
78
static boolean test1_2(int index, int[] array) {
79
if (index < 0 || index >= array.length) {
80
return false;
81
}
82
return true;
83
}
84
85
// Shouldn't matter whether first or second test is the one
86
// against a constants
87
// 0 <= index < array.length
88
@Args(compile = {5,}, good = {0, 9}, bad = {-1, 10})
89
static boolean test2_1(int index, int[] array) {
90
if (index >= array.length || index < 0) {
91
return false;
92
}
93
return true;
94
}
95
96
static boolean test2_2(int index, int[] array) {
97
if (index >= array.length || index < 0) {
98
return false;
99
}
100
return true;
101
}
102
103
// 0 <= index <= array.length
104
@Args(compile = {5,}, good = {0, 10}, bad = {-1, 11})
105
static boolean test3_1(int index, int[] array) {
106
if (index < 0 || index > array.length) {
107
return false;
108
}
109
return true;
110
}
111
112
static boolean test3_2(int index, int[] array) {
113
if (index < 0 || index > array.length) {
114
return false;
115
}
116
return true;
117
}
118
119
// 0 <= index <= array.length
120
@Args(compile = {5,}, good = {0, 10}, bad = {-1, 11})
121
static boolean test4_1(int index, int[] array) {
122
if (index > array.length || index < 0 ) {
123
return false;
124
}
125
return true;
126
}
127
128
static boolean test4_2(int index, int[] array) {
129
if (index > array.length || index < 0) {
130
return false;
131
}
132
return true;
133
}
134
135
static int[] test5_helper(int i) {
136
return (i < 100) ? new int[10] : new int[5];
137
}
138
139
// 0 < index < array.length
140
@Args(compile = {5,}, good = {1, 9}, bad = {0, 10})
141
static boolean test5_1(int index, int[] array) {
142
array = test5_helper(index); // array.length must be not constant greater than 1
143
if (index <= 0 || index >= array.length) {
144
return false;
145
}
146
return true;
147
}
148
149
static boolean test5_2(int index, int[] array) {
150
array = test5_helper(index); // array.length must be not constant greater than 1
151
if (index <= 0 || index >= array.length) {
152
return false;
153
}
154
return true;
155
}
156
157
// 0 < index < array.length
158
@Args(compile = {5,}, good = {1, 9}, bad = {0, 10})
159
static boolean test6_1(int index, int[] array) {
160
array = test5_helper(index); // array.length must be not constant greater than 1
161
if (index >= array.length || index <= 0 ) {
162
return false;
163
}
164
return true;
165
}
166
167
static boolean test6_2(int index, int[] array) {
168
array = test5_helper(index); // array.length must be not constant greater than 1
169
if (index >= array.length || index <= 0) {
170
return false;
171
}
172
return true;
173
}
174
175
// 0 < index <= array.length
176
@Args(compile = {5,}, good = {1, 10}, bad = {0, 11})
177
static boolean test7_1(int index, int[] array) {
178
if (index <= 0 || index > array.length) {
179
return false;
180
}
181
return true;
182
}
183
184
static boolean test7_2(int index, int[] array) {
185
if (index <= 0 || index > array.length) {
186
return false;
187
}
188
return true;
189
}
190
191
// 0 < index <= array.length
192
@Args(compile = {5,}, good = {1, 10}, bad = {0, 11})
193
static boolean test8_1(int index, int[] array) {
194
if (index > array.length || index <= 0 ) {
195
return false;
196
}
197
return true;
198
}
199
200
static boolean test8_2(int index, int[] array) {
201
if (index > array.length || index <= 0) {
202
return false;
203
}
204
return true;
205
}
206
207
static int[] test9_helper1(int i) {
208
return (i < 100) ? new int[1] : new int[2];
209
}
210
211
static int[] test9_helper2(int i) {
212
return (i < 100) ? new int[10] : new int[11];
213
}
214
215
// array1.length <= index < array2.length
216
@Args(compile = {5,}, good = {1, 9}, bad = {0, 10})
217
static boolean test9_1(int index, int[] array) {
218
int[] array1 = test9_helper1(index);
219
int[] array2 = test9_helper2(index);
220
if (index < array1.length || index >= array2.length) {
221
return false;
222
}
223
return true;
224
}
225
226
static boolean test9_2(int index, int[] array) {
227
int[] array1 = test9_helper1(index);
228
int[] array2 = test9_helper2(index);
229
if (index < array1.length || index >= array2.length) {
230
return false;
231
}
232
return true;
233
}
234
235
// Previously supported pattern
236
@Args(compile = {-5,5,15}, good = {0, 9}, bad = {-1, 10}, deoptimize=false)
237
static boolean test10_1(int index, int[] array) {
238
if (index < 0 || index >= 10) {
239
return false;
240
}
241
return true;
242
}
243
244
static int[] array11 = new int[10];
245
@Args(compile = {5,}, good = {0, 9}, bad = {-1,})
246
static boolean test11_1(int index, int[] array) {
247
if (index < 0) {
248
return false;
249
}
250
int unused = array11[index];
251
// If this one is folded with the first test then we allow
252
// array access above to proceed even for out of bound array
253
// index and the method throws an
254
// ArrayIndexOutOfBoundsException.
255
if (index >= array.length) {
256
return false;
257
}
258
return true;
259
}
260
261
static int[] array12 = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
262
@Args(compile = {5,}, good = {0, 9}, bad = {-1,})
263
static boolean test12_1(int index, int[] array) {
264
// Cannot be folded otherwise would cause incorrect array
265
// access if the array12 range check is executed before the
266
// folded test.
267
if (index < 0 || index >= array12[index]) {
268
return false;
269
}
270
return true;
271
}
272
273
// Same as test1_1 but pass null array when index < 0: shouldn't
274
// cause NPE.
275
@Args(compile = {5,}, good = {0, 9}, bad = {})
276
static boolean test13_1(int index, int[] array) {
277
if (index < 0 || index >= array.length) {
278
return false;
279
}
280
return true;
281
}
282
283
// Same as test10 but with uncommon traps
284
@Args(compile = {5}, good = {0, 9}, bad = {-1, 10})
285
static boolean test14_1(int index, int[] array) {
286
if (index < 0 || index >= 10) {
287
return false;
288
}
289
return true;
290
}
291
292
static boolean test14_2(int index, int[] array) {
293
if (index < 0 || index >= 10) {
294
return false;
295
}
296
return true;
297
}
298
299
// Same as test13_1 but pass null array: null trap should be reported on first if
300
@Args(compile = {5,}, good = {0, 9}, bad = {})
301
static boolean test15_1(int index, int[] array) {
302
if (index < 0 || index >= array.length) {
303
return false;
304
}
305
return true;
306
}
307
308
// Same as test1 but with no null check between the integer comparisons
309
@Args(compile = {5,}, good = {0, 9}, bad = {-1, 10})
310
static boolean test16_1(int index, int[] array) {
311
int l = array.length;
312
if (index < 0 || index >= l) {
313
return false;
314
}
315
return true;
316
}
317
318
static boolean test16_2(int index, int[] array) {
319
int l = array.length;
320
if (index < 0 || index >= l) {
321
return false;
322
}
323
return true;
324
}
325
326
// Same as test1 but bound check on array access should optimize
327
// out.
328
@Args(compile = {5,}, good = {0, 9}, bad = {-1, 10})
329
static boolean test17_1(int index, int[] array) {
330
if (index < 0 || index >= array.length) {
331
return false;
332
}
333
array[index] = 0;
334
return true;
335
}
336
337
static boolean test17_2(int index, int[] array) {
338
if (index < 0 || index >= array.length) {
339
return false;
340
}
341
array[index] = 0;
342
return true;
343
}
344
345
// Same as test1 but range check smearing should optimize
346
// 3rd range check out.
347
@Args(compile = {5,}, good = {}, bad = {})
348
static boolean test18_1(int index, int[] array) {
349
if (index < 0 || index >= array.length) {
350
return false;
351
}
352
array[index+2] = 0;
353
array[index+1] = 0;
354
return true;
355
}
356
357
static boolean test19_helper1(int index) {
358
if (index < 12) {
359
return false;
360
}
361
return true;
362
}
363
364
static boolean test19_helper2(int index) {
365
if (index > 8) {
366
return false;
367
}
368
return true;
369
}
370
371
// Second test should be optimized out
372
static boolean test19(int index, int[] array) {
373
test19_helper1(index);
374
test19_helper2(index);
375
return true;
376
}
377
378
final HashMap<String,Method> tests = new HashMap<>();
379
{
380
for (Method m : this.getClass().getDeclaredMethods()) {
381
if (m.getName().matches("test[0-9]+(_[0-9])?")) {
382
assert(Modifier.isStatic(m.getModifiers())) : m;
383
tests.put(m.getName(), m);
384
}
385
}
386
}
387
388
void doTest(String name) throws Exception {
389
Method m = tests.get(name + "_1");
390
391
Args anno = m.getAnnotation(Args.class);
392
int[] compile = anno.compile();
393
int[] good = anno.good();
394
int[] bad = anno.bad();
395
boolean deoptimize = anno.deoptimize();
396
397
// Get compiled
398
for (int i = 0; i < 20000;) {
399
for (int j = 0; j < compile.length; j++) {
400
m.invoke(null, compile[j], array);
401
i++;
402
}
403
}
404
405
if (!WHITE_BOX.isMethodCompiled(m)) {
406
System.out.println(name + "_1 not compiled");
407
success = false;
408
}
409
410
// check that good values don't trigger exception or
411
// deoptimization
412
for (int i = 0; i < good.length; i++) {
413
boolean res = (boolean)m.invoke(null, good[i], array);
414
415
if (!res) {
416
System.out.println(name + " bad result for good input " + good[i]);
417
success = false;
418
}
419
if (!WHITE_BOX.isMethodCompiled(m)) {
420
System.out.println(name + " deoptimized on valid access");
421
success = false;
422
}
423
}
424
425
// check that bad values trigger exception and deoptimization
426
for (int i = 0; i < bad.length; i++) {
427
if (i > 0 && deoptimize) {
428
m = tests.get(name + "_" + (i+1));
429
for (int k = 0; k < 20000;) {
430
for (int j = 0; j < compile.length; j++) {
431
m.invoke(null, compile[j], array);
432
k++;
433
}
434
}
435
if (!WHITE_BOX.isMethodCompiled(m)) {
436
System.out.println(name + ("_" + (i+1)) + " not compiled");
437
success = false;
438
}
439
}
440
441
boolean res = (boolean)m.invoke(null, bad[i], array);
442
443
if (res) {
444
System.out.println(name + " bad result for bad input " + bad[i]);
445
success = false;
446
}
447
// Only perform these additional checks if C2 is available
448
if (Platform.isServer() && !Platform.isEmulatedClient() &&
449
TIERED_STOP_AT_LEVEL == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) {
450
if (deoptimize && WHITE_BOX.isMethodCompiled(m)) {
451
System.out.println(name + " not deoptimized on invalid access");
452
success = false;
453
} else if (!deoptimize && !WHITE_BOX.isMethodCompiled(m)) {
454
System.out.println(name + " deoptimized on invalid access");
455
success = false;
456
}
457
}
458
}
459
460
}
461
462
private static final Unsafe UNSAFE;
463
464
static {
465
try {
466
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
467
unsafeField.setAccessible(true);
468
UNSAFE = (Unsafe) unsafeField.get(null);
469
}
470
catch (Exception e) {
471
throw new AssertionError(e);
472
}
473
}
474
475
// On x64, int to long conversion should optimize away in address computation
476
static int test20(int[] a) {
477
int sum = 0;
478
for (int i = 0; i < a.length; i++) {
479
sum += test20_helper(a, i);
480
}
481
return sum;
482
}
483
484
static int test20_helper(int[] a, int i) {
485
if (i < 0 || i >= a.length)
486
throw new ArrayIndexOutOfBoundsException();
487
488
long address = (((long) i) << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET;
489
return UNSAFE.getInt(a, address);
490
}
491
492
static int test21(int[] a) {
493
int sum = 0;
494
for (int i = 0; i < a.length; i++) {
495
sum += test20_helper(a, i);
496
}
497
return sum;
498
}
499
500
static int test21_helper(int[] a, int i) {
501
if (i < 0 || i >= a.length)
502
throw new ArrayIndexOutOfBoundsException();
503
504
long address = (((long) i) << 2) + UNSAFE.ARRAY_INT_BASE_OFFSET;
505
return UNSAFE.getIntVolatile(a, address);
506
}
507
508
static public void main(String[] args) throws Exception {
509
510
if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
511
throw new AssertionError("Background compilation enabled");
512
}
513
514
TestExplicitRangeChecks test = new TestExplicitRangeChecks();
515
516
test.doTest("test1");
517
test.doTest("test2");
518
test.doTest("test3");
519
test.doTest("test4");
520
521
// pollute branch profile
522
for (int i = 0; i < 10000; i++) {
523
test5_helper((i%2 == 0) ? 0 : 1000);
524
}
525
526
test.doTest("test5");
527
test.doTest("test6");
528
test.doTest("test7");
529
test.doTest("test8");
530
531
// pollute branch profile
532
for (int i = 0; i < 10000; i++) {
533
test9_helper1((i%2 == 0) ? 0 : 1000);
534
test9_helper2((i%2 == 0) ? 0 : 1000);
535
}
536
537
test.doTest("test9");
538
test.doTest("test10");
539
test.doTest("test11");
540
test.doTest("test12");
541
542
test.doTest("test13");
543
{
544
Method m = test.tests.get("test13_1");
545
for (int i = 0; i < 1; i++) {
546
test13_1(-1, null);
547
if (!WHITE_BOX.isMethodCompiled(m)) {
548
break;
549
}
550
}
551
}
552
test.doTest("test13");
553
{
554
Method m = test.tests.get("test13_1");
555
for (int i = 0; i < 10; i++) {
556
test13_1(-1, null);
557
if (!WHITE_BOX.isMethodCompiled(m)) {
558
break;
559
}
560
}
561
}
562
563
test.doTest("test14");
564
565
test.doTest("test15");
566
{
567
Method m = test.tests.get("test15_1");
568
for (int i = 0; i < 10; i++) {
569
try {
570
test15_1(5, null);
571
} catch(NullPointerException npe) {}
572
if (!WHITE_BOX.isMethodCompiled(m)) {
573
break;
574
}
575
}
576
}
577
test.doTest("test15");
578
test.doTest("test16");
579
test.doTest("test17");
580
test.doTest("test18");
581
582
for (int i = 0; i < 20000; i++) {
583
test19_helper1(20);
584
test19_helper2(5);
585
}
586
587
{
588
Method m = test.tests.get("test19");
589
WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
590
}
591
592
for (int i = 0; i < 20000; i++) {
593
test20(array);
594
}
595
596
for (int i = 0; i < 20000; i++) {
597
test21(array);
598
}
599
600
if (!success) {
601
throw new RuntimeException("some tests failed");
602
}
603
}
604
}
605
606