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