• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 public class Main {
18 
19   /// CHECK-START: int Main.sieve(int) BCE (before)
20   /// CHECK: BoundsCheck
21   /// CHECK: ArraySet
22   /// CHECK: BoundsCheck
23   /// CHECK: ArrayGet
24   /// CHECK: BoundsCheck
25   /// CHECK: ArraySet
26 
27   /// CHECK-START: int Main.sieve(int) BCE (after)
28   /// CHECK-NOT: BoundsCheck
29   /// CHECK: ArraySet
30   /// CHECK-NOT: BoundsCheck
31   /// CHECK: ArrayGet
32   /// CHECK: BoundsCheck
33   /// CHECK: ArraySet
34 
sieve(int size)35   static int sieve(int size) {
36     int primeCount = 0;
37     boolean[] flags = new boolean[size + 1];
38     for (int i = 1; i < size; i++) flags[i] = true; // Can eliminate.
39     for (int i = 2; i < size; i++) {
40       if (flags[i]) { // Can eliminate.
41         primeCount++;
42         for (int k = i + 1; k <= size; k += i)
43           flags[k - 1] = false; // Can't eliminate yet due to (k+i) may overflow.
44       }
45     }
46     return primeCount;
47   }
48 
49 
50   /// CHECK-START: void Main.narrow(int[], int) BCE (before)
51   /// CHECK: BoundsCheck
52   /// CHECK: ArraySet
53   /// CHECK: BoundsCheck
54   /// CHECK: ArraySet
55   /// CHECK: BoundsCheck
56   /// CHECK: ArraySet
57 
58   /// CHECK-START: void Main.narrow(int[], int) BCE (after)
59   /// CHECK-NOT: BoundsCheck
60   /// CHECK: ArraySet
61   /// CHECK-NOT: BoundsCheck
62   /// CHECK: ArraySet
63   /// CHECK: BoundsCheck
64   /// CHECK: ArraySet
65   /// CHECK-NOT: BoundsCheck
66   /// CHECK: ArraySet
67   /// CHECK: BoundsCheck
68   /// CHECK: ArraySet
69 
narrow(int[] array, int offset)70   static void narrow(int[] array, int offset) {
71     if (offset < 0) {
72       return;
73     }
74     if (offset < array.length) {
75       // offset is in range [0, array.length-1].
76       // Bounds check can be eliminated.
77       array[offset] = 1;
78 
79       int biased_offset1 = offset + 1;
80       // biased_offset1 is in range [1, array.length].
81       if (biased_offset1 < array.length) {
82         // biased_offset1 is in range [1, array.length-1].
83         // Bounds check can be eliminated.
84         array[biased_offset1] = 1;
85       }
86 
87       int biased_offset2 = offset + 0x70000000;
88       // biased_offset2 is in range [0x70000000, array.length-1+0x70000000].
89       // It may overflow and be negative.
90       if (biased_offset2 < array.length) {
91         // Even with this test, biased_offset2 can be negative so we can't
92         // eliminate this bounds check.
93         array[biased_offset2] = 1;
94       }
95 
96       // offset_sub1 won't underflow since offset is no less than 0.
97       int offset_sub1 = offset - Integer.MAX_VALUE;
98       if (offset_sub1 >= 0) {
99         array[offset_sub1] = 1;  // Bounds check can be eliminated.
100       }
101 
102       // offset_sub2 can underflow.
103       int offset_sub2 = offset_sub1 - Integer.MAX_VALUE;
104       if (offset_sub2 >= 0) {
105         array[offset_sub2] = 1;  // Bounds check can't be eliminated.
106       }
107     }
108   }
109 
110 
111   /// CHECK-START: void Main.constantIndexing1(int[]) BCE (before)
112   /// CHECK: BoundsCheck
113   /// CHECK: ArraySet
114   /// CHECK: BoundsCheck
115   /// CHECK: ArraySet
116 
117   /// CHECK-START: void Main.constantIndexing1(int[]) BCE (after)
118   /// CHECK-NOT: Deoptimize
119   /// CHECK: BoundsCheck
120   /// CHECK: ArraySet
121   /// CHECK-NOT: BoundsCheck
122   /// CHECK: ArraySet
123 
constantIndexing1(int[] array)124   static void constantIndexing1(int[] array) {
125     // Decreasing order: bc for 5 but not for 4.
126     array[5] = 11;
127     array[4] = 11;
128   }
129 
130 
131   /// CHECK-START: void Main.$opt$noinline$constantIndexing2(int[]) BCE (before)
132   /// CHECK: BoundsCheck
133   /// CHECK: ArraySet
134   /// CHECK: BoundsCheck
135   /// CHECK: ArraySet
136   /// CHECK: BoundsCheck
137   /// CHECK: ArraySet
138   /// CHECK: BoundsCheck
139   /// CHECK: ArraySet
140 
141   /// CHECK-START: void Main.$opt$noinline$constantIndexing2(int[]) BCE (after)
142   /// CHECK: Deoptimize
143   /// CHECK-NOT: BoundsCheck
144   /// CHECK: ArraySet
145   /// CHECK-NOT: BoundsCheck
146   /// CHECK: ArraySet
147   /// CHECK-NOT: BoundsCheck
148   /// CHECK: ArraySet
149   /// CHECK-NOT: BoundsCheck
150   /// CHECK: ArraySet
151 
$opt$noinline$constantIndexing2(int[] array)152   static void $opt$noinline$constantIndexing2(int[] array) {
153     array[1] = 1;
154     array[2] = 1;
155     array[3] = 1;
156     array[4] = 1;
157     if (array[1] != 1) {
158       throw new Error("");
159     }
160   }
161 
162   /// CHECK-START: void Main.constantIndexing2b(int[]) BCE (before)
163   /// CHECK: BoundsCheck
164   /// CHECK: ArraySet
165   /// CHECK: BoundsCheck
166   /// CHECK: ArraySet
167   /// CHECK: BoundsCheck
168   /// CHECK: ArraySet
169   /// CHECK: BoundsCheck
170   /// CHECK: ArraySet
171   /// CHECK: BoundsCheck
172   /// CHECK: ArraySet
173 
174   /// CHECK-START: void Main.constantIndexing2b(int[]) BCE (after)
175   /// CHECK-NOT: Deoptimize
176   /// CHECK: BoundsCheck
177   /// CHECK: ArraySet
178   /// CHECK: BoundsCheck
179   /// CHECK: ArraySet
180   /// CHECK: BoundsCheck
181   /// CHECK: ArraySet
182   /// CHECK: BoundsCheck
183   /// CHECK: ArraySet
184   /// CHECK: BoundsCheck
185   /// CHECK: ArraySet
186 
constantIndexing2b(int[] array)187   static void constantIndexing2b(int[] array) {
188     array[0] = 6;
189     array[1] = 6;
190     array[2] = 6;
191     array[3] = 6;
192     array[-1] = 1;  // prevents the whole opt on [-1:4]
193   }
194 
195   /// CHECK-START: void Main.constantIndexing2c(int[]) BCE (before)
196   /// CHECK: BoundsCheck
197   /// CHECK: ArraySet
198   /// CHECK: BoundsCheck
199   /// CHECK: ArraySet
200   /// CHECK: BoundsCheck
201   /// CHECK: ArraySet
202   /// CHECK: BoundsCheck
203   /// CHECK: ArraySet
204 
205   /// CHECK-START: void Main.constantIndexing2c(int[]) BCE (after)
206   /// CHECK: Deoptimize
207   /// CHECK-NOT: BoundsCheck
208   /// CHECK: ArraySet
209   /// CHECK-NOT: BoundsCheck
210   /// CHECK: ArraySet
211   /// CHECK-NOT: BoundsCheck
212   /// CHECK: ArraySet
213   /// CHECK-NOT: BoundsCheck
214   /// CHECK: ArraySet
215 
constantIndexing2c(int[] array)216   static void constantIndexing2c(int[] array) {
217     array[0] = 7;
218     array[1] = 7;
219     array[2] = 7;
220     array[3] = 7;
221   }
222 
223   /// CHECK-START: int[] Main.constantIndexing3(int[], int[], boolean) BCE (before)
224   /// CHECK: BoundsCheck
225   /// CHECK: ArrayGet
226   /// CHECK: BoundsCheck
227   /// CHECK: ArraySet
228   /// CHECK: BoundsCheck
229   /// CHECK: ArrayGet
230   /// CHECK: BoundsCheck
231   /// CHECK: ArraySet
232   /// CHECK: BoundsCheck
233   /// CHECK: ArrayGet
234   /// CHECK: BoundsCheck
235   /// CHECK: ArraySet
236   /// CHECK: BoundsCheck
237   /// CHECK: ArrayGet
238   /// CHECK: BoundsCheck
239   /// CHECK: ArraySet
240 
241   /// CHECK-START: int[] Main.constantIndexing3(int[], int[], boolean) BCE (after)
242   /// CHECK: Deoptimize
243   /// CHECK-NOT: BoundsCheck
244   /// CHECK: ArrayGet
245   /// CHECK: Deoptimize
246   /// CHECK-NOT: BoundsCheck
247   /// CHECK: ArraySet
248   /// CHECK-NOT: BoundsCheck
249   /// CHECK: ArrayGet
250   /// CHECK-NOT: BoundsCheck
251   /// CHECK: ArraySet
252   /// CHECK-NOT: BoundsCheck
253   /// CHECK: ArrayGet
254   /// CHECK-NOT: BoundsCheck
255   /// CHECK: ArraySet
256   /// CHECK-NOT: BoundsCheck
257   /// CHECK: ArrayGet
258   /// CHECK-NOT: BoundsCheck
259   /// CHECK: ArraySet
260 
constantIndexing3(int[] array1, int[] array2, boolean copy)261   static int[] constantIndexing3(int[] array1, int[] array2, boolean copy) {
262     if (!copy) {
263       return array1;
264     }
265     array2[0] = array1[0];
266     array2[1] = array1[1];
267     array2[2] = array1[2];
268     array2[3] = array1[3];
269     return array2;
270   }
271 
272 
273   /// CHECK-START: void Main.constantIndexing4(int[]) BCE (before)
274   /// CHECK: BoundsCheck
275   /// CHECK: ArraySet
276 
277   /// CHECK-START: void Main.constantIndexing4(int[]) BCE (after)
278   /// CHECK-NOT: Deoptimize
279   /// CHECK: BoundsCheck
280   /// CHECK: ArraySet
281 
282   // There is only one array access. It's not beneficial
283   // to create a compare with deoptimization instruction.
constantIndexing4(int[] array)284   static void constantIndexing4(int[] array) {
285     array[0] = -1;
286   }
287 
288 
289   /// CHECK-START: void Main.constantIndexing5(int[]) BCE (before)
290   /// CHECK: BoundsCheck
291   /// CHECK: ArraySet
292   /// CHECK: BoundsCheck
293   /// CHECK: ArraySet
294 
295   /// CHECK-START: void Main.constantIndexing5(int[]) BCE (after)
296   /// CHECK-NOT: Deoptimize
297   /// CHECK: BoundsCheck
298   /// CHECK: ArraySet
299   /// CHECK: BoundsCheck
300   /// CHECK: ArraySet
301 
constantIndexing5(int[] array)302   static void constantIndexing5(int[] array) {
303     // We don't apply the deoptimization for very large constant index
304     // since it's likely to be an anomaly and will throw AIOOBE.
305     array[Integer.MAX_VALUE - 1000] = 1;
306     array[Integer.MAX_VALUE - 999] = 1;
307     array[Integer.MAX_VALUE - 998] = 1;
308   }
309 
310   /// CHECK-START: void Main.constantIndexing6(int[]) BCE (before)
311   /// CHECK: BoundsCheck
312   /// CHECK: ArraySet
313   /// CHECK: BoundsCheck
314   /// CHECK: ArraySet
315 
316   /// CHECK-START: void Main.constantIndexing6(int[]) BCE (after)
317   /// CHECK: Deoptimize
318   /// CHECK-NOT: BoundsCheck
319   /// CHECK: ArraySet
320   /// CHECK-NOT: BoundsCheck
321   /// CHECK: ArraySet
322 
constantIndexing6(int[] array)323   static void constantIndexing6(int[] array) {
324     array[3] = 111;
325     array[4] = 111;
326   }
327 
328   /// CHECK-START: void Main.constantIndexing7(int[], int) BCE (before)
329   /// CHECK: BoundsCheck
330   /// CHECK: ArraySet
331   /// CHECK: BoundsCheck
332   /// CHECK: ArraySet
333   /// CHECK: BoundsCheck
334   /// CHECK: ArraySet
335   /// CHECK: BoundsCheck
336   /// CHECK: ArraySet
337 
338   /// CHECK-START: void Main.constantIndexing7(int[], int) BCE (after)
339   /// CHECK: Deoptimize
340   /// CHECK: Deoptimize
341   /// CHECK-NOT: BoundsCheck
342   /// CHECK: ArraySet
343   /// CHECK-NOT: BoundsCheck
344   /// CHECK: ArraySet
345   /// CHECK-NOT: BoundsCheck
346   /// CHECK: ArraySet
347   /// CHECK-NOT: BoundsCheck
348   /// CHECK: ArraySet
349 
constantIndexing7(int[] array, int base)350   static void constantIndexing7(int[] array, int base) {
351     // With constant offsets to symbolic base.
352     array[base]     = 10;
353     array[base + 1] = 20;
354     array[base + 2] = 30;
355     array[base + 3] = 40;
356   }
357 
358   /// CHECK-START: void Main.constantIndexing8(int[], int) BCE (before)
359   /// CHECK: BoundsCheck
360   /// CHECK: ArraySet
361   /// CHECK: BoundsCheck
362   /// CHECK: ArraySet
363   /// CHECK: BoundsCheck
364   /// CHECK: ArraySet
365   /// CHECK: BoundsCheck
366   /// CHECK: ArraySet
367 
368   /// CHECK-START: void Main.constantIndexing8(int[], int) BCE (after)
369   /// CHECK: Deoptimize
370   /// CHECK: Deoptimize
371   /// CHECK-NOT: BoundsCheck
372   /// CHECK: ArraySet
373   /// CHECK-NOT: BoundsCheck
374   /// CHECK: ArraySet
375   /// CHECK-NOT: BoundsCheck
376   /// CHECK: ArraySet
377   /// CHECK-NOT: BoundsCheck
378   /// CHECK: ArraySet
379 
constantIndexing8(int[] array, int base)380   static void constantIndexing8(int[] array, int base) {
381     // With constant offsets "both ways" to symbolic base.
382     array[base - 1] = 100;
383     array[base]     = 200;
384     array[base + 1] = 300;
385     array[base + 2] = 400;
386   }
387 
388   /// CHECK-START: void Main.constantIndexing9(int[], int) BCE (before)
389   /// CHECK: BoundsCheck
390   /// CHECK: ArraySet
391   /// CHECK: BoundsCheck
392   /// CHECK: ArraySet
393   /// CHECK: BoundsCheck
394   /// CHECK: ArraySet
395   /// CHECK: BoundsCheck
396   /// CHECK: ArraySet
397 
398   /// CHECK-START: void Main.constantIndexing9(int[], int) BCE (after)
399   /// CHECK: Deoptimize
400   /// CHECK: Deoptimize
401   /// CHECK-NOT: BoundsCheck
402   /// CHECK: ArraySet
403   /// CHECK-NOT: BoundsCheck
404   /// CHECK: ArraySet
405   /// CHECK-NOT: BoundsCheck
406   /// CHECK: ArraySet
407   /// CHECK-NOT: BoundsCheck
408   /// CHECK: ArraySet
409   /// CHECK-NOT: BoundsCheck
410 
constantIndexing9(int[] array, int base)411   static void constantIndexing9(int[] array, int base) {
412     // Final range is base..base+3 so conditional
413     // references may be included in the end.
414     array[base] = 0;
415     if (base != 12345)
416       array[base + 2] = 2;
417     array[base + 3] = 3;
418     if (base != 67890)
419       array[base + 1] = 1;
420   }
421 
422   /// CHECK-START: void Main.constantIndexing10(int[], int) BCE (before)
423   /// CHECK: BoundsCheck
424   /// CHECK: ArraySet
425   /// CHECK: BoundsCheck
426   /// CHECK: ArraySet
427   /// CHECK: BoundsCheck
428   /// CHECK: ArraySet
429   /// CHECK: BoundsCheck
430   /// CHECK: ArraySet
431 
432   /// CHECK-START: void Main.constantIndexing10(int[], int) BCE (after)
433   /// CHECK: Deoptimize
434   /// CHECK: Deoptimize
435   /// CHECK-NOT: BoundsCheck
436   /// CHECK: ArraySet
437   /// CHECK-NOT: BoundsCheck
438   /// CHECK: ArraySet
439   /// CHECK-NOT: BoundsCheck
440   /// CHECK: ArraySet
441   /// CHECK-NOT: BoundsCheck
442   /// CHECK: ArraySet
443 
constantIndexing10(int[] array, int base)444   static void constantIndexing10(int[] array, int base) {
445     // Offset hidden in incremented base.
446     array[base] = 1;
447     array[++base] = 2;
448     array[++base] = 3;
449     array[++base] = 4;
450   }
451 
runAllConstantIndices()452   static void runAllConstantIndices() {
453     int[] a1 = { 0 };
454     int[] a6 = { 0, 0, 0, 0, 0, 0 };
455 
456     boolean caught = false;
457     try {
458       constantIndexing1(a1);
459     } catch (ArrayIndexOutOfBoundsException e) {
460       caught = true;
461     }
462     if (!caught) {
463       System.out.println("constant indices 1 failed!");
464     }
465 
466     constantIndexing1(a6);
467     if (a6[4] != 11 || a6[5] != 11) {
468       System.out.println("constant indices 1 failed!");
469     }
470 
471     $opt$noinline$constantIndexing2(a6);
472     if (a6[0] != 0 || a6[1] != 1 || a6[2] != 1 ||
473         a6[3] != 1 || a6[4] != 1 || a6[5] != 11) {
474       System.out.println("constant indices 2 failed!");
475     }
476 
477     caught = false;
478     try {
479       constantIndexing2b(a6);
480     } catch (ArrayIndexOutOfBoundsException e) {
481       caught = true;
482     }
483     if (!caught || a6[0] != 6 || a6[1] != 6 || a6[2] != 6 ||
484                    a6[3] != 6 || a6[4] != 1 || a6[5] != 11) {
485       System.out.println("constant indices 2b failed!");
486     }
487 
488     caught = false;
489     try {
490       constantIndexing2c(a1);
491     } catch (ArrayIndexOutOfBoundsException e) {
492       caught = true;
493     }
494     if (!caught || a1[0] != 7) {
495       System.out.println("constant indices 2c failed!");
496     }
497 
498     constantIndexing2c(a6);
499     if (a6[0] != 7 || a6[1] != 7 || a6[2] != 7 ||
500         a6[3] != 7 || a6[4] != 1 || a6[5] != 11) {
501       System.out.println("constant indices 2c failed!");
502     }
503 
504     int[] b4 = new int[4];
505     constantIndexing3(a6, b4, true);
506     if (b4[0] != 7 || b4[1] != 7 || b4[2] != 7 || b4[3] != 7) {
507       System.out.println("constant indices 3 failed!");
508     }
509 
510     constantIndexing4(a1);
511     if (a1[0] != -1) {
512       System.out.println("constant indices 4 failed!");
513     }
514 
515     caught = false;
516     try {
517       constantIndexing5(a6);
518     } catch (ArrayIndexOutOfBoundsException e) {
519       caught = true;
520     }
521     if (!caught) {
522       System.out.println("constant indices 5 failed!");
523     }
524 
525     constantIndexing6(a6);
526     if (a6[0] != 7   || a6[1] != 7   || a6[2] != 7 ||
527         a6[3] != 111 || a6[4] != 111 || a6[5] != 11) {
528       System.out.println("constant indices 6 failed!");
529     }
530 
531     constantIndexing7(a6, 1);
532     if (a6[0] != 7  || a6[1] != 10 || a6[2] != 20 ||
533         a6[3] != 30 || a6[4] != 40 || a6[5] != 11) {
534       System.out.println("constant indices 7 failed!");
535     }
536 
537     caught = false;
538     try {
539       constantIndexing7(a6, 5);
540     } catch (ArrayIndexOutOfBoundsException e) {
541       caught = true;
542     }
543     if (!caught || a6[0] != 7  || a6[1] != 10 || a6[2] != 20 ||
544                    a6[3] != 30 || a6[4] != 40 || a6[5] != 10) {
545       System.out.println("constant indices 7 failed!");
546     }
547 
548     constantIndexing8(a6, 1);
549     if (a6[0] != 100 || a6[1] != 200 || a6[2] != 300 ||
550         a6[3] != 400 || a6[4] != 40  || a6[5] != 10) {
551       System.out.println("constant indices 8 failed!");
552     }
553 
554     caught = false;
555     try {
556       constantIndexing8(a6, 0);
557     } catch (ArrayIndexOutOfBoundsException e) {
558       caught = true;
559     }
560     if (!caught || a6[0] != 100) {
561       System.out.println("constant indices 8 failed!");
562     }
563 
564     constantIndexing9(a6, 0);
565     if (a6[0] != 0 || a6[1] != 1  || a6[2] != 2  ||
566         a6[3] != 3 || a6[4] != 40 || a6[5] != 10) {
567       System.out.println("constant indices 9 failed!");
568     }
569 
570     constantIndexing10(a6, 0);
571     if (a6[0] != 1 || a6[1] != 2  || a6[2] != 3  ||
572         a6[3] != 4 || a6[4] != 40 || a6[5] != 10) {
573       System.out.println("constant indices 10 failed!");
574     }
575   }
576 
577   // A helper into which the actual throwing function should be inlined.
constantIndexingForward6(int[] array)578   static void constantIndexingForward6(int[] array) {
579     assertIsManaged();
580     constantIndexing6(array);
581   }
582 
583   /// CHECK-START: void Main.loopPattern1(int[]) BCE (before)
584   /// CHECK: BoundsCheck
585   /// CHECK: ArraySet
586   /// CHECK: BoundsCheck
587   /// CHECK: ArraySet
588   /// CHECK: BoundsCheck
589   /// CHECK: ArraySet
590   /// CHECK: BoundsCheck
591   /// CHECK: ArraySet
592   /// CHECK: BoundsCheck
593   /// CHECK: ArraySet
594   /// CHECK: BoundsCheck
595   /// CHECK: ArraySet
596   /// CHECK: BoundsCheck
597   /// CHECK: ArraySet
598 
599   /// CHECK-START: void Main.loopPattern1(int[]) BCE (after)
600   /// CHECK-NOT: BoundsCheck
601   /// CHECK: ArraySet
602   /// CHECK-NOT: BoundsCheck
603   /// CHECK: ArraySet
604   /// CHECK-NOT: BoundsCheck
605   /// CHECK: ArraySet
606   /// CHECK: BoundsCheck
607   /// CHECK: ArraySet
608   /// CHECK: BoundsCheck
609   /// CHECK: ArraySet
610   /// CHECK: BoundsCheck
611   /// CHECK: ArraySet
612   /// CHECK-NOT: BoundsCheck
613   /// CHECK: ArraySet
614 
loopPattern1(int[] array)615   static void loopPattern1(int[] array) {
616     for (int i = 0; i < array.length; i++) {
617       array[i] = 1;  // Bounds check can be eliminated.
618     }
619 
620     for (int i = 1; i < array.length; i++) {
621       array[i] = 1;  // Bounds check can be eliminated.
622     }
623 
624     for (int i = 1; i < array.length - 1; i++) {
625       array[i] = 1;  // Bounds check can be eliminated.
626     }
627 
628     for (int i = -1; i < array.length; i++) {
629       array[i] = 1;  // Bounds check can't be eliminated.
630     }
631 
632     for (int i = 0; i <= array.length; i++) {
633       array[i] = 1;  // Bounds check can't be eliminated.
634     }
635 
636     for (int i = 0; i < array.length; i += 2) {
637       // We don't have any assumption on max array length yet.
638       // Bounds check can't be eliminated due to overflow concern.
639       array[i] = 1;
640     }
641 
642     for (int i = 1; i < array.length; i += 2) {
643       // Bounds check can be eliminated since i is odd so the last
644       // i that's less than array.length is at most (Integer.MAX_VALUE - 2).
645       array[i] = 1;
646     }
647   }
648 
649 
650   /// CHECK-START: void Main.loopPattern2(int[]) BCE (before)
651   /// CHECK: BoundsCheck
652   /// CHECK: ArraySet
653   /// CHECK: BoundsCheck
654   /// CHECK: ArraySet
655   /// CHECK: BoundsCheck
656   /// CHECK: ArraySet
657   /// CHECK: BoundsCheck
658   /// CHECK: ArraySet
659   /// CHECK: BoundsCheck
660   /// CHECK: ArraySet
661   /// CHECK: BoundsCheck
662   /// CHECK: ArraySet
663 
664   /// CHECK-START: void Main.loopPattern2(int[]) BCE (after)
665   /// CHECK-NOT: BoundsCheck
666   /// CHECK: ArraySet
667   /// CHECK-NOT: BoundsCheck
668   /// CHECK: ArraySet
669   /// CHECK-NOT: BoundsCheck
670   /// CHECK: ArraySet
671   /// CHECK: BoundsCheck
672   /// CHECK: ArraySet
673   /// CHECK: BoundsCheck
674   /// CHECK: ArraySet
675   /// CHECK-NOT: BoundsCheck
676   /// CHECK: ArraySet
677 
loopPattern2(int[] array)678   static void loopPattern2(int[] array) {
679     for (int i = array.length - 1; i >= 0; i--) {
680       array[i] = 1;  // Bounds check can be eliminated.
681     }
682 
683     for (int i = array.length; i > 0; i--) {
684       array[i - 1] = 1;  // Bounds check can be eliminated.
685     }
686 
687     for (int i = array.length - 1; i > 0; i--) {
688       array[i] = 1;  // Bounds check can be eliminated.
689     }
690 
691     for (int i = array.length; i >= 0; i--) {
692       array[i] = 1;  // Bounds check can't be eliminated.
693     }
694 
695     for (int i = array.length; i >= 0; i--) {
696       array[i - 1] = 1;  // Bounds check can't be eliminated.
697     }
698 
699     for (int i = array.length; i > 0; i -= 20) {
700       // For i >= 0, (i - 20 - 1) is guaranteed not to underflow.
701       array[i - 1] = 1;  // Bounds check can be eliminated.
702     }
703   }
704 
705 
706   /// CHECK-START: void Main.loopPattern3(int[]) BCE (before)
707   /// CHECK: BoundsCheck
708   /// CHECK: ArraySet
709 
710   /// CHECK-START: void Main.loopPattern3(int[]) BCE (after)
711   /// CHECK: BoundsCheck
712   /// CHECK: ArraySet
713 
loopPattern3(int[] array)714   static void loopPattern3(int[] array) {
715     java.util.Random random = new java.util.Random();
716     for (int i = 0; ; i++) {
717       if (random.nextInt() % 1000 == 0 && i < array.length) {
718         // Can't eliminate the bound check since not every i++ is
719         // matched with a array length check, so there is some chance that i
720         // overflows and is negative.
721         array[i] = 1;
722       }
723     }
724   }
725 
726 
727   /// CHECK-START: void Main.constantNewArray() BCE (before)
728   /// CHECK: BoundsCheck
729   /// CHECK: ArraySet
730   /// CHECK: BoundsCheck
731   /// CHECK: ArraySet
732   /// CHECK: BoundsCheck
733   /// CHECK: ArraySet
734   /// CHECK: BoundsCheck
735   /// CHECK: ArraySet
736   /// CHECK: BoundsCheck
737   /// CHECK: ArraySet
738 
739   /// CHECK-START: void Main.constantNewArray() BCE (after)
740   /// CHECK-NOT: BoundsCheck
741   /// CHECK: ArraySet
742   /// CHECK: BoundsCheck
743   /// CHECK: ArraySet
744   /// CHECK-NOT: BoundsCheck
745   /// CHECK: ArraySet
746   /// CHECK-NOT: BoundsCheck
747   /// CHECK: ArraySet
748   /// CHECK: BoundsCheck
749   /// CHECK: ArraySet
750 
constantNewArray()751   static void constantNewArray() {
752     int[] array = new int[10];
753     for (int i = 0; i < 10; i++) {
754       array[i] = 1;  // Bounds check can be eliminated.
755     }
756 
757     for (int i = 0; i <= 10; i++) {
758       array[i] = 1;  // Bounds check can't be eliminated.
759     }
760 
761     array[0] = 1;  // Bounds check can be eliminated.
762     array[9] = 1;  // Bounds check can be eliminated.
763     array[10] = 1; // Bounds check can't be eliminated.
764   }
765 
766 
readData()767   static byte readData() {
768     return 1;
769   }
770 
771   /// CHECK-START: void Main.circularBufferProducer() BCE (before)
772   /// CHECK: BoundsCheck
773   /// CHECK: ArraySet
774 
775   /// CHECK-START: void Main.circularBufferProducer() BCE (after)
776   /// CHECK-NOT: BoundsCheck
777   /// CHECK: ArraySet
778 
circularBufferProducer()779   static void circularBufferProducer() {
780     byte[] array = new byte[4096];
781     int i = 0;
782     while (true) {
783       array[i & (array.length - 1)] = readData();
784       i++;
785     }
786   }
787 
788 
789   /// CHECK-START: void Main.pyramid1(int[]) BCE (before)
790   /// CHECK: BoundsCheck
791   /// CHECK: ArraySet
792   /// CHECK: BoundsCheck
793   /// CHECK: ArraySet
794 
795   /// CHECK-START: void Main.pyramid1(int[]) BCE (after)
796   /// CHECK-NOT: BoundsCheck
797   /// CHECK: ArraySet
798   /// CHECK-NOT: BoundsCheck
799   /// CHECK: ArraySet
800 
801   // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
pyramid1(int[] array)802   static void pyramid1(int[] array) {
803     for (int i = 0; i < (array.length + 1) / 2; i++) {
804       array[i] = i;
805       array[array.length - 1 - i] = i;
806     }
807   }
808 
809 
810   /// CHECK-START: void Main.pyramid2(int[]) BCE (before)
811   /// CHECK: BoundsCheck
812   /// CHECK: ArraySet
813   /// CHECK: BoundsCheck
814   /// CHECK: ArraySet
815 
816   /// CHECK-START: void Main.pyramid2(int[]) BCE (after)
817   /// CHECK-NOT: BoundsCheck
818   /// CHECK: ArraySet
819   /// CHECK-NOT: BoundsCheck
820   /// CHECK: ArraySet
821 
822   // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
pyramid2(int[] array)823   static void pyramid2(int[] array) {
824     for (int i = 0; i < (array.length + 1) >> 1; i++) {
825       array[i] = i;
826       array[array.length - 1 - i] = i;
827     }
828   }
829 
830 
831   /// CHECK-START: void Main.pyramid3(int[]) BCE (before)
832   /// CHECK: BoundsCheck
833   /// CHECK: ArraySet
834   /// CHECK: BoundsCheck
835   /// CHECK: ArraySet
836 
837   /// CHECK-START: void Main.pyramid3(int[]) BCE (after)
838   /// CHECK-NOT: BoundsCheck
839   /// CHECK: ArraySet
840   /// CHECK-NOT: BoundsCheck
841   /// CHECK: ArraySet
842 
843   // Set array to something like {0, 1, 2, 3, 2, 1, 0}.
pyramid3(int[] array)844   static void pyramid3(int[] array) {
845     for (int i = 0; i < (array.length + 1) >>> 1; i++) {
846       array[i] = i;
847       array[array.length - 1 - i] = i;
848     }
849   }
850 
851 
852   /// CHECK-START: boolean Main.isPyramid(int[]) BCE (before)
853   /// CHECK: BoundsCheck
854   /// CHECK: ArrayGet
855   /// CHECK: BoundsCheck
856   /// CHECK: ArrayGet
857 
858   /// CHECK-START: boolean Main.isPyramid(int[]) BCE (after)
859   /// CHECK-NOT: BoundsCheck
860   /// CHECK: ArrayGet
861   /// CHECK-NOT: BoundsCheck
862   /// CHECK: ArrayGet
863 
isPyramid(int[] array)864   static boolean isPyramid(int[] array) {
865     int i = 0;
866     int j = array.length - 1;
867     while (i <= j) {
868       if (array[i] != i) {
869         return false;
870       }
871       if (array[j] != i) {
872         return false;
873       }
874       i++; j--;
875     }
876     return true;
877   }
878 
879 
880   /// CHECK-START: void Main.bubbleSort(int[]) GVN (before)
881   /// CHECK: BoundsCheck
882   /// CHECK: ArrayGet
883   /// CHECK: BoundsCheck
884   /// CHECK: ArrayGet
885   /// CHECK: BoundsCheck
886   /// CHECK: ArrayGet
887   /// CHECK: BoundsCheck
888   /// CHECK: ArrayGet
889   /// CHECK: BoundsCheck
890   /// CHECK: ArraySet
891   /// CHECK: BoundsCheck
892   /// CHECK: ArraySet
893 
894   /// CHECK-START: void Main.bubbleSort(int[]) GVN (after)
895   /// CHECK: BoundsCheck
896   /// CHECK: ArrayGet
897   /// CHECK: BoundsCheck
898   /// CHECK: ArrayGet
899   /// CHECK-NOT: ArrayGet
900   /// CHECK-NOT: ArrayGet
901   /// CHECK-NOT: BoundsCheck
902   /// CHECK: ArraySet
903   /// CHECK-NOT: BoundsCheck
904   /// CHECK: ArraySet
905 
906   /// CHECK-START: void Main.bubbleSort(int[]) BCE (after)
907   /// CHECK-NOT: BoundsCheck
908   /// CHECK: ArrayGet
909   /// CHECK-NOT: BoundsCheck
910   /// CHECK: ArrayGet
911   /// CHECK-NOT: ArrayGet
912   /// CHECK-NOT: ArrayGet
913   /// CHECK-NOT: BoundsCheck
914   /// CHECK: ArraySet
915   /// CHECK-NOT: BoundsCheck
916   /// CHECK: ArraySet
917 
bubbleSort(int[] array)918   static void bubbleSort(int[] array) {
919     for (int i = 0; i < array.length - 1; i++) {
920       for (int j = 0; j < array.length - i - 1; j++) {
921         if (array[j] > array[j + 1]) {
922           int temp = array[j + 1];
923           array[j + 1] = array[j];
924           array[j] = temp;
925         }
926       }
927     }
928   }
929 
930   /// CHECK-START: void Main.nonzeroLength(int[]) BCE (before)
931   /// CHECK-DAG: BoundsCheck
932   //
933   /// CHECK-START: void Main.nonzeroLength(int[]) BCE (after)
934   /// CHECK-NOT: BoundsCheck
935   /// CHECK-NOT: Deoptimize
nonzeroLength(int[] a)936   public static void nonzeroLength(int[] a) {
937     if (a.length != 0) {
938       a[0] = 112;
939     }
940   }
941 
942   /// CHECK-START: void Main.knownLength(int[]) BCE (before)
943   /// CHECK-DAG: BoundsCheck
944   /// CHECK-DAG: BoundsCheck
945   //
946   /// CHECK-START: void Main.knownLength(int[]) BCE (after)
947   /// CHECK-NOT: BoundsCheck
948   /// CHECK-NOT: Deoptimize
knownLength(int[] a)949   public static void knownLength(int[] a) {
950     if (a.length == 2) {
951       a[0] = -1;
952       a[1] = -2;
953     }
954   }
955 
956   static int[][] mA;
957 
958   /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (before)
959   //  Array references mA[i] and ..[j] both in inner loop.
960   /// CHECK-DAG:  <<Get1:l\d+>>  ArrayGet [<<Array1:l\d+>>,<<Bounds1:i\d+>>] loop:<<InnerLoop:B\d+>>
961   /// CHECK-DAG:  <<Array1>>     NullCheck [<<Field1:l\d+>>]                 loop:<<InnerLoop>>
962   /// CHECK-DAG:  <<Len1:i\d+>>  ArrayLength [<<Array1>>]                    loop:<<InnerLoop>>
963   /// CHECK-DAG:  <<Bounds1>>    BoundsCheck [<<Index1:i\d+>>,<<Len1>>]      loop:<<InnerLoop>>
964   /// CHECK-DAG:  <<Get2:i\d+>>  ArrayGet [<<Array2:l\d+>>,<<Bounds2:i\d+>>] loop:<<InnerLoop>>
965   /// CHECK-DAG:  <<Array2>>     NullCheck [<<Get1>>]                        loop:<<InnerLoop>>
966   /// CHECK-DAG:  <<Len2:i\d+>>  ArrayLength [<<Array2>>]                    loop:<<InnerLoop>>
967   /// CHECK-DAG:  <<Bounds2>>    BoundsCheck [<<Index2:i\d+>>,<<Len2>>]      loop:<<InnerLoop>>
968   // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
969   /// CHECK-DAG:                 InvokeStaticOrDirect [<<Get2>>{{(,[ij]\d+)?}}] loop:<<InnerLoop>>
970   /// CHECK-DAG:  <<Index2>>     Phi                                         loop:<<InnerLoop>>
971   /// CHECK-DAG:  <<Index1>>     Phi                                         loop:<<OuterLoop:B\d+>>
972   /// CHECK-DAG:  <<Field1>>     StaticFieldGet                              loop:none
973   /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
974   //
975   /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (after)
976   //  Array reference mA[i] hoisted to same level as deopt.
977   /// CHECK-DAG:                 Deoptimize                                  loop:<<OuterLoop:B\d+>>
978   /// CHECK-DAG:                 ArrayLength                                 loop:<<OuterLoop>>
979   /// CHECK-DAG:  <<Get1:l\d+>>  ArrayGet [<<Array1:l\d+>>,<<Index1:i\d+>>]  loop:<<OuterLoop>>
980   //  Array reference ..[j] still in inner loop, with a direct index.
981   /// CHECK-DAG:  <<Get2:i\d+>>  ArrayGet [<<Array2:l\d+>>,<<Index2:i\d+>>]  loop:<<InnerLoop:B\d+>>
982   // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
983   /// CHECK-DAG:                 InvokeStaticOrDirect [<<Get2>>{{(,[ij]\d+)?}}] loop:<<InnerLoop>>
984   /// CHECK-DAG:  <<Index2>>     Phi                                         loop:<<InnerLoop>>
985   /// CHECK-DAG:  <<Index1>>     Phi                                         loop:<<OuterLoop>>
986   //  Synthetic phi.
987   /// CHECK-DAG:  <<Array2>>     Phi                                         loop:<<OuterLoop>>
988   /// CHECK-DAG:  <<Array1>>     StaticFieldGet                              loop:none
989   /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
990   //
991   /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (after)
992   /// CHECK-NOT: NullCheck
993   /// CHECK-NOT: BoundsCheck
dynamicBCEAndIntrinsic(int n)994   static void dynamicBCEAndIntrinsic(int n) {
995     for (int i = 0; i < n; i++) {
996       for (int j = 0; j < n; j++) {
997         // Since intrinsic call cannot modify fields or arrays,
998         // dynamic BCE and hoisting can be applied to the inner loop.
999         mA[i][j] = Math.abs(mA[i][j]);
1000       }
1001     }
1002   }
1003 
foo()1004   static int foo() {
1005     try {
1006       assertIsManaged();
1007       // This will cause AIOOBE.
1008       $opt$noinline$constantIndexing2(new int[3]);
1009     } catch (ArrayIndexOutOfBoundsException e) {
1010       assertIsManaged();  // This is to ensure that single-frame deoptimization works.
1011                           // Will need to be updated if $opt$noinline$constantIndexing2 is inlined.
1012       try {
1013         // This will cause AIOOBE.
1014         constantIndexingForward6(new int[3]);
1015       } catch (ArrayIndexOutOfBoundsException e2) {
1016         // Having deopted, we expect to be running interpreted at this point.
1017         // Does not apply to debuggable, however, since we do not inline.
1018         return 99;
1019       }
1020     }
1021     return 0;
1022   }
1023 
1024 
1025   int sum;
1026 
1027   /// CHECK-START: void Main.foo1(int[], int, int, boolean) BCE (before)
1028   /// CHECK: BoundsCheck
1029   /// CHECK: ArraySet
1030   /// CHECK-NOT: BoundsCheck
1031   /// CHECK: ArrayGet
1032 
1033   /// CHECK-START: void Main.foo1(int[], int, int, boolean) BCE (after)
1034   /// CHECK: Phi
1035   /// CHECK-NOT: BoundsCheck
1036   /// CHECK: ArraySet
1037   /// CHECK-NOT: BoundsCheck
1038   /// CHECK: ArrayGet
1039   //  Added blocks at end for deoptimization.
1040   /// CHECK: Exit
1041   /// CHECK: If
1042   /// CHECK: Deoptimize
1043   /// CHECK: Deoptimize
1044   /// CHECK: Deoptimize
1045   /// CHECK-NOT: Deoptimize
1046   /// CHECK: Goto
1047   /// CHECK: Goto
1048   /// CHECK: Goto
1049 
foo1(int[] array, int start, int end, boolean expectInterpreter)1050   void foo1(int[] array, int start, int end, boolean expectInterpreter) {
1051     if (end < 0)
1052       throw new Error("");
1053     // Three HDeoptimize will be added. Two for the index
1054     // and one for null check on array (to hoist null
1055     // check and array.length out of loop).
1056     for (int i = start ; i < end; i++) {
1057       if (expectInterpreter) {
1058         assertIsInterpreted();
1059       } else {
1060         assertIsManaged();
1061       }
1062       array[i] = 1;
1063       sum += array[i];
1064     }
1065   }
1066 
1067 
1068   /// CHECK-START: void Main.foo2(int[], int, int, boolean) BCE (before)
1069   /// CHECK: BoundsCheck
1070   /// CHECK: ArraySet
1071   /// CHECK-NOT: BoundsCheck
1072   /// CHECK: ArrayGet
1073   /// CHECK-START: void Main.foo2(int[], int, int, boolean) BCE (after)
1074   /// CHECK: Phi
1075   /// CHECK-NOT: BoundsCheck
1076   /// CHECK: ArraySet
1077   /// CHECK-NOT: BoundsCheck
1078   /// CHECK: ArrayGet
1079   //  Added blocks at end for deoptimization.
1080   /// CHECK: Exit
1081   /// CHECK: If
1082   /// CHECK: Deoptimize
1083   /// CHECK: Deoptimize
1084   /// CHECK: Deoptimize
1085   /// CHECK-NOT: Deoptimize
1086   /// CHECK: Goto
1087   /// CHECK: Goto
1088   /// CHECK: Goto
1089 
foo2(int[] array, int start, int end, boolean expectInterpreter)1090   void foo2(int[] array, int start, int end, boolean expectInterpreter) {
1091     if (end < 0)
1092       throw new Error("");
1093     // Three HDeoptimize will be added. Two for the index
1094     // and one for null check on array (to hoist null
1095     // check and array.length out of loop).
1096     for (int i = start ; i <= end; i++) {
1097       if (expectInterpreter) {
1098         assertIsInterpreted();
1099       } else {
1100         assertIsManaged();
1101       }
1102       array[i] = 1;
1103       sum += array[i];
1104     }
1105   }
1106 
1107 
1108   /// CHECK-START: void Main.foo3(int[], int, boolean) BCE (before)
1109   /// CHECK: BoundsCheck
1110   /// CHECK: ArraySet
1111   /// CHECK-NOT: BoundsCheck
1112   /// CHECK: ArrayGet
1113   /// CHECK-START: void Main.foo3(int[], int, boolean) BCE (after)
1114   /// CHECK: Phi
1115   /// CHECK-NOT: BoundsCheck
1116   /// CHECK: ArraySet
1117   /// CHECK-NOT: BoundsCheck
1118   /// CHECK: ArrayGet
1119   //  Added blocks at end for deoptimization.
1120   /// CHECK: Exit
1121   /// CHECK: If
1122   /// CHECK: Deoptimize
1123   /// CHECK: Deoptimize
1124   /// CHECK: Deoptimize
1125   /// CHECK-NOT: Deoptimize
1126   /// CHECK: Goto
1127   /// CHECK: Goto
1128   /// CHECK: Goto
1129 
foo3(int[] array, int end, boolean expectInterpreter)1130   void foo3(int[] array, int end, boolean expectInterpreter) {
1131     if (end < 0)
1132       throw new Error("");
1133     // Three HDeoptimize will be added. Two for the index
1134     // and one for null check on array (to hoist null check
1135     // and array.length out of loop).
1136     for (int i = 3 ; i <= end; i++) {
1137       if (expectInterpreter) {
1138         assertIsInterpreted();
1139       } else {
1140         assertIsManaged();
1141       }
1142       array[i] = 1;
1143       sum += array[i];
1144     }
1145   }
1146 
1147 
1148   /// CHECK-START: void Main.foo4(int[], int, boolean) BCE (before)
1149   /// CHECK: BoundsCheck
1150   /// CHECK: ArraySet
1151   /// CHECK-NOT: BoundsCheck
1152   /// CHECK: ArrayGet
1153 
1154   /// CHECK-START: void Main.foo4(int[], int, boolean) BCE (after)
1155   /// CHECK: Phi
1156   /// CHECK-NOT: BoundsCheck
1157   /// CHECK: ArraySet
1158   /// CHECK-NOT: BoundsCheck
1159   /// CHECK: ArrayGet
1160   //  Added blocks at end for deoptimization.
1161   /// CHECK: Exit
1162   /// CHECK: If
1163   /// CHECK: Deoptimize
1164   /// CHECK: Deoptimize
1165   /// CHECK: Deoptimize
1166   /// CHECK-NOT: Deoptimize
1167   /// CHECK: Goto
1168   /// CHECK: Goto
1169   /// CHECK: Goto
1170 
foo4(int[] array, int end, boolean expectInterpreter)1171   void foo4(int[] array, int end, boolean expectInterpreter) {
1172     if (end < 0)
1173       throw new Error("");
1174     // Three HDeoptimize will be added. Two for the index
1175     // and one for null check on array (to hoist null check
1176     // and array.length out of loop).
1177     for (int i = end ; i > 0; i--) {
1178       if (expectInterpreter) {
1179         assertIsInterpreted();
1180       } else {
1181         assertIsManaged();
1182       }
1183       array[i - 1] = 1;
1184       sum += array[i - 1];
1185     }
1186   }
1187 
1188 
1189   /// CHECK-START: void Main.foo5(int[], int, boolean) BCE (before)
1190   /// CHECK: BoundsCheck
1191   /// CHECK: ArraySet
1192   /// CHECK: BoundsCheck
1193   /// CHECK: ArrayGet
1194   /// CHECK: BoundsCheck
1195   /// CHECK: ArrayGet
1196   /// CHECK: BoundsCheck
1197   /// CHECK: ArrayGet
1198 
1199   /// CHECK-START: void Main.foo5(int[], int, boolean) BCE (after)
1200   /// CHECK-NOT: BoundsCheck
1201   /// CHECK: ArraySet
1202   /// CHECK: Phi
1203   /// CHECK-NOT: BoundsCheck
1204   /// CHECK: ArrayGet
1205   /// CHECK-NOT: BoundsCheck
1206   /// CHECK: ArrayGet
1207   /// CHECK-NOT: BoundsCheck
1208   /// CHECK: ArrayGet
1209   //  Added blocks at end for deoptimization.
1210   /// CHECK: Exit
1211   /// CHECK: If
1212   /// CHECK: Deoptimize
1213   /// CHECK: Deoptimize
1214   /// CHECK: Deoptimize
1215   /// CHECK-NOT: Deoptimize
1216   /// CHECK: Goto
1217   /// CHECK: Goto
1218   /// CHECK: Goto
1219 
foo5(int[] array, int end, boolean expectInterpreter)1220   void foo5(int[] array, int end, boolean expectInterpreter) {
1221     if (end < 0)
1222       throw new Error("");
1223     // Bounds check in this loop can be eliminated without deoptimization.
1224     for (int i = array.length - 1 ; i >= 0; i--) {
1225       array[i] = 1;
1226     }
1227     // Three HDeoptimize will be added for the bounds.
1228     // The null check is not necessary.
1229     for (int i = end - 2 ; i > 0; i--) {
1230       if (expectInterpreter) {
1231         assertIsInterpreted();
1232       } else {
1233         assertIsManaged();
1234       }
1235       sum += array[i - 1];
1236       sum += array[i];
1237       sum += array[i + 1];
1238     }
1239   }
1240 
1241 
1242   /// CHECK-START: void Main.foo6(int[], int, int, boolean) BCE (before)
1243   /// CHECK: BoundsCheck
1244   /// CHECK: ArrayGet
1245   /// CHECK: BoundsCheck
1246   /// CHECK: ArrayGet
1247   /// CHECK: BoundsCheck
1248   /// CHECK: ArrayGet
1249   /// CHECK: BoundsCheck
1250   /// CHECK: ArrayGet
1251   /// CHECK: BoundsCheck
1252   /// CHECK: ArrayGet
1253   /// CHECK-NOT: BoundsCheck
1254   /// CHECK: ArraySet
1255   /// CHECK-START: void Main.foo6(int[], int, int, boolean) BCE (after)
1256   /// CHECK: Phi
1257   /// CHECK-NOT: BoundsCheck
1258   /// CHECK: ArrayGet
1259   /// CHECK-NOT: BoundsCheck
1260   /// CHECK: ArrayGet
1261   /// CHECK-NOT: BoundsCheck
1262   /// CHECK: ArrayGet
1263   /// CHECK-NOT: BoundsCheck
1264   /// CHECK: ArrayGet
1265   /// CHECK-NOT: BoundsCheck
1266   /// CHECK: ArrayGet
1267   /// CHECK-NOT: BoundsCheck
1268   /// CHECK: ArraySet
1269   //  Added blocks at end for deoptimization.
1270   /// CHECK: Exit
1271   /// CHECK: If
1272   /// CHECK: Deoptimize
1273   /// CHECK: Deoptimize
1274   /// CHECK: Deoptimize
1275   /// CHECK: Deoptimize
1276   /// CHECK-NOT: Deoptimize
1277   /// CHECK: Goto
1278   /// CHECK: Goto
1279   /// CHECK: Goto
1280 
foo6(int[] array, int start, int end, boolean expectInterpreter)1281   void foo6(int[] array, int start, int end, boolean expectInterpreter) {
1282     if (end < 0)
1283       throw new Error("");
1284     for (int i = end; i >= start; i--) {
1285       if (expectInterpreter) {
1286         assertIsInterpreted();
1287       } else {
1288         assertIsManaged();
1289       }
1290       array[i] = (array[i-2] + array[i-1] + array[i] + array[i+1] + array[i+2]) / 5;
1291     }
1292   }
1293 
1294 
1295   /// CHECK-START: void Main.foo7(int[], int, int, boolean) BCE (before)
1296   /// CHECK: BoundsCheck
1297   /// CHECK: ArrayGet
1298   /// CHECK: BoundsCheck
1299   /// CHECK: ArrayGet
1300 
1301   /// CHECK-START: void Main.foo7(int[], int, int, boolean) BCE (after)
1302   /// CHECK: Phi
1303   /// CHECK: BoundsCheck
1304   /// CHECK: ArrayGet
1305   /// CHECK-NOT: BoundsCheck
1306   /// CHECK: ArrayGet
1307   //  Added blocks at end for deoptimization.
1308   /// CHECK: Exit
1309   /// CHECK: If
1310   /// CHECK: Deoptimize
1311   /// CHECK: Deoptimize
1312   /// CHECK: Deoptimize
1313   /// CHECK-NOT: Deoptimize
1314   /// CHECK: Goto
1315   /// CHECK: Goto
1316   /// CHECK: Goto
1317 
foo7(int[] array, int start, int end, boolean lowEnd)1318   void foo7(int[] array, int start, int end, boolean lowEnd) {
1319     // Three HDeoptimize will be added. One for the index
1320     // and one for null check on array (to hoist null
1321     // check and array.length out of loop).
1322     for (int i = start ; i < end; i++) {
1323       if (lowEnd) {
1324         // This array access isn't certain. So we don't
1325         // use +1000 offset in decision making for deoptimization
1326         // conditions.
1327         sum += array[i + 1000];
1328       }
1329       sum += array[i];
1330     }
1331   }
1332 
1333 
1334   /// CHECK-START: void Main.foo8(int[][], int, int) BCE (before)
1335   /// CHECK: BoundsCheck
1336   /// CHECK: ArrayGet
1337   /// CHECK: BoundsCheck
1338   /// CHECK: ArraySet
1339 
1340   /// CHECK-START: void Main.foo8(int[][], int, int) BCE (after)
1341   /// CHECK: Phi
1342   /// CHECK-NOT: BoundsCheck
1343   /// CHECK: ArrayGet
1344   /// CHECK: Phi
1345   /// CHECK-NOT: BoundsCheck
1346   /// CHECK: ArraySet
1347   //  Added blocks at end for deoptimization.
1348   /// CHECK: Exit
1349   /// CHECK: If
1350   /// CHECK: Deoptimize
1351   /// CHECK: Deoptimize
1352   /// CHECK: Deoptimize
1353   /// CHECK: Goto
1354   /// CHECK: Goto
1355   /// CHECK: Goto
1356   /// CHECK: If
1357   /// CHECK: Deoptimize
1358   /// CHECK: Deoptimize
1359   /// CHECK: Deoptimize
1360   /// CHECK-NOT: Deoptimize
1361   /// CHECK: Goto
1362   /// CHECK: Goto
1363   /// CHECK: Goto
1364 
foo8(int[][] matrix, int start, int end)1365   void foo8(int[][] matrix, int start, int end) {
1366     // Three HDeoptimize will be added for the outer loop,
1367     // two for the index, and null check on matrix. Same
1368     // for the inner loop.
1369     for (int i = start; i < end; i++) {
1370       int[] row = matrix[i];
1371       for (int j = start; j < end; j++) {
1372         row[j] = 1;
1373       }
1374     }
1375   }
1376 
1377 
1378   /// CHECK-START: void Main.foo9(int[], boolean) BCE (before)
1379   /// CHECK: NullCheck
1380   /// CHECK: BoundsCheck
1381   /// CHECK: ArrayGet
1382 
1383   /// CHECK-START: void Main.foo9(int[], boolean) BCE (after)
1384   //  The loop is guaranteed to be entered. No need to transform the
1385   //  loop for loop body entry test.
1386   /// CHECK: Deoptimize
1387   /// CHECK: Deoptimize
1388   /// CHECK: Deoptimize
1389   /// CHECK-NOT: Deoptimize
1390   /// CHECK: Phi
1391   /// CHECK-NOT: NullCheck
1392   /// CHECK-NOT: BoundsCheck
1393   /// CHECK: ArrayGet
1394 
1395   /// CHECK-START: void Main.foo9(int[], boolean) instruction_simplifier$after_bce (after)
1396   //  Simplification removes the redundant check
1397   /// CHECK: Deoptimize
1398   /// CHECK: Deoptimize
1399   /// CHECK-NOT: Deoptimize
1400 
foo9(int[] array, boolean expectInterpreter)1401   void foo9(int[] array, boolean expectInterpreter) {
1402     // Three HDeoptimize will be added. Two for the index and one for null check on array. Then
1403     // simplification removes one redundant HDeoptimize.
1404     for (int i = 0 ; i < 10; i++) {
1405       if (expectInterpreter) {
1406         assertIsInterpreted();
1407       } else {
1408         assertIsManaged();
1409       }
1410       sum += array[i];
1411     }
1412   }
1413 
1414 
1415   /// CHECK-START: void Main.partialLooping(int[], int, int) BCE (before)
1416   /// CHECK: BoundsCheck
1417   /// CHECK: ArraySet
1418 
1419   /// CHECK-START: void Main.partialLooping(int[], int, int) BCE (after)
1420   /// CHECK-NOT: Deoptimize
1421   /// CHECK: BoundsCheck
1422   /// CHECK: ArraySet
1423 
partialLooping(int[] array, int start, int end)1424   void partialLooping(int[] array, int start, int end) {
1425     // This loop doesn't cover the full range of [start, end) so
1426     // adding deoptimization is too aggressive, since end can be
1427     // greater than array.length but the loop is never going to work on
1428     // more than 2 elements.
1429     for (int i = start; i < end; i++) {
1430       if (i == 2) {
1431         return;
1432       }
1433       array[i] = 1;
1434     }
1435   }
1436 
1437 
testUnknownBounds()1438   static void testUnknownBounds() {
1439     boolean caught = false;
1440 
1441     runAllConstantIndices();
1442 
1443     Main main = new Main();
1444     main.foo1(new int[10], 0, 10, false);
1445     if (main.sum != 10) {
1446       System.out.println("foo1 failed!");
1447     }
1448 
1449     caught = false;
1450     main = new Main();
1451     try {
1452       main.foo1(new int[10], 0, 11, true);
1453     } catch (ArrayIndexOutOfBoundsException e) {
1454       caught = true;
1455     }
1456     if (!caught || main.sum != 10) {
1457       System.out.println("foo1 exception failed!");
1458     }
1459 
1460     main = new Main();
1461     main.foo2(new int[10], 0, 9, false);
1462     if (main.sum != 10) {
1463       System.out.println("foo2 failed!");
1464     }
1465 
1466     caught = false;
1467     main = new Main();
1468     try {
1469       main.foo2(new int[10], 0, 10, true);
1470     } catch (ArrayIndexOutOfBoundsException e) {
1471       caught = true;
1472     }
1473     if (!caught || main.sum != 10) {
1474       System.out.println("foo2 exception failed!");
1475     }
1476 
1477     main = new Main();
1478     main.foo3(new int[10], 9, false);
1479     if (main.sum != 7) {
1480       System.out.println("foo3 failed!");
1481     }
1482 
1483     caught = false;
1484     main = new Main();
1485     try {
1486       main.foo3(new int[10], 10, true);
1487     } catch (ArrayIndexOutOfBoundsException e) {
1488       caught = true;
1489     }
1490     if (!caught || main.sum != 7) {
1491       System.out.println("foo3 exception failed!");
1492     }
1493 
1494     main = new Main();
1495     main.foo4(new int[10], 10, false);
1496     if (main.sum != 10) {
1497       System.out.println("foo4 failed!");
1498     }
1499 
1500     caught = false;
1501     main = new Main();
1502     try {
1503       main.foo4(new int[10], 11, true);
1504     } catch (ArrayIndexOutOfBoundsException e) {
1505       caught = true;
1506     }
1507     if (!caught || main.sum != 0) {
1508       System.out.println("foo4 exception failed!");
1509     }
1510 
1511     main = new Main();
1512     main.foo5(new int[10], 10, false);
1513     if (main.sum != 24) {
1514       System.out.println("foo5 failed!");
1515     }
1516 
1517     caught = false;
1518     main = new Main();
1519     try {
1520       main.foo5(new int[10], 11, true);
1521     } catch (ArrayIndexOutOfBoundsException e) {
1522       caught = true;
1523     }
1524     if (!caught || main.sum != 2) {
1525       System.out.println("foo5 exception failed!");
1526     }
1527 
1528     main = new Main();
1529     main.foo6(new int[10], 2, 7, false);
1530 
1531     main = new Main();
1532     int[] array9 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
1533     main.foo9(array9, false);
1534     if (main.sum != 45) {
1535       System.out.println("foo9 failed!");
1536     }
1537 
1538     main = new Main();
1539     int[] array = new int[4];
1540     main.partialLooping(new int[3], 0, 4);
1541     if ((array[0] != 1) && (array[1] != 1) &&
1542         (array[2] != 0) && (array[3] != 0)) {
1543       System.out.println("partialLooping failed!");
1544     }
1545 
1546     caught = false;
1547     main = new Main();
1548     try {
1549       main.foo6(new int[10], 2, 8, true);
1550     } catch (ArrayIndexOutOfBoundsException e) {
1551       caught = true;
1552     }
1553     if (!caught) {
1554       System.out.println("foo6 exception failed!");
1555     }
1556 
1557     caught = false;
1558     main = new Main();
1559     try {
1560       main.foo6(new int[10], 1, 7, true);
1561     } catch (ArrayIndexOutOfBoundsException e) {
1562       caught = true;
1563     }
1564     if (!caught) {
1565       System.out.println("foo6 exception failed!");
1566     }
1567 
1568   }
1569 
testExceptionMessage()1570   public void testExceptionMessage() {
1571     short[] B1 = new short[5];
1572     int[] B2 = new int[5];
1573     Exception err = null;
1574     try {
1575       testExceptionMessage1(B1, B2, null, -1, 6);
1576     } catch (Exception e) {
1577       err = e;
1578     }
1579     System.out.println(err);
1580   }
1581 
testExceptionMessage1(short[] a1, int[] a2, long a3[], int start, int finish)1582   void testExceptionMessage1(short[] a1, int[] a2, long a3[], int start, int finish) {
1583     int j = finish + 77;
1584     // Bug: 22665511
1585     // A deoptimization will be triggered here right before the loop. Need to make
1586     // sure the value of j is preserved for the interpreter.
1587     for (int i = start; i <= finish; i++) {
1588       a2[j - 1] = a1[i + 1];
1589     }
1590   }
1591 
1592   // Make sure this method is compiled with optimizing.
1593   /// CHECK-START: void Main.main(java.lang.String[]) register (after)
1594   /// CHECK: ParallelMove
1595 
main(String[] args)1596   public static void main(String[] args) {
1597     System.loadLibrary(args[0]);
1598 
1599     if (!compiledWithOptimizing() ||
1600         !hasOatFile() ||
1601         runtimeIsSoftFail() ||
1602         isInterpreted()) {
1603       disableStackFrameAsserts();
1604     }
1605 
1606     sieve(20);
1607 
1608     int[] array = {5, 2, 3, 7, 0, 1, 6, 4};
1609     bubbleSort(array);
1610     for (int i = 0; i < 8; i++) {
1611       if (array[i] != i) {
1612         System.out.println("bubble sort failed!");
1613       }
1614     }
1615 
1616     nonzeroLength(array);
1617     if (array[0] != 112) {
1618       System.out.println("nonzero length failed!");
1619     }
1620 
1621     knownLength(array);
1622     if (array[0] != 112 || array[1] != 1) {
1623       System.out.println("nonzero length failed!");
1624     }
1625     array = new int[2];
1626     knownLength(array);
1627     if (array[0] != -1 || array[1] != -2) {
1628       System.out.println("nonzero length failed!");
1629     }
1630 
1631     // Zero length array does not break.
1632     array = new int[0];
1633     nonzeroLength(array);
1634     knownLength(array);
1635 
1636     mA = new int[4][4];
1637     for (int i = 0; i < 4; i++) {
1638       for (int j = 0; j < 4; j++) {
1639         mA[i][j] = -1;
1640       }
1641     }
1642     dynamicBCEAndIntrinsic(4);
1643     for (int i = 0; i < 4; i++) {
1644       for (int j = 0; j < 4; j++) {
1645         if (mA[i][i] != 1) {
1646           System.out.println("dynamic bce failed!");
1647         }
1648       }
1649     }
1650 
1651     array = new int[7];
1652     pyramid1(array);
1653     if (!isPyramid(array)) {
1654       System.out.println("pyramid1 failed!");
1655     }
1656 
1657     array = new int[8];
1658     pyramid2(array);
1659     if (!isPyramid(array)) {
1660       System.out.println("pyramid2 failed!");
1661     }
1662 
1663     java.util.Arrays.fill(array, -1);
1664     pyramid3(array);
1665     if (!isPyramid(array)) {
1666       System.out.println("pyramid3 failed!");
1667     }
1668 
1669     // Make sure this value is kept after deoptimization.
1670     int i = 1;
1671     if (foo() + i != 100) {
1672       System.out.println("foo failed!");
1673     };
1674 
1675     testUnknownBounds();
1676     new Main().testExceptionMessage();
1677   }
1678 
compiledWithOptimizing()1679   public static native boolean compiledWithOptimizing();
disableStackFrameAsserts()1680   public static native void disableStackFrameAsserts();
assertIsManaged()1681   public static native void assertIsManaged();
assertIsInterpreted()1682   public static native void assertIsInterpreted();
hasOatFile()1683   public static native boolean hasOatFile();
runtimeIsSoftFail()1684   public static native boolean runtimeIsSoftFail();
isInterpreted()1685   public static native boolean isInterpreted();
1686 }
1687