blob: 2877ef88afd556a3ce829a3c9546e042274ab5aa [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.reflect.Method;
public class Main {
public enum TestPath {
ExceptionalFlow1(true, false, 3),
ExceptionalFlow2(false, true, 8),
NormalFlow(false, false, 42);
TestPath(boolean arg1, boolean arg2, int expected) {
this.arg1 = arg1;
this.arg2 = arg2;
this.expected = expected;
}
public boolean arg1;
public boolean arg2;
public int expected;
}
// Test that IntermediateAddress instruction is not alive across BoundsCheck which can throw to
// a catch block.
//
/// CHECK-START-{ARM,ARM64}: void Main.boundsCheckAndCatch(int, int[], int[]) GVN$after_arch (before)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
/// CHECK-DAG: <<Offset:i\d+>> IntConstant 12
/// CHECK-DAG: <<IndexParam:i\d+>> ParameterValue
/// CHECK-DAG: <<ArrayA:l\d+>> ParameterValue
/// CHECK-DAG: <<ArrayB:l\d+>> ParameterValue
//
/// CHECK-DAG: <<NullCh1:l\d+>> NullCheck [<<ArrayA>>]
/// CHECK-DAG: <<LengthA:i\d+>> ArrayLength
/// CHECK-DAG: <<BoundsCh1:i\d+>> BoundsCheck [<<IndexParam>>,<<LengthA>>]
/// CHECK-DAG: TryBoundary
//
/// CHECK-DAG: <<IntAddr1:i\d+>> IntermediateAddress [<<NullCh1>>,<<Offset>>]
/// CHECK-DAG: ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const2>>]
/// CHECK-DAG: <<NullChB:l\d+>> NullCheck [<<ArrayB>>]
/// CHECK-DAG: <<LengthB:i\d+>> ArrayLength
/// CHECK-DAG: <<BoundsChB:i\d+>> BoundsCheck [<<Const0>>,<<LengthB>>]
/// CHECK-DAG: <<GetB:i\d+>> ArrayGet [<<NullChB>>,<<BoundsChB>>]
/// CHECK-DAG: <<ZeroCheck:i\d+>> DivZeroCheck [<<IndexParam>>]
/// CHECK-DAG: <<Div:i\d+>> Div [<<GetB>>,<<ZeroCheck>>]
/// CHECK-DAG: <<Xplus1:i\d+>> Add [<<IndexParam>>,<<Const1>>]
/// CHECK-DAG: <<BoundsCh2:i\d+>> BoundsCheck [<<Xplus1>>,<<LengthA>>]
/// CHECK-DAG: <<IntAddr2:i\d+>> IntermediateAddress [<<NullCh1>>,<<Offset>>]
/// CHECK-DAG: ArraySet [<<IntAddr2>>,<<BoundsCh2>>,<<Div>>]
/// CHECK-DAG: TryBoundary
//
/// CHECK-DAG: ClearException
/// CHECK-DAG: <<IntAddr3:i\d+>> IntermediateAddress [<<NullCh1>>,<<Offset>>]
/// CHECK-DAG: ArraySet [<<IntAddr3>>,<<BoundsCh1>>,<<Const1>>]
//
/// CHECK-NOT: NullCheck
/// CHECK-NOT: IntermediateAddress
/// CHECK-START-{ARM,ARM64}: void Main.boundsCheckAndCatch(int, int[], int[]) GVN$after_arch (after)
/// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
/// CHECK-DAG: <<Offset:i\d+>> IntConstant 12
/// CHECK-DAG: <<IndexParam:i\d+>> ParameterValue
/// CHECK-DAG: <<ArrayA:l\d+>> ParameterValue
/// CHECK-DAG: <<ArrayB:l\d+>> ParameterValue
//
/// CHECK-DAG: <<NullCh1:l\d+>> NullCheck [<<ArrayA>>]
/// CHECK-DAG: <<LengthA:i\d+>> ArrayLength
/// CHECK-DAG: <<BoundsCh1:i\d+>> BoundsCheck [<<IndexParam>>,<<LengthA>>]
/// CHECK-DAG: TryBoundary
//
/// CHECK-DAG: <<IntAddr1:i\d+>> IntermediateAddress [<<NullCh1>>,<<Offset>>]
/// CHECK-DAG: ArraySet [<<IntAddr1>>,<<BoundsCh1>>,<<Const2>>]
/// CHECK-DAG: <<NullChB:l\d+>> NullCheck [<<ArrayB>>]
/// CHECK-DAG: <<LengthB:i\d+>> ArrayLength
/// CHECK-DAG: <<BoundsChB:i\d+>> BoundsCheck [<<Const0>>,<<LengthB>>]
/// CHECK-DAG: <<GetB:i\d+>> ArrayGet [<<NullChB>>,<<BoundsChB>>]
/// CHECK-DAG: <<ZeroCheck:i\d+>> DivZeroCheck [<<IndexParam>>]
/// CHECK-DAG: <<Div:i\d+>> Div [<<GetB>>,<<ZeroCheck>>]
/// CHECK-DAG: <<Xplus1:i\d+>> Add [<<IndexParam>>,<<Const1>>]
/// CHECK-DAG: <<BoundsCh2:i\d+>> BoundsCheck [<<Xplus1>>,<<LengthA>>]
/// CHECK-DAG: ArraySet [<<IntAddr1>>,<<BoundsCh2>>,<<Div>>]
/// CHECK-DAG: TryBoundary
//
/// CHECK-DAG: ClearException
/// CHECK-DAG: <<IntAddr3:i\d+>> IntermediateAddress [<<NullCh1>>,<<Offset>>]
/// CHECK-DAG: ArraySet [<<IntAddr3>>,<<BoundsCh1>>,<<Const1>>]
//
/// CHECK-NOT: NullCheck
/// CHECK-NOT: IntermediateAddress
// Make sure that BoundsCheck, DivZeroCheck and NullCheck don't stop IntermediateAddress sharing.
public static void boundsCheckAndCatch(int x, int[] a, int[] b) {
// This a[x] = 1 will be eliminated by LSE, but its related instructions (e.g. NullCheck and
// BoundsCheck) will remain.
a[x] = 1;
try {
a[x] = 2;
a[x + 1] = b[0] / x;
} catch (Exception e) {
a[x] = 1;
}
}
private static void expectEquals(int expected, int result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
}
}
public final static int ARRAY_SIZE = 128;
public static void testBoundsCheckAndCatch() {
int[] a = new int[ARRAY_SIZE];
int[] b = new int[ARRAY_SIZE];
int index = ARRAY_SIZE - 2;
boundsCheckAndCatch(index, a, b);
expectEquals(2, a[index]);
index = ARRAY_SIZE - 1;
boundsCheckAndCatch(index, a, b);
expectEquals(1, a[index]);
}
public static void testMethod(String method) throws Exception {
Class<?> c = Class.forName("Runtime");
Method m = c.getMethod(method, boolean.class, boolean.class);
for (TestPath path : TestPath.values()) {
Object[] arguments = new Object[] { path.arg1, path.arg2 };
int actual = (Integer) m.invoke(null, arguments);
if (actual != path.expected) {
throw new Error("Method: \"" + method + "\", path: " + path + ", " +
"expected: " + path.expected + ", actual: " + actual);
}
}
}
public static void testIntAddressCatch() throws Exception {
int[] a = new int[3];
Class<?> c = Class.forName("Runtime");
Method m = c.getMethod("testIntAddressCatch", int.class, Class.forName("[I"));
m.invoke(null, 0, a);
}
public static void main(String[] args) throws Exception {
testMethod("testUseAfterCatch_int");
testMethod("testUseAfterCatch_long");
testMethod("testUseAfterCatch_float");
testMethod("testUseAfterCatch_double");
testMethod("testCatchPhi_const");
testMethod("testCatchPhi_int");
testMethod("testCatchPhi_long");
testMethod("testCatchPhi_float");
testMethod("testCatchPhi_double");
testMethod("testCatchPhi_singleSlot");
testMethod("testCatchPhi_doubleSlot");
testBoundsCheckAndCatch();
testIntAddressCatch();
}
}