/*
* 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();
}
}
Messung V0.5 in Prozent C=89 H=88 G=88
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-29)
¤
*© Formatika GbR, Deutschland