Home | History | Annotate | Download | only in src
      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 //
     18 // Test on loop optimizations.
     19 //
     20 public class Main {
     21 
     22   static int sResult;
     23 
     24   //
     25   // Various sequence variables used in bound checks.
     26   //
     27 
     28   /// CHECK-START: void Main.bubble(int[]) BCE (before)
     29   /// CHECK-DAG: BoundsCheck
     30   /// CHECK-DAG: BoundsCheck
     31   //
     32   /// CHECK-START: void Main.bubble(int[]) BCE (after)
     33   /// CHECK-NOT: BoundsCheck
     34   //  TODO: also CHECK-NOT: Deoptimize, see b/27151190
     35   private static void bubble(int[] a) {
     36     for (int i = a.length; --i >= 0;) {
     37       for (int j = 0; j < i; j++) {
     38         if (a[j] > a[j+1]) {
     39           int tmp = a[j];
     40           a[j]  = a[j+1];
     41           a[j+1] = tmp;
     42         }
     43       }
     44     }
     45   }
     46 
     47   /// CHECK-START: int Main.periodicIdiom(int) BCE (before)
     48   /// CHECK-DAG: BoundsCheck
     49   //
     50   /// CHECK-START: int Main.periodicIdiom(int) BCE (after)
     51   /// CHECK-NOT: BoundsCheck
     52   /// CHECK-NOT: Deoptimize
     53   private static int periodicIdiom(int tc) {
     54     int[] x = { 1, 3 };
     55     // Loop with periodic sequence (0, 1).
     56     int k = 0;
     57     int result = 0;
     58     for (int i = 0; i < tc; i++) {
     59       result += x[k];
     60       k = 1 - k;
     61     }
     62     return result;
     63   }
     64 
     65   /// CHECK-START: int Main.periodicSequence2(int) BCE (before)
     66   /// CHECK-DAG: BoundsCheck
     67   //
     68   /// CHECK-START: int Main.periodicSequence2(int) BCE (after)
     69   /// CHECK-NOT: BoundsCheck
     70   /// CHECK-NOT: Deoptimize
     71   private static int periodicSequence2(int tc) {
     72     int[] x = { 1, 3 };
     73     // Loop with periodic sequence (0, 1).
     74     int k = 0;
     75     int l = 1;
     76     int result = 0;
     77     for (int i = 0; i < tc; i++) {
     78       result += x[k];
     79       int t = l;
     80       l = k;
     81       k = t;
     82     }
     83     return result;
     84   }
     85 
     86   /// CHECK-START: int Main.periodicSequence4(int) BCE (before)
     87   /// CHECK-DAG: BoundsCheck
     88   /// CHECK-DAG: BoundsCheck
     89   /// CHECK-DAG: BoundsCheck
     90   /// CHECK-DAG: BoundsCheck
     91   //
     92   /// CHECK-START: int Main.periodicSequence4(int) BCE (after)
     93   /// CHECK-NOT: BoundsCheck
     94   /// CHECK-NOT: Deoptimize
     95   private static int periodicSequence4(int tc) {
     96     int[] x = { 1, 3, 5, 7 };
     97     // Loop with periodic sequence (0, 1, 2, 3).
     98     int k = 0;
     99     int l = 1;
    100     int m = 2;
    101     int n = 3;
    102     int result = 0;
    103     for (int i = 0; i < tc; i++) {
    104       result += x[k] + x[l] + x[m] + x[n];  // all used at once
    105       int t = n;
    106       n = k;
    107       k = l;
    108       l = m;
    109       m = t;
    110     }
    111     return result;
    112   }
    113 
    114   /// CHECK-START: int Main.justRightUp1() BCE (before)
    115   /// CHECK-DAG: BoundsCheck
    116   //
    117   /// CHECK-START: int Main.justRightUp1() BCE (after)
    118   /// CHECK-NOT: BoundsCheck
    119   /// CHECK-NOT: Deoptimize
    120   private static int justRightUp1() {
    121     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    122     int result = 0;
    123     for (int i = Integer.MAX_VALUE - 10, k = 0; i < Integer.MAX_VALUE; i++) {
    124       result += x[k++];
    125     }
    126     return result;
    127   }
    128 
    129   /// CHECK-START: int Main.justRightUp2() BCE (before)
    130   /// CHECK-DAG: BoundsCheck
    131   //
    132   /// CHECK-START: int Main.justRightUp2() BCE (after)
    133   /// CHECK-NOT: BoundsCheck
    134   /// CHECK-NOT: Deoptimize
    135   private static int justRightUp2() {
    136     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    137     int result = 0;
    138     for (int i = Integer.MAX_VALUE - 10; i < Integer.MAX_VALUE; i++) {
    139       result += x[i - Integer.MAX_VALUE + 10];
    140     }
    141     return result;
    142   }
    143 
    144   /// CHECK-START: int Main.justRightUp3() BCE (before)
    145   /// CHECK-DAG: BoundsCheck
    146   //
    147   /// CHECK-START: int Main.justRightUp3() BCE (after)
    148   /// CHECK-NOT: BoundsCheck
    149   /// CHECK-NOT: Deoptimize
    150   private static int justRightUp3() {
    151     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    152     int result = 0;
    153     for (int i = Integer.MAX_VALUE - 10, k = 0; i <= Integer.MAX_VALUE - 1; i++) {
    154       result += x[k++];
    155     }
    156     return result;
    157   }
    158 
    159   /// CHECK-START: int Main.justOOBUp() BCE (before)
    160   /// CHECK-DAG: BoundsCheck
    161   //
    162   /// CHECK-START: int Main.justOOBUp() BCE (after)
    163   /// CHECK-DAG: BoundsCheck
    164   //
    165   /// CHECK-START: int Main.justOOBUp() BCE (after)
    166   /// CHECK-NOT: Deoptimize
    167   private static int justOOBUp() {
    168     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    169     int result = 0;
    170     // Infinite loop!
    171     for (int i = Integer.MAX_VALUE - 9, k = 0; i <= Integer.MAX_VALUE; i++) {
    172       result += x[k++];
    173     }
    174     return result;
    175   }
    176 
    177   /// CHECK-START: int Main.justRightDown1() BCE (before)
    178   /// CHECK-DAG: BoundsCheck
    179   //
    180   /// CHECK-START: int Main.justRightDown1() BCE (after)
    181   /// CHECK-NOT: BoundsCheck
    182   /// CHECK-NOT: Deoptimize
    183   private static int justRightDown1() {
    184     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    185     int result = 0;
    186     for (int i = Integer.MIN_VALUE + 10, k = 0; i > Integer.MIN_VALUE; i--) {
    187       result += x[k++];
    188     }
    189     return result;
    190   }
    191 
    192   /// CHECK-START: int Main.justRightDown2() BCE (before)
    193   /// CHECK-DAG: BoundsCheck
    194   //
    195   /// CHECK-START: int Main.justRightDown2() BCE (after)
    196   /// CHECK-NOT: BoundsCheck
    197   /// CHECK-NOT: Deoptimize
    198   private static int justRightDown2() {
    199     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    200     int result = 0;
    201     for (int i = Integer.MIN_VALUE + 10; i > Integer.MIN_VALUE; i--) {
    202       result += x[Integer.MAX_VALUE + i];
    203     }
    204     return result;
    205   }
    206 
    207   /// CHECK-START: int Main.justRightDown3() BCE (before)
    208   /// CHECK-DAG: BoundsCheck
    209   //
    210   /// CHECK-START: int Main.justRightDown3() BCE (after)
    211   /// CHECK-NOT: BoundsCheck
    212   /// CHECK-NOT: Deoptimize
    213   private static int justRightDown3() {
    214     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    215     int result = 0;
    216     for (int i = Integer.MIN_VALUE + 10, k = 0; i >= Integer.MIN_VALUE + 1; i--) {
    217       result += x[k++];
    218     }
    219     return result;
    220   }
    221 
    222   /// CHECK-START: int Main.justOOBDown() BCE (before)
    223   /// CHECK-DAG: BoundsCheck
    224   //
    225   /// CHECK-START: int Main.justOOBDown() BCE (after)
    226   /// CHECK-DAG: BoundsCheck
    227   //
    228   /// CHECK-START: int Main.justOOBDown() BCE (after)
    229   /// CHECK-NOT: Deoptimize
    230   private static int justOOBDown() {
    231     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    232     int result = 0;
    233     // Infinite loop!
    234     for (int i = Integer.MIN_VALUE + 9, k = 0; i >= Integer.MIN_VALUE; i--) {
    235       result += x[k++];
    236     }
    237     return result;
    238   }
    239 
    240   /// CHECK-START: void Main.lowerOOB(int[]) BCE (before)
    241   /// CHECK-DAG: BoundsCheck
    242   //
    243   /// CHECK-START: void Main.lowerOOB(int[]) BCE (after)
    244   /// CHECK-DAG: BoundsCheck
    245   //
    246   /// CHECK-START: void Main.lowerOOB(int[]) BCE (after)
    247   /// CHECK-NOT: Deoptimize
    248   private static void lowerOOB(int[] x) {
    249     // OOB!
    250     for (int i = -1; i < x.length; i++) {
    251       sResult += x[i];
    252     }
    253   }
    254 
    255   /// CHECK-START: void Main.upperOOB(int[]) BCE (before)
    256   /// CHECK-DAG: BoundsCheck
    257   //
    258   /// CHECK-START: void Main.upperOOB(int[]) BCE (after)
    259   /// CHECK-DAG: BoundsCheck
    260   //
    261   /// CHECK-START: void Main.upperOOB(int[]) BCE (after)
    262   /// CHECK-NOT: Deoptimize
    263   private static void upperOOB(int[] x) {
    264     // OOB!
    265     for (int i = 0; i <= x.length; i++) {
    266       sResult += x[i];
    267     }
    268   }
    269 
    270   /// CHECK-START: void Main.doWhileUpOOB() BCE (before)
    271   /// CHECK-DAG: BoundsCheck
    272   //
    273   /// CHECK-START: void Main.doWhileUpOOB() BCE (after)
    274   /// CHECK-DAG: BoundsCheck
    275   //
    276   /// CHECK-START: void Main.doWhileUpOOB() BCE (after)
    277   /// CHECK-NOT: Deoptimize
    278   private static void doWhileUpOOB() {
    279     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    280     int i = 0;
    281     // OOB!
    282     do {
    283       sResult += x[i++];
    284     } while (i <= x.length);
    285   }
    286 
    287   /// CHECK-START: void Main.doWhileDownOOB() BCE (before)
    288   /// CHECK-DAG: BoundsCheck
    289   //
    290   /// CHECK-START: void Main.doWhileDownOOB() BCE (after)
    291   /// CHECK-DAG: BoundsCheck
    292   //
    293   /// CHECK-START: void Main.doWhileDownOOB() BCE (after)
    294   /// CHECK-NOT: Deoptimize
    295   private static void doWhileDownOOB() {
    296     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    297     int i = x.length - 1;
    298     // OOB!
    299     do {
    300       sResult += x[i--];
    301     } while (-1 <= i);
    302   }
    303 
    304   /// CHECK-START: void Main.hiddenOOB1(int) BCE (before)
    305   /// CHECK-DAG: BoundsCheck
    306   //
    307   /// CHECK-START: void Main.hiddenOOB1(int) BCE (after)
    308   /// CHECK-DAG: Deoptimize
    309   //
    310   /// CHECK-START: void Main.hiddenOOB1(int) BCE (after)
    311   /// CHECK-NOT: BoundsCheck
    312   private static void hiddenOOB1(int lo) {
    313     int[] a = { 1 } ;
    314     for (int i = lo; i <= 10; i++) {
    315       // Dangerous loop where careless static range analysis would yield strict upper bound
    316       // on index j of 5. When, for instance, lo and thus i = -2147483648, the upper bound
    317       // becomes really positive due to arithmetic wrap-around, causing OOB.
    318       // Dynamic BCE is feasible though, since it checks the range.
    319       for (int j = 4; j < i - 5; j++) {
    320         sResult += a[j - 4];
    321       }
    322     }
    323   }
    324 
    325   /// CHECK-START: void Main.hiddenOOB2(int) BCE (before)
    326   /// CHECK-DAG: BoundsCheck
    327   //
    328   /// CHECK-START: void Main.hiddenOOB2(int) BCE (after)
    329   /// CHECK-DAG: Deoptimize
    330   //
    331   /// CHECK-START: void Main.hiddenOOB2(int) BCE (after)
    332   /// CHECK-NOT: BoundsCheck
    333   private static void hiddenOOB2(int hi) {
    334     int[] a = { 1 } ;
    335     for (int i = 0; i < hi; i++) {
    336       // Dangerous loop where careless static range analysis would yield strict lower bound
    337       // on index j of 5. When, for instance, hi and thus i = 2147483647, the upper bound
    338       // becomes really negative due to arithmetic wrap-around, causing OOB.
    339       // Dynamic BCE is feasible though, since it checks the range.
    340       for (int j = 6; j > i + 5; j--) {
    341         sResult += a[j - 6];
    342       }
    343     }
    344   }
    345 
    346   /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (before)
    347   /// CHECK-DAG: BoundsCheck
    348   //
    349   /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (after)
    350   /// CHECK-DAG: BoundsCheck
    351   //
    352   /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (after)
    353   /// CHECK-NOT: Deoptimize
    354   private static void hiddenInfiniteOOB() {
    355     int[] a = { 11 } ;
    356     for (int i = -1; i <= 0; i++) {
    357       // Dangerous loop where careless static range analysis would yield a safe upper bound
    358       // of -3. In reality, due to arithmetic wrap-around (when i = -1, j <= 2147483647;
    359       // whereas when i = 0, j <= -3), this is an infinite loop that goes OOB.
    360       for (int j = -3; j <= 2147483646 * i - 3; j++) {
    361         sResult += a[j + 3];
    362       }
    363     }
    364   }
    365 
    366   /// CHECK-START: void Main.hiddenFiniteOOB() BCE (before)
    367   /// CHECK-DAG: BoundsCheck
    368   //
    369   /// CHECK-START: void Main.hiddenFiniteOOB() BCE (after)
    370   /// CHECK-DAG: Deoptimize
    371   //
    372   /// CHECK-START: void Main.hiddenFiniteOOB() BCE (after)
    373   /// CHECK-NOT: BoundsCheck
    374   private static void hiddenFiniteOOB() {
    375     int[] a = { 111 } ;
    376     for (int i = -1; i <= 0; i++) {
    377       // Dangerous loop similar as above where the loop is now finite, but the
    378       // loop still goes out of bounds for i = -1 due to the large upper bound.
    379       // Dynamic BCE is feasible though, since it checks the range.
    380       for (int j = -4; j < 2147483646 * i - 3; j++) {
    381         sResult += a[j + 4];
    382       }
    383     }
    384   }
    385 
    386   /// CHECK-START: void Main.inductionOOB(int[]) BCE (before)
    387   /// CHECK-DAG: BoundsCheck
    388   //
    389   /// CHECK-START: void Main.inductionOOB(int[]) BCE (after)
    390   /// CHECK-DAG: BoundsCheck
    391   //
    392   /// CHECK-START: void Main.inductionOOB(int[]) BCE (after)
    393   /// CHECK-NOT: Deoptimize
    394   private static void inductionOOB(int[] a) {
    395     // Careless range analysis would remove the bounds check.
    396     // However, the narrower induction b wraps around arithmetically
    397     // before it reaches the end of arrays longer than 127.
    398     byte b = 0;
    399     for (int i = 0; i < a.length; i++) {
    400       a[b++] = i;
    401     }
    402   }
    403 
    404   /// CHECK-START: void Main.controlOOB(int[]) BCE (before)
    405   /// CHECK-DAG: BoundsCheck
    406   //
    407   /// CHECK-START: void Main.controlOOB(int[]) BCE (after)
    408   /// CHECK-DAG: BoundsCheck
    409   //
    410   /// CHECK-START: void Main.controlOOB(int[]) BCE (after)
    411   /// CHECK-NOT: Deoptimize
    412   private static void controlOOB(int[] a) {
    413     // As above, but now the loop control also wraps around.
    414     for (byte i = 0; i < a.length; i++) {
    415       a[i] = -i;
    416     }
    417   }
    418 
    419   /// CHECK-START: void Main.conversionOOB(int[]) BCE (before)
    420   /// CHECK-DAG: BoundsCheck
    421   //
    422   /// CHECK-START: void Main.conversionOOB(int[]) BCE (after)
    423   /// CHECK-DAG: BoundsCheck
    424   //
    425   /// CHECK-START: void Main.conversionOOB(int[]) BCE (after)
    426   /// CHECK-NOT: Deoptimize
    427   private static void conversionOOB(int[] a) {
    428     // As above, but with wrap around caused by an explicit conversion.
    429     for (int i = 0; i < a.length; ) {
    430       a[i] = i;
    431       i = (byte) (i + 1);
    432     }
    433   }
    434 
    435   /// CHECK-START: int[] Main.add() BCE (before)
    436   /// CHECK-DAG: BoundsCheck
    437   //
    438   /// CHECK-START: int[] Main.add() BCE (after)
    439   /// CHECK-NOT: BoundsCheck
    440   /// CHECK-NOT: Deoptimize
    441   private static int[] add() {
    442     int[] a = new int[10];
    443     for (int i = 0; i <= 3; i++) {
    444       for (int j = 0; j <= 6; j++) {
    445         a[i + j] += 1;
    446       }
    447     }
    448     return a;
    449   }
    450 
    451   /// CHECK-START: int[] Main.multiply1() BCE (before)
    452   /// CHECK-DAG: BoundsCheck
    453   //
    454   /// CHECK-START: int[] Main.multiply1() BCE (after)
    455   /// CHECK-NOT: BoundsCheck
    456   /// CHECK-NOT: Deoptimize
    457   private static int[] multiply1() {
    458     int[] a = new int[10];
    459     try {
    460       for (int i = 0; i <= 3; i++) {
    461         for (int j = 0; j <= 3; j++) {
    462           // Range [0,9]: safe.
    463           a[i * j] += 1;
    464         }
    465       }
    466     } catch (Exception e) {
    467       a[0] += 1000;
    468     }
    469     return a;
    470   }
    471 
    472   /// CHECK-START: int[] Main.multiply2() BCE (before)
    473   /// CHECK-DAG: BoundsCheck
    474   //
    475   /// CHECK-START: int[] Main.multiply2() BCE (after)
    476   /// CHECK-DAG: BoundsCheck
    477   //
    478   /// CHECK-START: int[] Main.multiply2() BCE (after)
    479   /// CHECK-NOT: Deoptimize
    480   static int[] multiply2() {
    481     int[] a = new int[10];
    482     try {
    483       for (int i = -3; i <= 3; i++) {
    484         for (int j = -3; j <= 3; j++) {
    485           // Range [-9,9]: unsafe.
    486           a[i * j] += 1;
    487         }
    488       }
    489     } catch (Exception e) {
    490       a[0] += 1000;
    491     }
    492     return a;
    493   }
    494 
    495   /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before)
    496   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    497   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    498   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    499   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    500   //
    501   /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after)
    502   /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
    503   /// CHECK-DAG: Deoptimize  loop:none
    504   //
    505   /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after)
    506   /// CHECK-NOT: NullCheck   loop:{{B\d+}}
    507   /// CHECK-NOT: ArrayLength loop:{{B\d+}}
    508   /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
    509   private static int linearDynamicBCE1(int[] x, int lo, int hi) {
    510     int result = 0;
    511     for (int i = lo; i < hi; i++) {
    512       sResult += x[i];
    513     }
    514     return result;
    515   }
    516 
    517   /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before)
    518   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    519   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    520   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    521   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    522   //
    523   /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after)
    524   /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
    525   /// CHECK-DAG: Deoptimize  loop:none
    526   //
    527   /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after)
    528   /// CHECK-NOT: NullCheck   loop:{{B\d+}}
    529   /// CHECK-NOT: ArrayLength loop:{{B\d+}}
    530   /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
    531   private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) {
    532     int result = 0;
    533     for (int i = lo; i < hi; i++) {
    534       sResult += x[offset + i];
    535     }
    536     return result;
    537   }
    538 
    539   /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before)
    540   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    541   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    542   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    543   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    544   //
    545   /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after)
    546   /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
    547   /// CHECK-DAG: Deoptimize  loop:none
    548   //
    549   /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after)
    550   /// CHECK-NOT: NullCheck   loop:{{B\d+}}
    551   /// CHECK-NOT: ArrayLength loop:{{B\d+}}
    552   /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
    553   private static int wrapAroundDynamicBCE(int[] x) {
    554     int w = 9;
    555     int result = 0;
    556     for (int i = 0; i < 10; i++) {
    557       result += x[w];
    558       w = i;
    559     }
    560     return result;
    561   }
    562 
    563   /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before)
    564   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    565   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    566   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    567   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    568   //
    569   /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after)
    570   /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
    571   /// CHECK-DAG: Deoptimize  loop:none
    572   //
    573   /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after)
    574   /// CHECK-NOT: NullCheck   loop:{{B\d+}}
    575   /// CHECK-NOT: ArrayLength loop:{{B\d+}}
    576   /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
    577   private static int periodicDynamicBCE(int[] x) {
    578     int k = 0;
    579     int result = 0;
    580     for (int i = 0; i < 10; i++) {
    581       result += x[k];
    582       k = 1 - k;
    583     }
    584     return result;
    585   }
    586 
    587   /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
    588   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    589   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    590   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    591   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    592   //
    593   /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
    594   /// CHECK-DAG: ArrayGet    loop:{{B\d+}}
    595   /// CHECK-DAG: Deoptimize  loop:none
    596   //
    597   /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
    598   /// CHECK-NOT: NullCheck   loop:{{B\d+}}
    599   /// CHECK-NOT: ArrayLength loop:{{B\d+}}
    600   /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
    601   static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
    602     // This loop could be infinite for hi = max int. Since i is also used
    603     // as subscript, however, dynamic bce can proceed.
    604     int result = 0;
    605     for (int i = lo; i <= hi; i++) {
    606       result += x[i];
    607     }
    608     return result;
    609   }
    610 
    611   /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
    612   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    613   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    614   //
    615   /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
    616   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    617   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    618   //
    619   /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
    620   /// CHECK-NOT: Deoptimize
    621   static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
    622     // As above, but now the index is not used as subscript,
    623     // and dynamic bce is not applied.
    624     int result = 0;
    625     for (int k = 0, i = lo; i <= hi; i++) {
    626       result += x[k++];
    627     }
    628     return result;
    629   }
    630 
    631   /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before)
    632   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    633   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    634   //
    635   /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after)
    636   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    637   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    638   //
    639   /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after)
    640   /// CHECK-NOT: Deoptimize
    641   static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) {
    642     int result = 0;
    643     // Mix of int and long induction.
    644     int k = 0;
    645     for (long i = lo; i < hi; i++) {
    646       result += x[k++];
    647     }
    648     return result;
    649   }
    650 
    651   /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (before)
    652   /// CHECK-DAG: BoundsCheck loop:<<InnerLoop:B\d+>>
    653   /// CHECK-DAG: ArrayGet    loop:<<InnerLoop>>
    654   /// CHECK-DAG: If          loop:<<InnerLoop>>
    655   /// CHECK-DAG: If          loop:<<OuterLoop:B\d+>>
    656   /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
    657   //
    658   /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after)
    659   /// CHECK-DAG: ArrayGet   loop:<<InnerLoop:B\d+>>
    660   /// CHECK-DAG: Deoptimize loop:<<OuterLoop:B\d+>>
    661   /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
    662   //
    663   /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after)
    664   /// CHECK-NOT: BoundsCheck
    665   //
    666   //  No additional top tests were introduced.
    667   /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after)
    668   /// CHECK-DAG: If
    669   /// CHECK-DAG: If
    670   /// CHECK-NOT: If
    671   static int dynamicBCEConstantRange(int[] x) {
    672     int result = 0;
    673     for (int i = 2; i <= 6; i++) {
    674       // Range analysis sees that innermost loop is finite and always taken.
    675       for (int j = i - 2; j <= i + 2; j++) {
    676         result += x[j];
    677       }
    678     }
    679     return result;
    680   }
    681 
    682   /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before)
    683   /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop:B\d+>>
    684   /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
    685   /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
    686   //
    687   /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
    688   //  Order matters:
    689   /// CHECK:              Deoptimize loop:<<Loop:B\d+>>
    690   //  CHECK-NOT:          Goto       loop:<<Loop>>
    691   /// CHECK-DAG: {{l\d+}} ArrayGet   loop:<<Loop>>
    692   /// CHECK-DAG: {{l\d+}} ArrayGet   loop:<<Loop>>
    693   /// CHECK-DAG: {{l\d+}} ArrayGet   loop:<<Loop>>
    694   /// CHECK:              Goto       loop:<<Loop>>
    695   //
    696   /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
    697   /// CHECK-DAG: Deoptimize loop:none
    698   static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) {
    699     // Deliberately test array length on a before the loop so that only bounds checks
    700     // on constant subscripts remain, making them a viable candidate for hoisting.
    701     if (a.length == 0) {
    702       return -1;
    703     }
    704     // Loop that allows BCE on x[i].
    705     int result = 0;
    706     for (int i = lo; i < hi; i++) {
    707       result += x[i];
    708       if ((i % 10) != 0) {
    709         // None of the subscripts inside a conditional are removed by dynamic bce,
    710         // making them a candidate for deoptimization based on constant indices.
    711         // Compiler should ensure the array loads are not subsequently hoisted
    712         // "above" the deoptimization "barrier" on the bounds.
    713         a[0][i] = 1;
    714         a[1][i] = 2;
    715         a[99][i] = 3;
    716       }
    717     }
    718     return result;
    719   }
    720 
    721   /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (before)
    722   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    723   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    724   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    725   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    726   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    727   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    728   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    729   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    730   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    731   //  For brevity, just test occurrence of at least one of each in the loop:
    732   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    733   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    734   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    735   //
    736   /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
    737   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    738   /// CHECK-NOT: ArrayGet    loop:<<Loop>>
    739   //
    740   /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
    741   /// CHECK-NOT: NullCheck   loop:{{B\d+}}
    742   /// CHECK-NOT: ArrayLength loop:{{B\d+}}
    743   /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
    744   //
    745   /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
    746   /// CHECK-DAG: Deoptimize  loop:none
    747   static int dynamicBCEAndConstantIndicesAllPrimTypes(int[] q,
    748                                                       boolean[] r,
    749                                                       byte[] s,
    750                                                       char[] t,
    751                                                       short[] u,
    752                                                       int[] v,
    753                                                       long[] w,
    754                                                       float[] x,
    755                                                       double[] y, int lo, int hi) {
    756     int result = 0;
    757     for (int i = lo; i < hi; i++) {
    758       // All constant index array references can be hoisted out of the loop during BCE on q[i].
    759       result += q[i] + (r[0] ? 1 : 0) + (int) s[0] + (int) t[0] + (int) u[0] + (int) v[0] +
    760                                         (int) w[0] + (int) x[0] + (int) y[0];
    761     }
    762     return result;
    763   }
    764 
    765   /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (before)
    766   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    767   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    768   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    769   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    770   /// CHECK-DAG: ArrayGet    loop:<<Loop>>
    771   /// CHECK-DAG: NullCheck   loop:<<Loop>>
    772   /// CHECK-DAG: ArrayLength loop:<<Loop>>
    773   /// CHECK-DAG: BoundsCheck loop:<<Loop>>
    774   //
    775   /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after)
    776   /// CHECK-DAG: ArrayGet    loop:<<Loop:B\d+>>
    777   /// CHECK-DAG: Deoptimize  loop:none
    778   //
    779   /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after)
    780   /// CHECK-NOT: ArrayLength loop:{{B\d+}}
    781   /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
    782   static int dynamicBCEAndConstantIndexRefType(int[] q, Integer[] z, int lo, int hi) {
    783     int result = 0;
    784     for (int i = lo; i < hi; i++) {
    785       // Similar to above, but now implicit call to intValue() may prevent hoisting
    786       // z[0] itself during BCE on q[i]. Therefore, we just check BCE on q[i].
    787       result += q[i] + z[0];
    788     }
    789     return result;
    790   }
    791 
    792   //
    793   // Verifier.
    794   //
    795 
    796   public static void main(String[] args) {
    797     // Set to run expensive tests for correctness too.
    798     boolean HEAVY = false;
    799 
    800     int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    801 
    802     int[] a200 = new int[200];
    803 
    804     // Sorting.
    805     int[] sort = { 5, 4, 1, 9, 10, 2, 7, 6, 3, 8 };
    806     bubble(sort);
    807     for (int i = 0; i < 10; i++) {
    808       expectEquals(sort[i], x[i]);
    809     }
    810 
    811     // Periodic adds (1, 3), one at the time.
    812     expectEquals(0, periodicIdiom(-1));
    813     for (int tc = 0; tc < 32; tc++) {
    814       int expected = (tc >> 1) << 2;
    815       if ((tc & 1) != 0)
    816         expected += 1;
    817       expectEquals(expected, periodicIdiom(tc));
    818     }
    819 
    820     // Periodic adds (1, 3), one at the time.
    821     expectEquals(0, periodicSequence2(-1));
    822     for (int tc = 0; tc < 32; tc++) {
    823       int expected = (tc >> 1) << 2;
    824       if ((tc & 1) != 0)
    825         expected += 1;
    826       expectEquals(expected, periodicSequence2(tc));
    827     }
    828 
    829     // Periodic adds (1, 3, 5, 7), all at once.
    830     expectEquals(0, periodicSequence4(-1));
    831     for (int tc = 0; tc < 32; tc++) {
    832       expectEquals(tc * 16, periodicSequence4(tc));
    833     }
    834 
    835     // Large bounds.
    836     expectEquals(55, justRightUp1());
    837     expectEquals(55, justRightUp2());
    838     expectEquals(55, justRightUp3());
    839     expectEquals(55, justRightDown1());
    840     expectEquals(55, justRightDown2());
    841     expectEquals(55, justRightDown3());
    842     sResult = 0;
    843     try {
    844       justOOBUp();
    845     } catch (ArrayIndexOutOfBoundsException e) {
    846       sResult = 1;
    847     }
    848     expectEquals(1, sResult);
    849     sResult = 0;
    850     try {
    851       justOOBDown();
    852     } catch (ArrayIndexOutOfBoundsException e) {
    853       sResult = 1;
    854     }
    855     expectEquals(1, sResult);
    856 
    857     // Lower bound goes OOB.
    858     sResult = 0;
    859     try {
    860       lowerOOB(x);
    861     } catch (ArrayIndexOutOfBoundsException e) {
    862       sResult += 1000;
    863     }
    864     expectEquals(1000, sResult);
    865 
    866     // Upper bound goes OOB.
    867     sResult = 0;
    868     try {
    869       upperOOB(x);
    870     } catch (ArrayIndexOutOfBoundsException e) {
    871       sResult += 1000;
    872     }
    873     expectEquals(1055, sResult);
    874 
    875     // Do while up goes OOB.
    876     sResult = 0;
    877     try {
    878       doWhileUpOOB();
    879     } catch (ArrayIndexOutOfBoundsException e) {
    880       sResult += 1000;
    881     }
    882     expectEquals(1055, sResult);
    883 
    884     // Do while down goes OOB.
    885     sResult = 0;
    886     try {
    887       doWhileDownOOB();
    888     } catch (ArrayIndexOutOfBoundsException e) {
    889       sResult += 1000;
    890     }
    891     expectEquals(1055, sResult);
    892 
    893     // Hidden OOB.
    894     sResult = 0;
    895     try {
    896       hiddenOOB1(10);  // no OOB
    897     } catch (ArrayIndexOutOfBoundsException e) {
    898       sResult += 1000;
    899     }
    900     expectEquals(1, sResult);
    901     sResult = 0;
    902     try {
    903       hiddenOOB1(-2147483648);  // OOB
    904     } catch (ArrayIndexOutOfBoundsException e) {
    905       sResult += 1000;
    906     }
    907     expectEquals(1001, sResult);
    908     sResult = 0;
    909     try {
    910       hiddenOOB2(1);  // no OOB
    911     } catch (ArrayIndexOutOfBoundsException e) {
    912       sResult += 1000;
    913     }
    914     expectEquals(1, sResult);
    915     if (HEAVY) {
    916       sResult = 0;
    917       try {
    918         hiddenOOB2(2147483647);  // OOB
    919       } catch (ArrayIndexOutOfBoundsException e) {
    920         sResult += 1000;
    921       }
    922       expectEquals(1002, sResult);
    923     }
    924     sResult = 0;
    925     try {
    926       hiddenInfiniteOOB();
    927     } catch (ArrayIndexOutOfBoundsException e) {
    928       sResult += 1000;
    929     }
    930     expectEquals(1011, sResult);
    931     sResult = 0;
    932     try {
    933       hiddenFiniteOOB();
    934     } catch (ArrayIndexOutOfBoundsException e) {
    935       sResult += 1000;
    936     }
    937     expectEquals(1111, sResult);
    938     sResult = 0;
    939     try {
    940       inductionOOB(a200);
    941     } catch (ArrayIndexOutOfBoundsException e) {
    942       sResult += 1000;
    943     }
    944     expectEquals(1000, sResult);
    945     for (int i = 0; i < 200; i++) {
    946       expectEquals(i < 128 ? i : 0, a200[i]);
    947     }
    948     sResult = 0;
    949     try {
    950       controlOOB(a200);
    951     } catch (ArrayIndexOutOfBoundsException e) {
    952       sResult += 1000;
    953     }
    954     expectEquals(1000, sResult);
    955     for (int i = 0; i < 200; i++) {
    956       expectEquals(i < 128 ? -i : 0, a200[i]);
    957     }
    958     sResult = 0;
    959     try {
    960       conversionOOB(a200);
    961     } catch (ArrayIndexOutOfBoundsException e) {
    962       sResult += 1000;
    963     }
    964     expectEquals(1000, sResult);
    965     for (int i = 0; i < 200; i++) {
    966       expectEquals(i < 128 ? i : 0, a200[i]);
    967     }
    968 
    969     // Addition.
    970     {
    971       int[] e1 ={ 1, 2, 3, 4, 4, 4, 4, 3, 2, 1 };
    972       int[] a1 = add();
    973       for (int i = 0; i < 10; i++) {
    974         expectEquals(a1[i], e1[i]);
    975       }
    976     }
    977 
    978     // Multiplication.
    979     {
    980       int[] e1 = { 7, 1, 2, 2, 1, 0, 2, 0, 0, 1 };
    981       int[] a1 = multiply1();
    982       for (int i = 0; i < 10; i++) {
    983         expectEquals(a1[i], e1[i]);
    984       }
    985       int[] e2 = { 1001, 0, 0, 1, 0, 0, 1, 0, 0, 1 };
    986       int[] a2 = multiply2();
    987       for (int i = 0; i < 10; i++) {
    988         expectEquals(a2[i], e2[i]);
    989       }
    990     }
    991 
    992     // Dynamic BCE.
    993     sResult = 0;
    994     try {
    995       linearDynamicBCE1(x, -1, x.length);
    996     } catch (ArrayIndexOutOfBoundsException e) {
    997       sResult += 1000;
    998     }
    999     expectEquals(1000, sResult);
   1000     sResult = 0;
   1001     linearDynamicBCE1(x, 0, x.length);
   1002     expectEquals(55, sResult);
   1003     sResult = 0;
   1004     try {
   1005       linearDynamicBCE1(x, 0, x.length + 1);
   1006     } catch (ArrayIndexOutOfBoundsException e) {
   1007       sResult += 1000;
   1008     }
   1009     expectEquals(1055, sResult);
   1010 
   1011     // Dynamic BCE with offset.
   1012     sResult = 0;
   1013     try {
   1014       linearDynamicBCE2(x, 0, x.length, -1);
   1015     } catch (ArrayIndexOutOfBoundsException e) {
   1016       sResult += 1000;
   1017     }
   1018     expectEquals(1000, sResult);
   1019     sResult = 0;
   1020     linearDynamicBCE2(x, 0, x.length, 0);
   1021     expectEquals(55, sResult);
   1022     sResult = 0;
   1023     try {
   1024       linearDynamicBCE2(x, 0, x.length, 1);
   1025     } catch (ArrayIndexOutOfBoundsException e) {
   1026       sResult += 1000;
   1027     }
   1028     expectEquals(1054, sResult);
   1029 
   1030     // Dynamic BCE candidates.
   1031     expectEquals(55, wrapAroundDynamicBCE(x));
   1032     expectEquals(15, periodicDynamicBCE(x));
   1033     expectEquals(55, dynamicBCEPossiblyInfiniteLoop(x, 0, 9));
   1034     expectEquals(55, noDynamicBCEPossiblyInfiniteLoop(x, 0, 9));
   1035     expectEquals(55, noDynamicBCEMixedInductionTypes(x, 0, 10));
   1036     expectEquals(125, dynamicBCEConstantRange(x));
   1037 
   1038     // Dynamic BCE combined with constant indices.
   1039     int[][] a;
   1040     a = new int[0][0];
   1041     expectEquals(-1, dynamicBCEAndConstantIndices(x, a, 0, 10));
   1042     a = new int[100][10];
   1043     expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10));
   1044     for (int i = 0; i < 10; i++) {
   1045       expectEquals((i % 10) != 0 ? 1 : 0, a[0][i]);
   1046       expectEquals((i % 10) != 0 ? 2 : 0, a[1][i]);
   1047       expectEquals((i % 10) != 0 ? 3 : 0, a[99][i]);
   1048     }
   1049     a = new int[2][10];
   1050     sResult = 0;
   1051     try {
   1052       expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10));
   1053     } catch (ArrayIndexOutOfBoundsException e) {
   1054       sResult = 1;
   1055     }
   1056     expectEquals(1, sResult);
   1057     expectEquals(a[0][1], 1);
   1058     expectEquals(a[1][1], 2);
   1059 
   1060     // Dynamic BCE combined with constant indices of all types.
   1061     boolean[] x1 = { true };
   1062     byte[] x2 = { 2 };
   1063     char[] x3 = { 3 };
   1064     short[] x4 = { 4 };
   1065     int[] x5 = { 5 };
   1066     long[] x6 = { 6 };
   1067     float[] x7 = { 7 };
   1068     double[] x8 = { 8 };
   1069     expectEquals(415,
   1070         dynamicBCEAndConstantIndicesAllPrimTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, 0, 10));
   1071     Integer[] x9 = { 9 };
   1072     expectEquals(145, dynamicBCEAndConstantIndexRefType(x, x9, 0, 10));
   1073 
   1074     System.out.println("passed");
   1075   }
   1076 
   1077   private static void expectEquals(int expected, int result) {
   1078     if (expected != result) {
   1079       throw new Error("Expected: " + expected + ", found: " + result);
   1080     }
   1081   }
   1082 }
   1083