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 
TestPath(boolean arg1, boolean arg2, int expected)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.
boundsCheckAndCatch(int x, int[] a, int[] b)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 
expectEquals(int expected, int result)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 
testBoundsCheckAndCatch()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 
testMethod(String method)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 
testIntAddressCatch()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 
main(String[] args)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