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