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 import java.lang.reflect.Method;
     18 
     19 public class Main {
     20 
     21   // Workaround for b/18051191.
     22   class InnerClass {}
     23 
     24   public enum TestPath {
     25     ExceptionalFlow1(true, false, 3),
     26     ExceptionalFlow2(false, true, 8),
     27     NormalFlow(false, false, 42);
     28 
     29     TestPath(boolean arg1, boolean arg2, int expected) {
     30       this.arg1 = arg1;
     31       this.arg2 = arg2;
     32       this.expected = expected;
     33     }
     34 
     35     public boolean arg1;
     36     public boolean arg2;
     37     public int expected;
     38   }
     39 
     40   // Test that IntermediateAddress instruction is not alive across BoundsCheck which can throw to
     41   // a catch block.
     42   //
     43   /// CHECK-START-{ARM,ARM64}: void Main.boundsCheckAndCatch(int, int[], int[]) GVN$after_arch (before)
     44   /// CHECK-DAG: <<Const0:i\d+>>       IntConstant 0
     45   /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
     46   /// CHECK-DAG: <<Const2:i\d+>>       IntConstant 2
     47   /// CHECK-DAG: <<Offset:i\d+>>       IntConstant 12
     48   /// CHECK-DAG: <<IndexParam:i\d+>>   ParameterValue
     49   /// CHECK-DAG: <<ArrayA:l\d+>>       ParameterValue
     50   /// CHECK-DAG: <<ArrayB:l\d+>>       ParameterValue
     51   //
     52 
     53   /// CHECK-DAG: <<NullCh1:l\d+>>      NullCheck [<<ArrayA>>]
     54   /// CHECK-DAG: <<LengthA:i\d+>>      ArrayLength
     55   /// CHECK-DAG: <<BoundsCh1:i\d+>>    BoundsCheck [<<IndexParam>>,<<LengthA>>]
     56   /// CHECK-DAG: <<IntAddr1:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
     57   /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const1>>]
     58   /// CHECK-DAG:                       TryBoundary
     59   //
     60   /// CHECK-DAG: <<IntAddr2:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
     61   /// CHECK-DAG:                       ArraySet [<<IntAddr2>>,<<BoundsCh1>>,<<Const2>>]
     62   /// CHECK-DAG: <<NullChB:l\d+>>      NullCheck [<<ArrayB>>]
     63   /// CHECK-DAG: <<LengthB:i\d+>>      ArrayLength
     64   /// CHECK-DAG: <<BoundsChB:i\d+>>    BoundsCheck [<<Const0>>,<<LengthB>>]
     65   /// CHECK-DAG: <<GetB:i\d+>>         ArrayGet [<<NullChB>>,<<BoundsChB>>]
     66   /// CHECK-DAG: <<ZeroCheck:i\d+>>    DivZeroCheck [<<IndexParam>>]
     67   /// CHECK-DAG: <<Div:i\d+>>          Div [<<GetB>>,<<ZeroCheck>>]
     68   /// CHECK-DAG: <<Xplus1:i\d+>>       Add [<<IndexParam>>,<<Const1>>]
     69   /// CHECK-DAG: <<BoundsCh2:i\d+>>    BoundsCheck [<<Xplus1>>,<<LengthA>>]
     70   /// CHECK-DAG: <<IntAddr3:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
     71   /// CHECK-DAG:                       ArraySet [<<IntAddr3>>,<<BoundsCh2>>,<<Div>>]
     72   /// CHECK-DAG:                       TryBoundary
     73   //
     74   /// CHECK-DAG:                       ClearException
     75   /// CHECK-DAG: <<IntAddr4:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
     76   /// CHECK-DAG:                       ArraySet [<<IntAddr4>>,<<BoundsCh1>>,<<Const1>>]
     77   //
     78   /// CHECK-NOT:                       NullCheck
     79   /// CHECK-NOT:                       IntermediateAddress
     80 
     81   /// CHECK-START-{ARM,ARM64}: void Main.boundsCheckAndCatch(int, int[], int[]) GVN$after_arch (after)
     82   /// CHECK-DAG: <<Const0:i\d+>>       IntConstant 0
     83   /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
     84   /// CHECK-DAG: <<Const2:i\d+>>       IntConstant 2
     85   /// CHECK-DAG: <<Offset:i\d+>>       IntConstant 12
     86   /// CHECK-DAG: <<IndexParam:i\d+>>   ParameterValue
     87   /// CHECK-DAG: <<ArrayA:l\d+>>       ParameterValue
     88   /// CHECK-DAG: <<ArrayB:l\d+>>       ParameterValue
     89   //
     90   /// CHECK-DAG: <<NullCh1:l\d+>>      NullCheck [<<ArrayA>>]
     91   /// CHECK-DAG: <<LengthA:i\d+>>      ArrayLength
     92   /// CHECK-DAG: <<BoundsCh1:i\d+>>    BoundsCheck [<<IndexParam>>,<<LengthA>>]
     93   /// CHECK-DAG: <<IntAddr1:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
     94   /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const1>>]
     95   /// CHECK-DAG:                       TryBoundary
     96   //
     97   /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const2>>]
     98   /// CHECK-DAG: <<NullChB:l\d+>>      NullCheck [<<ArrayB>>]
     99   /// CHECK-DAG: <<LengthB:i\d+>>      ArrayLength
    100   /// CHECK-DAG: <<BoundsChB:i\d+>>    BoundsCheck [<<Const0>>,<<LengthB>>]
    101   /// CHECK-DAG: <<GetB:i\d+>>         ArrayGet [<<NullChB>>,<<BoundsChB>>]
    102   /// CHECK-DAG: <<ZeroCheck:i\d+>>    DivZeroCheck [<<IndexParam>>]
    103   /// CHECK-DAG: <<Div:i\d+>>          Div [<<GetB>>,<<ZeroCheck>>]
    104   /// CHECK-DAG: <<Xplus1:i\d+>>       Add [<<IndexParam>>,<<Const1>>]
    105   /// CHECK-DAG: <<BoundsCh2:i\d+>>    BoundsCheck [<<Xplus1>>,<<LengthA>>]
    106   /// CHECK-DAG:                       ArraySet [<<IntAddr1>>,<<BoundsCh2>>,<<Div>>]
    107   /// CHECK-DAG:                       TryBoundary
    108   //
    109   /// CHECK-DAG:                       ClearException
    110   /// CHECK-DAG: <<IntAddr4:i\d+>>     IntermediateAddress [<<NullCh1>>,<<Offset>>]
    111   /// CHECK-DAG:                       ArraySet [<<IntAddr4>>,<<BoundsCh1>>,<<Const1>>]
    112   //
    113   /// CHECK-NOT:                       NullCheck
    114   /// CHECK-NOT:                       IntermediateAddress
    115 
    116   //  Make sure that BoundsCheck, DivZeroCheck and NullCheck don't stop IntermediateAddress sharing.
    117   public static void boundsCheckAndCatch(int x, int[] a, int[] b) {
    118     a[x] = 1;
    119     try {
    120       a[x] = 2;
    121       a[x + 1] = b[0] / x;
    122     } catch (Exception e) {
    123       a[x] = 1;
    124     }
    125   }
    126 
    127   private static void expectEquals(int expected, int result) {
    128     if (expected != result) {
    129       throw new Error("Expected: " + expected + ", found: " + result);
    130     }
    131   }
    132 
    133   public final static int ARRAY_SIZE = 128;
    134 
    135   public static void testBoundsCheckAndCatch() {
    136     int[] a = new int[ARRAY_SIZE];
    137     int[] b = new int[ARRAY_SIZE];
    138 
    139     int index = ARRAY_SIZE - 2;
    140     boundsCheckAndCatch(index, a, b);
    141     expectEquals(2, a[index]);
    142 
    143     index = ARRAY_SIZE - 1;
    144     boundsCheckAndCatch(index, a, b);
    145     expectEquals(1, a[index]);
    146   }
    147 
    148   public static void testMethod(String method) throws Exception {
    149     Class<?> c = Class.forName("Runtime");
    150     Method m = c.getMethod(method, boolean.class, boolean.class);
    151 
    152     for (TestPath path : TestPath.values()) {
    153       Object[] arguments = new Object[] { path.arg1, path.arg2 };
    154       int actual = (Integer) m.invoke(null, arguments);
    155 
    156       if (actual != path.expected) {
    157         throw new Error("Method: \"" + method + "\", path: " + path + ", " +
    158                         "expected: " + path.expected + ", actual: " + actual);
    159       }
    160     }
    161   }
    162 
    163   public static void testIntAddressCatch()  throws Exception {
    164     int[] a = new int[3];
    165 
    166     Class<?> c = Class.forName("Runtime");
    167     Method m = c.getMethod("testIntAddressCatch", int.class,  Class.forName("[I"));
    168     m.invoke(null, 0, a);
    169   }
    170 
    171   public static void main(String[] args) throws Exception {
    172     testMethod("testUseAfterCatch_int");
    173     testMethod("testUseAfterCatch_long");
    174     testMethod("testUseAfterCatch_float");
    175     testMethod("testUseAfterCatch_double");
    176     testMethod("testCatchPhi_const");
    177     testMethod("testCatchPhi_int");
    178     testMethod("testCatchPhi_long");
    179     testMethod("testCatchPhi_float");
    180     testMethod("testCatchPhi_double");
    181     testMethod("testCatchPhi_singleSlot");
    182     testMethod("testCatchPhi_doubleSlot");
    183 
    184     testBoundsCheckAndCatch();
    185     testIntAddressCatch();
    186   }
    187 }
    188