summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/412-new-array/info.txt2
-rw-r--r--test/412-new-array/smali/fill_array_data.smali15
-rw-r--r--test/412-new-array/src/Main.java39
-rw-r--r--test/449-checker-bce/src/Main.java17
-rw-r--r--test/458-checker-instruction-simplification/src/Main.java12
-rw-r--r--test/501-regression-packed-switch/info.txt2
-rw-r--r--test/501-regression-packed-switch/smali/Test.smali25
-rw-r--r--test/501-regression-packed-switch/src/Main.java5
-rw-r--r--test/527-checker-array-access-split/src/Main.java298
-rw-r--r--test/529-checker-unresolved/src/Main.java10
-rw-r--r--test/530-checker-loops3/expected.txt1
-rw-r--r--test/530-checker-loops3/info.txt1
-rw-r--r--test/530-checker-loops3/src/Main.java327
-rw-r--r--test/566-polymorphic-inlining/polymorphic_inline.cc1
-rw-r--r--test/566-polymorphic-inlining/src/Main.java33
-rw-r--r--test/604-hot-static-interface/hot_static_interface.cc62
-rw-r--r--test/604-hot-static-interface/src/Main.java4
-rw-r--r--test/611-checker-simplify-if/expected.txt7
-rw-r--r--test/611-checker-simplify-if/info.txt1
-rw-r--r--test/611-checker-simplify-if/src/Main.java281
-rw-r--r--test/612-jit-dex-cache/expected.txt1
-rw-r--r--test/612-jit-dex-cache/info.txt2
-rw-r--r--test/612-jit-dex-cache/src-ex/B.java18
-rw-r--r--test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java36
-rw-r--r--test/612-jit-dex-cache/src/A.java21
-rw-r--r--test/612-jit-dex-cache/src/B.java18
-rw-r--r--test/612-jit-dex-cache/src/Main.java67
-rw-r--r--test/Android.libarttest.mk3
-rw-r--r--test/Android.run-test.mk2
-rw-r--r--test/common/runtime_state.cc38
-rwxr-xr-xtest/run-test13
31 files changed, 1243 insertions, 119 deletions
diff --git a/test/412-new-array/info.txt b/test/412-new-array/info.txt
index cb388b6023..b5f834aa31 100644
--- a/test/412-new-array/info.txt
+++ b/test/412-new-array/info.txt
@@ -1 +1,3 @@
Simple tests for new-array, filled-new-array and fill-array-data.
+Regression test for the arm64 mterp miscalculating the fill-array-data-payload
+address, zero-extending a register instead of sign-extending.
diff --git a/test/412-new-array/smali/fill_array_data.smali b/test/412-new-array/smali/fill_array_data.smali
index 34776db5de..2b24e56cef 100644
--- a/test/412-new-array/smali/fill_array_data.smali
+++ b/test/412-new-array/smali/fill_array_data.smali
@@ -15,6 +15,21 @@
.end method
+.method public static intArrayFillInstructionAfterData([I)V
+ .registers 1
+ goto :FillInstruction
+
+:ArrayData
+ .array-data 4
+ 1 2 3 4 5
+ .end array-data
+
+:FillInstruction
+ fill-array-data v0, :ArrayData
+ return-void
+
+.end method
+
.method public static shortArray([S)V
.registers 1
diff --git a/test/412-new-array/src/Main.java b/test/412-new-array/src/Main.java
index b9c2a053e0..d95d2c52f3 100644
--- a/test/412-new-array/src/Main.java
+++ b/test/412-new-array/src/Main.java
@@ -259,6 +259,45 @@ public class Main extends TestCase {
}
{
+ Method m = c.getMethod("intArrayFillInstructionAfterData", int[].class);
+ int[] array = new int[7];
+ Object[] args = { array };
+ m.invoke(null, args);
+ assertEquals(7, array.length);
+ assertEquals(1, array[0]);
+ assertEquals(2, array[1]);
+ assertEquals(3, array[2]);
+ assertEquals(4, array[3]);
+ assertEquals(5, array[4]);
+ assertEquals(0, array[5]);
+ assertEquals(0, array[6]);
+
+ array = new int[2];
+ args[0] = array;
+ Throwable exception = null;
+ try {
+ m.invoke(null, args);
+ } catch (InvocationTargetException e) {
+ exception = e.getCause();
+ assertTrue(exception instanceof IndexOutOfBoundsException);
+ }
+ assertNotNull(exception);
+ exception = null;
+ // Test that nothing has been written to the array.
+ assertEquals(0, array[0]);
+ assertEquals(0, array[1]);
+
+ args[0] = null;
+ try {
+ m.invoke(null, args);
+ } catch (InvocationTargetException e) {
+ exception = e.getCause();
+ assertTrue(exception instanceof NullPointerException);
+ }
+ assertNotNull(exception);
+ }
+
+ {
Method m = c.getMethod("shortArray", short[].class);
short[] array = new short[7];
Object[] args = { array };
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 41771b52c4..c125e337cb 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -1204,9 +1204,6 @@ public class Main {
/// CHECK: Deoptimize
/// CHECK: Deoptimize
/// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
/// CHECK-NOT: Deoptimize
/// CHECK: Goto
/// CHECK: Goto
@@ -1217,7 +1214,7 @@ public class Main {
for (int i = array.length - 1 ; i >= 0; i--) {
array[i] = 1;
}
- // Several HDeoptimize will be added. Two for each index.
+ // Three HDeoptimize will be added for the bounds.
// The null check is not necessary.
for (int i = end - 2 ; i > 0; i--) {
if (expectInterpreter) {
@@ -1266,20 +1263,12 @@ public class Main {
/// CHECK: Deoptimize
/// CHECK: Deoptimize
/// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
/// CHECK-NOT: Deoptimize
/// CHECK: Goto
/// CHECK: Goto
/// CHECK: Goto
void foo6(int[] array, int start, int end, boolean expectInterpreter) {
- // Several HDeoptimize will be added.
for (int i = end; i >= start; i--) {
if (expectInterpreter) {
assertIsInterpreted();
@@ -1398,8 +1387,8 @@ public class Main {
/// CHECK-NOT: Deoptimize
void foo9(int[] array, boolean expectInterpreter) {
- // Two HDeoptimize will be added. Two for the index
- // and one for null check on array.
+ // Three HDeoptimize will be added. Two for the index and one for null check on array. Then
+ // simplification removes one redundant HDeoptimize.
for (int i = 0 ; i < 10; i++) {
if (expectInterpreter) {
assertIsInterpreted();
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index 359d521ffc..040479e8c5 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -1142,7 +1142,13 @@ public class Main {
public static boolean $noinline$EqualBoolVsIntConst(boolean arg) {
if (doThrow) { throw new Error(); }
- return (arg ? 0 : 1) != 2;
+ // Make calls that will be inlined to make sure the instruction simplifier
+ // sees the simplification (dead code elimination will also try to simplify it).
+ return (arg ? $inline$ReturnArg(0) : $inline$ReturnArg(1)) != 2;
+ }
+
+ public static int $inline$ReturnArg(int arg) {
+ return arg;
}
/// CHECK-START: boolean Main.$noinline$NotEqualBoolVsIntConst(boolean) instruction_simplifier_after_bce (before)
@@ -1161,7 +1167,9 @@ public class Main {
public static boolean $noinline$NotEqualBoolVsIntConst(boolean arg) {
if (doThrow) { throw new Error(); }
- return (arg ? 0 : 1) == 2;
+ // Make calls that will be inlined to make sure the instruction simplifier
+ // sees the simplification (dead code elimination will also try to simplify it).
+ return (arg ? $inline$ReturnArg(0) : $inline$ReturnArg(1)) == 2;
}
/*
diff --git a/test/501-regression-packed-switch/info.txt b/test/501-regression-packed-switch/info.txt
index fbd93fa815..988b220a87 100644
--- a/test/501-regression-packed-switch/info.txt
+++ b/test/501-regression-packed-switch/info.txt
@@ -1,2 +1,4 @@
Regression test for the interpreter and optimizing's builder which used
to trip when compiled code contained a packed switch with no targets.
+Regression test for the arm64 mterp miscalculating the switch table
+address, zero-extending a register instead of sign-extending.
diff --git a/test/501-regression-packed-switch/smali/Test.smali b/test/501-regression-packed-switch/smali/Test.smali
index 8756ed5f23..5a760c7880 100644
--- a/test/501-regression-packed-switch/smali/Test.smali
+++ b/test/501-regression-packed-switch/smali/Test.smali
@@ -27,3 +27,28 @@
.packed-switch 0x0
.end packed-switch
.end method
+
+.method public static PackedSwitchAfterData(I)I
+ .registers 1
+ goto :pswitch_instr
+
+ :case0
+ const/4 v0, 0x1
+ return v0
+
+ :pswitch_data
+ .packed-switch 0x0
+ :case0
+ :case1
+ .end packed-switch
+
+ :pswitch_instr
+ packed-switch v0, :pswitch_data
+ const/4 v0, 0x7
+ return v0
+
+ :case1
+ const/4 v0, 0x4
+ return v0
+
+.end method
diff --git a/test/501-regression-packed-switch/src/Main.java b/test/501-regression-packed-switch/src/Main.java
index b80bc62c50..12bc1a8138 100644
--- a/test/501-regression-packed-switch/src/Main.java
+++ b/test/501-regression-packed-switch/src/Main.java
@@ -29,5 +29,10 @@ public class Main {
if (result != 5) {
throw new Error("Expected 5, got " + result);
}
+ m = c.getMethod("PackedSwitchAfterData", new Class[] { int.class });
+ result = (Integer) m.invoke(null, new Integer(0));
+ if (result != 1) {
+ throw new Error("Expected 1, got " + result);
+ }
}
}
diff --git a/test/527-checker-array-access-split/src/Main.java b/test/527-checker-array-access-split/src/Main.java
index ead94464bf..3366f20cc5 100644
--- a/test/527-checker-array-access-split/src/Main.java
+++ b/test/527-checker-array-access-split/src/Main.java
@@ -34,9 +34,21 @@ public class Main {
/// CHECK-START-ARM64: int Main.constantIndexGet(int[]) instruction_simplifier_arm64 (after)
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK-NOT: Arm64IntermediateAddress
+ /// CHECK-NOT: IntermediateAddress
/// CHECK: ArrayGet [<<Array>>,<<Index>>]
+
+ /// CHECK-START-ARM: int Main.constantIndexGet(int[]) instruction_simplifier_arm (before)
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: ArrayGet [<<Array>>,<<Index>>]
+
+ /// CHECK-START-ARM: int Main.constantIndexGet(int[]) instruction_simplifier_arm (after)
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK-NOT: IntermediateAddress
+ /// CHECK: ArrayGet [<<Array>>,<<Index>>]
+
public static int constantIndexGet(int array[]) {
return array[1];
}
@@ -55,9 +67,22 @@ public class Main {
/// CHECK: <<Const2:i\d+>> IntConstant 2
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK-NOT: Arm64IntermediateAddress
+ /// CHECK-NOT: IntermediateAddress
+ /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Const2>>]
+
+
+ /// CHECK-START-ARM: void Main.constantIndexSet(int[]) instruction_simplifier_arm (before)
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
/// CHECK: ArraySet [<<Array>>,<<Index>>,<<Const2>>]
+ /// CHECK-START-ARM: void Main.constantIndexSet(int[]) instruction_simplifier_arm (after)
+ /// CHECK: <<Const2:i\d+>> IntConstant 2
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK-NOT: IntermediateAddress
+ /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Const2>>]
public static void constantIndexSet(int array[]) {
array[1] = 2;
@@ -76,7 +101,20 @@ public class Main {
/// CHECK: <<DataOffset:i\d+>> IntConstant
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK: <<Address:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: ArrayGet [<<Address>>,<<Index>>]
+
+
+ /// CHECK-START-ARM: int Main.get(int[], int) instruction_simplifier_arm (before)
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: ArrayGet [<<Array>>,<<Index>>]
+
+ /// CHECK-START-ARM: int Main.get(int[], int) instruction_simplifier_arm (after)
+ /// CHECK: <<DataOffset:i\d+>> IntConstant
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: ArrayGet [<<Address>>,<<Index>>]
public static int get(int array[], int index) {
@@ -102,7 +140,26 @@ public class Main {
/// CHECK: <<DataOffset:i\d+>> IntConstant
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK: <<Address:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: ArraySet [<<Address>>,<<Index>>,<<Arg>>]
+
+
+ /// CHECK-START-ARM: void Main.set(int[], int, int) instruction_simplifier_arm (before)
+ /// CHECK: ParameterValue
+ /// CHECK: ParameterValue
+ /// CHECK: <<Arg:i\d+>> ParameterValue
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Arg>>]
+
+ /// CHECK-START-ARM: void Main.set(int[], int, int) instruction_simplifier_arm (after)
+ /// CHECK: ParameterValue
+ /// CHECK: ParameterValue
+ /// CHECK: <<Arg:i\d+>> ParameterValue
+ /// CHECK: <<DataOffset:i\d+>> IntConstant
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: ArraySet [<<Address>>,<<Index>>,<<Arg>>]
public static void set(int array[], int index, int value) {
@@ -126,10 +183,10 @@ public class Main {
/// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK: <<Address1:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
- /// CHECK: <<Address2:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
/// CHECK-START-ARM64: void Main.getSet(int[], int) GVN_after_arch (after)
@@ -137,12 +194,42 @@ public class Main {
/// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK: <<Address:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
- /// CHECK-NOT: Arm64IntermediateAddress
+ /// CHECK-NOT: IntermediateAddress
/// CHECK: ArraySet [<<Address>>,<<Index>>,<<Add>>]
+
+ /// CHECK-START-ARM: void Main.getSet(int[], int) instruction_simplifier_arm (before)
+ /// CHECK: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>]
+
+ /// CHECK-START-ARM: void Main.getSet(int[], int) instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
+
+ /// CHECK-START-ARM: void Main.getSet(int[], int) GVN_after_arch (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK-NOT: IntermediateAddress
+ /// CHECK: ArraySet [<<Address>>,<<Index>>,<<Add>>]
public static void getSet(int array[], int index) {
array[index] = array[index] + 1;
}
@@ -166,11 +253,11 @@ public class Main {
/// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK: <<Address1:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
/// CHECK: NewArray
- /// CHECK: <<Address2:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
/// CHECK-START-ARM64: int[] Main.accrossGC(int[], int) GVN_after_arch (after)
@@ -178,11 +265,45 @@ public class Main {
/// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
/// CHECK: <<Array:l\d+>> NullCheck
/// CHECK: <<Index:i\d+>> BoundsCheck
- /// CHECK: <<Address1:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
/// CHECK: NewArray
- /// CHECK: <<Address2:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
+
+
+ /// CHECK-START-ARM: int[] Main.accrossGC(int[], int) instruction_simplifier_arm (before)
+ /// CHECK: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK: NewArray
+ /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>]
+
+ /// CHECK-START-ARM: int[] Main.accrossGC(int[], int) instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK: NewArray
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
+
+ /// CHECK-START-ARM: int[] Main.accrossGC(int[], int) GVN_after_arch (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant
+ /// CHECK: <<Array:l\d+>> NullCheck
+ /// CHECK: <<Index:i\d+>> BoundsCheck
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK: NewArray
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
public static int[] accrossGC(int array[], int index) {
@@ -196,6 +317,14 @@ public class Main {
* Test that the intermediate address is shared between array accesses after
* the bounds check have been removed by BCE.
*/
+ // For checker tests `instruction_simplifier_<arch> (after)` below, by the time we reach
+ // the architecture-specific instruction simplifier, BCE has removed the bounds checks in
+ // the loop.
+
+ // Note that we do not care that the `DataOffset` is `12`. But if we do not
+ // specify it and any other `IntConstant` appears before that instruction,
+ // checker will match the previous `IntConstant`, and we will thus fail the
+ // check.
/// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (before)
/// CHECK: <<Const1:i\d+>> IntConstant 1
@@ -207,14 +336,6 @@ public class Main {
/// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
/// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>]
- // By the time we reach the architecture-specific instruction simplifier, BCE
- // has removed the bounds checks in the loop.
-
- // Note that we do not care that the `DataOffset` is `12`. But if we do not
- // specify it and any other `IntConstant` appears before that instruction,
- // checker will match the previous `IntConstant`, and we will thus fail the
- // check.
-
/// CHECK-START-ARM64: int Main.canMergeAfterBCE1() instruction_simplifier_arm64 (after)
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12
@@ -222,10 +343,10 @@ public class Main {
/// CHECK: <<Index:i\d+>> Phi
/// CHECK: If
// -------------- Loop
- /// CHECK: <<Address1:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
- /// CHECK: <<Address2:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
/// CHECK-START-ARM64: int Main.canMergeAfterBCE1() GVN_after_arch (after)
@@ -235,10 +356,47 @@ public class Main {
/// CHECK: <<Index:i\d+>> Phi
/// CHECK: If
// -------------- Loop
- /// CHECK: <<Address:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK-NOT: IntermediateAddress
+ /// CHECK: ArraySet [<<Address>>,<<Index>>,<<Add>>]
+
+
+ /// CHECK-START-ARM: int Main.canMergeAfterBCE1() instruction_simplifier_arm (before)
+ /// CHECK: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<Array:l\d+>> NewArray
+ /// CHECK: <<Index:i\d+>> Phi
+ /// CHECK: If
+ // -------------- Loop
+ /// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK: ArraySet [<<Array>>,<<Index>>,<<Add>>]
+
+ /// CHECK-START-ARM: int Main.canMergeAfterBCE1() instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12
+ /// CHECK: <<Array:l\d+>> NewArray
+ /// CHECK: <<Index:i\d+>> Phi
+ /// CHECK: If
+ // -------------- Loop
+ /// CHECK: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
+ /// CHECK: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-NEXT: ArraySet [<<Address2>>,<<Index>>,<<Add>>]
+
+ /// CHECK-START-ARM: int Main.canMergeAfterBCE1() GVN_after_arch (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12
+ /// CHECK: <<Array:l\d+>> NewArray
+ /// CHECK: <<Index:i\d+>> Phi
+ /// CHECK: If
+ // -------------- Loop
+ /// CHECK: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK: <<ArrayGet:i\d+>> ArrayGet [<<Address>>,<<Index>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGet>>,<<Const1>>]
- /// CHECK-NOT: Arm64IntermediateAddress
+ /// CHECK-NOT: IntermediateAddress
/// CHECK: ArraySet [<<Address>>,<<Index>>,<<Add>>]
public static int canMergeAfterBCE1() {
@@ -279,12 +437,12 @@ public class Main {
/// CHECK: If
// -------------- Loop
/// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>]
- /// CHECK-DAG: <<Address1:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-DAG: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
- /// CHECK-DAG: <<Address2:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-DAG: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address2>>,<<Index1>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGetI>>,<<ArrayGetI1>>]
- /// CHECK: <<Address3:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: <<Address3:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK: ArraySet [<<Address3>>,<<Index1>>,<<Add>>]
/// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN_after_arch (after)
@@ -295,7 +453,7 @@ public class Main {
/// CHECK: If
// -------------- Loop
/// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>]
- /// CHECK-DAG: <<Address:l\d+>> Arm64IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-DAG: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
/// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address>>,<<Index>>]
/// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address>>,<<Index1>>]
/// CHECK: <<Add:i\d+>> Add [<<ArrayGetI>>,<<ArrayGetI1>>]
@@ -304,8 +462,55 @@ public class Main {
// There should be only one intermediate address computation in the loop.
/// CHECK-START-ARM64: int Main.canMergeAfterBCE2() GVN_after_arch (after)
- /// CHECK: Arm64IntermediateAddress
- /// CHECK-NOT: Arm64IntermediateAddress
+ /// CHECK: IntermediateAddress
+ /// CHECK-NOT: IntermediateAddress
+
+
+ /// CHECK-START-ARM: int Main.canMergeAfterBCE2() instruction_simplifier_arm (before)
+ /// CHECK: <<Const1:i\d+>> IntConstant 1
+ /// CHECK: <<Array:l\d+>> NewArray
+ /// CHECK: <<Index:i\d+>> Phi
+ /// CHECK: If
+ // -------------- Loop
+ /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>]
+ /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Array>>,<<Index>>]
+ /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Array>>,<<Index1>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGetI>>,<<ArrayGetI1>>]
+ /// CHECK: ArraySet [<<Array>>,<<Index1>>,<<Add>>]
+
+ /// CHECK-START-ARM: int Main.canMergeAfterBCE2() instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12
+ /// CHECK: <<Array:l\d+>> NewArray
+ /// CHECK: <<Index:i\d+>> Phi
+ /// CHECK: If
+ // -------------- Loop
+ /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>]
+ /// CHECK-DAG: <<Address1:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address1>>,<<Index>>]
+ /// CHECK-DAG: <<Address2:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address2>>,<<Index1>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGetI>>,<<ArrayGetI1>>]
+ /// CHECK: <<Address3:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK: ArraySet [<<Address3>>,<<Index1>>,<<Add>>]
+
+ /// CHECK-START-ARM: int Main.canMergeAfterBCE2() GVN_after_arch (after)
+ /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
+ /// CHECK-DAG: <<DataOffset:i\d+>> IntConstant 12
+ /// CHECK: <<Array:l\d+>> NewArray
+ /// CHECK: <<Index:i\d+>> Phi
+ /// CHECK: If
+ // -------------- Loop
+ /// CHECK-DAG: <<Index1:i\d+>> Add [<<Index>>,<<Const1>>]
+ /// CHECK-DAG: <<Address:l\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>]
+ /// CHECK-DAG: <<ArrayGetI:i\d+>> ArrayGet [<<Address>>,<<Index>>]
+ /// CHECK-DAG: <<ArrayGetI1:i\d+>> ArrayGet [<<Address>>,<<Index1>>]
+ /// CHECK: <<Add:i\d+>> Add [<<ArrayGetI>>,<<ArrayGetI1>>]
+ /// CHECK: ArraySet [<<Address>>,<<Index1>>,<<Add>>]
+
+ /// CHECK-START-ARM: int Main.canMergeAfterBCE2() GVN_after_arch (after)
+ /// CHECK: IntermediateAddress
+ /// CHECK-NOT: IntermediateAddress
public static int canMergeAfterBCE2() {
int[] array = {0, 1, 2, 3};
@@ -315,6 +520,37 @@ public class Main {
return array[array.length - 1];
}
+ /// CHECK-START-ARM: int Main.checkLongFloatDouble() instruction_simplifier_arm (before)
+ /// CHECK-DAG: <<Array1:l\d+>> NewArray
+ /// CHECK-DAG: <<Array2:l\d+>> NewArray
+ /// CHECK-DAG: <<Array3:l\d+>> NewArray
+ /// CHECK-DAG: <<Index:i\d+>> Phi
+ /// CHECK-DAG: ArrayGet [<<Array1>>,<<Index>>]
+ /// CHECK-DAG: ArrayGet [<<Array2>>,<<Index>>]
+ /// CHECK-DAG: ArrayGet [<<Array3>>,<<Index>>]
+
+ /// CHECK-START-ARM: int Main.checkLongFloatDouble() instruction_simplifier_arm (after)
+ /// CHECK-DAG: <<Array1:l\d+>> NewArray
+ /// CHECK-DAG: <<Array2:l\d+>> NewArray
+ /// CHECK-DAG: <<Array3:l\d+>> NewArray
+ /// CHECK-DAG: <<Index:i\d+>> Phi
+ /// CHECK-DAG: ArrayGet [<<Array1>>,<<Index>>]
+ /// CHECK-DAG: ArrayGet [<<Array2>>,<<Index>>]
+ /// CHECK-DAG: ArrayGet [<<Array3>>,<<Index>>]
+
+ /// CHECK-START-ARM: int Main.checkLongFloatDouble() instruction_simplifier_arm (after)
+ /// CHECK-NOT: IntermediateAddress
+ public static int checkLongFloatDouble() {
+ long[] array_long = {0, 1, 2, 3};
+ float[] array_float = {(float)0.0, (float)1.0, (float)2.0, (float)3.0};
+ double[] array_double = {0.0, 1.0, 2.0, 3.0};
+ double s = 0.0;
+
+ for (int i = 0; i < 4; i++) {
+ s += (double)array_long[i] + (double)array_float[i] + array_double[i];
+ }
+ return (int)s;
+ }
public static void main(String[] args) {
int[] array = {123, 456, 789};
@@ -337,5 +573,7 @@ public class Main {
assertIntEquals(4, canMergeAfterBCE1());
assertIntEquals(6, canMergeAfterBCE2());
+
+ assertIntEquals(18, checkLongFloatDouble());
}
}
diff --git a/test/529-checker-unresolved/src/Main.java b/test/529-checker-unresolved/src/Main.java
index 5a36ba5d9c..7b5cbc1504 100644
--- a/test/529-checker-unresolved/src/Main.java
+++ b/test/529-checker-unresolved/src/Main.java
@@ -77,6 +77,16 @@ public class Main extends UnresolvedSuperClass {
expectEquals(123456789123456789f, UnresolvedClass.staticFloat);
expectEquals(123456789123456789d, UnresolvedClass.staticDouble);
expectEquals(o, UnresolvedClass.staticObject);
+
+ // Check "large" values.
+
+ UnresolvedClass.staticByte = (byte)-1;
+ UnresolvedClass.staticChar = (char)32768;
+ UnresolvedClass.staticInt = -1;
+
+ expectEquals((byte)-1, UnresolvedClass.staticByte);
+ expectEquals((char)32768, UnresolvedClass.staticChar);
+ expectEquals(-1, UnresolvedClass.staticInt);
}
/// CHECK-START: void Main.callUnresolvedInstanceFieldAccess(UnresolvedClass) register (before)
diff --git a/test/530-checker-loops3/expected.txt b/test/530-checker-loops3/expected.txt
new file mode 100644
index 0000000000..b0aad4deb5
--- /dev/null
+++ b/test/530-checker-loops3/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/530-checker-loops3/info.txt b/test/530-checker-loops3/info.txt
new file mode 100644
index 0000000000..07d99a3e55
--- /dev/null
+++ b/test/530-checker-loops3/info.txt
@@ -0,0 +1 @@
+Test on loop optimizations, in particular loop-based dynamic bce.
diff --git a/test/530-checker-loops3/src/Main.java b/test/530-checker-loops3/src/Main.java
new file mode 100644
index 0000000000..5ffcbe964d
--- /dev/null
+++ b/test/530-checker-loops3/src/Main.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+//
+// Test on loop optimizations, in particular dynamic BCE. In all cases,
+// bounds check on a[] is resolved statically. Bounds checks on b[]
+// exercise various different scenarios. In all cases, loop-based
+// dynamic BCE is better than the dominator-based BCE, since it
+// generates the test outside the loop.
+//
+public class Main {
+
+ /// CHECK-START: void Main.oneConstantIndex(int[], int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.oneConstantIndex(int[], int[]) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.oneConstantIndex(int[], int[]) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void oneConstantIndex(int[] a, int[] b) {
+ // Dynamic bce on b requires two deopts: one null and one bound.
+ for (int i = 0; i < a.length; i++) {
+ a[i] = b[1];
+ }
+ }
+
+ /// CHECK-START: void Main.multipleConstantIndices(int[], int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.multipleConstantIndices(int[], int[]) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.multipleConstantIndices(int[], int[]) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void multipleConstantIndices(int[] a, int[] b) {
+ // Dynamic bce on b requires two deopts: one null and one bound.
+ for (int i = 0; i < a.length; i++) {
+ a[i] = b[0] + b[1] + b[2];
+ }
+ }
+
+ /// CHECK-START: void Main.oneInvariantIndex(int[], int[], int) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.oneInvariantIndex(int[], int[], int) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.oneInvariantIndex(int[], int[], int) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void oneInvariantIndex(int[] a, int[] b, int c) {
+ // Dynamic bce on b requires two deopts: one null and one bound.
+ for (int i = 0; i < a.length; i++) {
+ a[i] = b[c];
+ }
+ }
+
+ /// CHECK-START: void Main.multipleInvariantIndices(int[], int[], int) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.multipleInvariantIndices(int[], int[], int) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.multipleInvariantIndices(int[], int[], int) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void multipleInvariantIndices(int[] a, int[] b, int c) {
+ // Dynamic bce on b requires three deopts: one null and two bounds.
+ for (int i = 0; i < a.length; i++) {
+ a[i] = b[c-1] + b[c] + b[c+1];
+ }
+ }
+
+ /// CHECK-START: void Main.oneUnitStride(int[], int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.oneUnitStride(int[], int[]) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.oneUnitStride(int[], int[]) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void oneUnitStride(int[] a, int[] b) {
+ // Dynamic bce on b requires three deopts: one null and two bounds.
+ for (int i = 0; i < a.length; i++) {
+ a[i] = b[i];
+ }
+ }
+
+ /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) instruction_simplifier_after_bce (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.multipleUnitStrides(int[], int[]) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void multipleUnitStrides(int[] a, int[] b) {
+ // Dynamic bce on b requires four deopts: one null and three bounds.
+ // One redundant deopt is removed by simplifier.
+ // TODO: range information could remove another
+ for (int i = 1; i < a.length - 1; i++) {
+ a[i] = b[i-1] + b[i] + b[i+1];
+ }
+ }
+
+ /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) instruction_simplifier_after_bce (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.multipleUnitStridesConditional(int[], int[]) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void multipleUnitStridesConditional(int[] a, int[] b) {
+ // Dynamic bce on b requires four deopts: one null and three bounds.
+ // The two conditional references may be included, since they are in range.
+ // One redundant deopt is removed by simplifier.
+ for (int i = 2; i < a.length - 2; i++) {
+ int t = b[i-2] + b[i] + b[i+2] + (((i & 1) == 0) ? b[i+1] : b[i-1]);
+ a[i] = t;
+ }
+ }
+
+ /// CHECK-START: void Main.shifter(int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.shifter(int[]) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.shifter(int[]) instruction_simplifier_after_bce (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.shifter(int[]) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void shifter(int[] x) {
+ // Real-life example: should have four deopts: one null and three bounds.
+ // Two redundant deopts are removed by simplifier.
+ for (int i = 16; i < 80; i++) {
+ int t = x[i - 3] ^ x[i - 8] ^ x[i - 14] ^ x[i - 16];
+ x[i] = t << 1 | t >>> 31;
+ }
+ }
+
+ /// CHECK-START: void Main.stencil(int[], int, int) BCE (before)
+ /// CHECK-DAG: BoundsCheck loop:<<Loop:B\d+>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ /// CHECK-DAG: BoundsCheck loop:<<Loop>>
+ //
+ /// CHECK-START: void Main.stencil(int[], int, int) BCE (after)
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-DAG: Deoptimize loop:none
+ /// CHECK-NOT: Deoptimize
+ //
+ /// CHECK-START: void Main.stencil(int[], int, int) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static void stencil(int[] array, int start, int end) {
+ // Real-life example: should have four deopts: one null and three bounds.
+ for (int i = end; i >= start; i--) {
+ array[i] = (array[i-2] + array[i-1] + array[i] + array[i+1] + array[i+2]) / 5;
+ }
+ }
+
+ //
+ // Verifier.
+ //
+
+ public static void main(String[] args) {
+ int[] a = new int[10];
+ int b[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+ int b1[] = { 100 };
+
+ oneConstantIndex(a, b);
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(2, a[i]);;
+ }
+ try {
+ oneConstantIndex(a, b1);
+ throw new Error("Should throw AIOOBE");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+
+ multipleConstantIndices(a, b);
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(6, a[i]);;
+ }
+ try {
+ multipleConstantIndices(a, b1);
+ throw new Error("Should throw AIOOBE");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+
+ oneInvariantIndex(a, b, 1);
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(2, a[i]);;
+ }
+ try {
+ oneInvariantIndex(a, b1, 1);
+ throw new Error("Should throw AIOOBE");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+
+ multipleInvariantIndices(a, b, 1);
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(6, a[i]);;
+ }
+ try {
+ multipleInvariantIndices(a, b1, 1);
+ throw new Error("Should throw AIOOBE");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+
+ oneUnitStride(a, b);
+ for (int i = 0; i < a.length; i++) {
+ expectEquals(i + 1, a[i]);;
+ }
+ try {
+ oneUnitStride(a, b1);
+ throw new Error("Should throw AIOOBE");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ expectEquals(100, a[0]);;
+ }
+
+ multipleUnitStrides(a, b);
+ for (int i = 1; i < a.length - 1; i++) {
+ expectEquals(3 * i + 3, a[i]);;
+ }
+ try {
+ multipleUnitStrides(a, b1);
+ throw new Error("Should throw AIOOBE");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+
+ multipleUnitStridesConditional(a, b);
+ for (int i = 2; i < a.length - 2; i++) {
+ int e = 3 * i + 3 + (((i & 1) == 0) ? i + 2 : i);
+ expectEquals(e, a[i]);;
+ }
+ try {
+ multipleUnitStridesConditional(a, b1);
+ throw new Error("Should throw AIOOBE");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ }
+
+ System.out.println("passed");
+ }
+
+ private static void expectEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+}
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index c0d93dd8a1..9f4c6c91f8 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -81,6 +81,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_ensureJittedAndPolymorphicInline566(
do_checks(cls, "testInvokeVirtual");
do_checks(cls, "testInvokeInterface");
+ do_checks(cls, "testInvokeInterface2");
do_checks(cls, "$noinline$testInlineToSameTarget");
}
diff --git a/test/566-polymorphic-inlining/src/Main.java b/test/566-polymorphic-inlining/src/Main.java
index d39e6ed57b..53852a417c 100644
--- a/test/566-polymorphic-inlining/src/Main.java
+++ b/test/566-polymorphic-inlining/src/Main.java
@@ -16,6 +16,8 @@
interface Itf {
public Class sameInvokeInterface();
+ public Class sameInvokeInterface2();
+ public Class sameInvokeInterface3();
}
public class Main implements Itf {
@@ -50,6 +52,8 @@ public class Main implements Itf {
testInvokeVirtual(mains[1]);
testInvokeInterface(itfs[0]);
testInvokeInterface(itfs[1]);
+ testInvokeInterface2(itfs[0]);
+ testInvokeInterface2(itfs[1]);
$noinline$testInlineToSameTarget(mains[0]);
$noinline$testInlineToSameTarget(mains[1]);
}
@@ -64,9 +68,13 @@ public class Main implements Itf {
assertEquals(Itf.class, testInvokeInterface(itfs[0]));
assertEquals(Itf.class, testInvokeInterface(itfs[1]));
+ assertEquals(Itf.class, testInvokeInterface2(itfs[0]));
+ assertEquals(Itf.class, testInvokeInterface2(itfs[1]));
+
// This will trigger a deoptimization of the compiled code.
assertEquals(OtherSubclass.class, testInvokeVirtual(mains[2]));
assertEquals(OtherSubclass.class, testInvokeInterface(itfs[2]));
+ assertEquals(null, testInvokeInterface2(itfs[2]));
// Run this once to make sure we execute the JITted code.
$noinline$testInlineToSameTarget(mains[0]);
@@ -83,10 +91,28 @@ public class Main implements Itf {
return Itf.class;
}
+ public Class sameInvokeInterface2() {
+ field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
+ return Itf.class;
+ }
+
+ public Class sameInvokeInterface3() {
+ field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo.
+ return Itf.class;
+ }
+
public static Class testInvokeInterface(Itf i) {
return i.sameInvokeInterface();
}
+ public static Class testInvokeInterface2(Itf i) {
+ // Make three interface calls that will do a ClassTableGet to ensure bogus code
+ // generation of ClassTableGet will crash.
+ i.sameInvokeInterface();
+ i.sameInvokeInterface2();
+ return i.sameInvokeInterface3();
+ }
+
public static Class testInvokeVirtual(Main m) {
return m.sameInvokeVirtual();
}
@@ -120,4 +146,11 @@ class OtherSubclass extends Main {
public Class sameInvokeInterface() {
return OtherSubclass.class;
}
+
+ public Class sameInvokeInterface2() {
+ return null;
+ }
+ public Class sameInvokeInterface3() {
+ return null;
+ }
}
diff --git a/test/604-hot-static-interface/hot_static_interface.cc b/test/604-hot-static-interface/hot_static_interface.cc
deleted file mode 100644
index 475a11d351..0000000000
--- a/test/604-hot-static-interface/hot_static_interface.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "art_method.h"
-#include "jit/jit.h"
-#include "jit/jit_code_cache.h"
-#include "jit/profiling_info.h"
-#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
-#include "ScopedUtfChars.h"
-#include "stack_map.h"
-
-namespace art {
-
-extern "C" JNIEXPORT void JNICALL Java_Main_waitUntilJitted(JNIEnv* env,
- jclass,
- jclass itf,
- jstring method_name) {
- jit::Jit* jit = Runtime::Current()->GetJit();
- if (jit == nullptr) {
- return;
- }
-
- ScopedObjectAccess soa(Thread::Current());
-
- ScopedUtfChars chars(env, method_name);
- CHECK(chars.c_str() != nullptr);
-
- mirror::Class* klass = soa.Decode<mirror::Class*>(itf);
- ArtMethod* method = klass->FindDeclaredDirectMethodByName(chars.c_str(), sizeof(void*));
-
- jit::JitCodeCache* code_cache = jit->GetCodeCache();
- OatQuickMethodHeader* header = nullptr;
- // Make sure there is a profiling info, required by the compiler.
- ProfilingInfo::Create(soa.Self(), method, /* retry_allocation */ true);
- while (true) {
- header = OatQuickMethodHeader::FromEntryPoint(method->GetEntryPointFromQuickCompiledCode());
- if (code_cache->ContainsPc(header->GetCode())) {
- break;
- } else {
- // Sleep to yield to the compiler thread.
- usleep(1000);
- // Will either ensure it's compiled or do the compilation itself.
- jit->CompileMethod(method, soa.Self(), /* osr */ false);
- }
- }
-}
-
-} // namespace art
diff --git a/test/604-hot-static-interface/src/Main.java b/test/604-hot-static-interface/src/Main.java
index 559f15d380..04d7cd6567 100644
--- a/test/604-hot-static-interface/src/Main.java
+++ b/test/604-hot-static-interface/src/Main.java
@@ -22,14 +22,14 @@ public class Main {
Itf.foo(new Object());
}
- waitUntilJitted(Itf.class, "foo");
+ ensureJitCompiled(Itf.class, "foo");
if (!Itf.foo(new Object())) {
throw new Error("Unexpected result");
}
}
- private static native void waitUntilJitted(Class itf, String method_name);
+ private static native void ensureJitCompiled(Class itf, String method_name);
}
interface Itf {
diff --git a/test/611-checker-simplify-if/expected.txt b/test/611-checker-simplify-if/expected.txt
new file mode 100644
index 0000000000..3083c4c528
--- /dev/null
+++ b/test/611-checker-simplify-if/expected.txt
@@ -0,0 +1,7 @@
+54
+54
+54
+12
+12
+12
+33
diff --git a/test/611-checker-simplify-if/info.txt b/test/611-checker-simplify-if/info.txt
new file mode 100644
index 0000000000..b090db816b
--- /dev/null
+++ b/test/611-checker-simplify-if/info.txt
@@ -0,0 +1 @@
+Checker tests for the 'if' simplification in the compiler.
diff --git a/test/611-checker-simplify-if/src/Main.java b/test/611-checker-simplify-if/src/Main.java
new file mode 100644
index 0000000000..21f4115c55
--- /dev/null
+++ b/test/611-checker-simplify-if/src/Main.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Main {
+
+ public static void main(String[] args) {
+ testNoInline(args);
+ System.out.println(staticField);
+ testInline(args);
+ System.out.println(staticField);
+ testNonConstantInputs(args);
+ System.out.println(staticField);
+ testNonConstantEqual(args);
+ System.out.println(staticField);
+ testGreaterCondition(args);
+ System.out.println(staticField);
+ testSwitch(args);
+ System.out.println(staticField);
+ testFP(args);
+ System.out.println(staticField);
+ }
+
+ // Test when a condition is the input of the if.
+
+ /// CHECK-START: void Main.testNoInline(java.lang.String[]) dead_code_elimination (before)
+ /// CHECK: <<Const0:i\d+>> IntConstant 0
+ /// CHECK: If
+ /// CHECK: <<Phi:i\d+>> Phi
+ /// CHECK: <<Equal:z\d+>> Equal [<<Phi>>,<<Const0>>]
+ /// CHECK: If [<<Equal>>]
+
+ /// CHECK-START: void Main.testNoInline(java.lang.String[]) dead_code_elimination (after)
+ /// CHECK: If
+ /// CHECK-NOT: Phi
+ /// CHECK-NOT: Equal
+ /// CHECK-NOT: If
+ public static void testNoInline(String[] args) {
+ boolean myVar = false;
+ if (args.length == 42) {
+ myVar = true;
+ } else {
+ staticField = 32;
+ myVar = false;
+ }
+ if (myVar) {
+ staticField = 12;
+ } else {
+ staticField = 54;
+ }
+ }
+
+ // Test when the phi is the input of the if.
+
+ /// CHECK-START: void Main.testInline(java.lang.String[]) dead_code_elimination_final (before)
+ /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
+ /// CHECK-DAG: If
+ /// CHECK-DAG: <<Phi:i\d+>> Phi
+ /// CHECK-DAG: If [<<Phi>>]
+
+ /// CHECK-START: void Main.testInline(java.lang.String[]) dead_code_elimination_final (after)
+ /// CHECK: If
+ /// CHECK-NOT: Phi
+ /// CHECK-NOT: If
+ public static void testInline(String[] args) {
+ boolean myVar = $inline$doTest(args);
+ if (myVar) {
+ staticField = 12;
+ } else {
+ staticField = 54;
+ }
+ }
+
+ public static boolean $inline$doTest(String[] args) {
+ boolean myVar;
+ if (args.length == 42) {
+ myVar = true;
+ } else {
+ staticField = 32;
+ myVar = false;
+ }
+ return myVar;
+ }
+
+ // Test when one input is not a constant. We can only optimize the constant input.
+
+ /// CHECK-START: void Main.testNonConstantInputs(java.lang.String[]) dead_code_elimination (before)
+ /// CHECK-DAG: <<Const34:i\d+>> IntConstant 34
+ /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
+ /// CHECK-DAG: If
+ /// CHECK-DAG: <<StaticFieldGet:i\d+>> StaticFieldGet
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const34>>,<<StaticFieldGet>>]
+ /// CHECK-DAG: <<NotEqual:z\d+>> NotEqual [<<Phi>>,<<Const42>>]
+ /// CHECK-DAG: If [<<NotEqual>>]
+
+ /// CHECK-START: void Main.testNonConstantInputs(java.lang.String[]) dead_code_elimination (after)
+ /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
+ /// CHECK-DAG: If
+ /// CHECK-DAG: <<StaticFieldGet:i\d+>> StaticFieldGet
+ /// CHECK-NOT: Phi
+ /// CHECK-DAG: <<NotEqual:z\d+>> NotEqual [<<StaticFieldGet>>,<<Const42>>]
+ /// CHECK-DAG: If [<<NotEqual>>]
+ public static void testNonConstantInputs(String[] args) {
+ int a = 42;
+ if (args.length == 42) {
+ a = 34;
+ } else {
+ staticField = 32;
+ a = otherStaticField;
+ }
+ if (a == 42) {
+ staticField = 12;
+ } else {
+ staticField = 54;
+ }
+ }
+
+ // Test with a condition.
+
+ /// CHECK-START: void Main.testGreaterCondition(java.lang.String[]) dead_code_elimination (before)
+ /// CHECK-DAG: <<Const34:i\d+>> IntConstant 34
+ /// CHECK-DAG: <<Const22:i\d+>> IntConstant 22
+ /// CHECK-DAG: <<Const25:i\d+>> IntConstant 25
+ /// CHECK-DAG: If
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const34>>,<<Const22>>]
+ /// CHECK-DAG: <<GE:z\d+>> GreaterThanOrEqual [<<Phi>>,<<Const25>>]
+ /// CHECK-DAG: If [<<GE>>]
+
+ /// CHECK-START: void Main.testGreaterCondition(java.lang.String[]) dead_code_elimination (after)
+ /// CHECK-DAG: If
+ /// CHECK-NOT: Phi
+ /// CHECK-NOT: GreaterThanOrEqual
+ /// CHECK-NOT: If
+ public static void testGreaterCondition(String[] args) {
+ int a = 42;;
+ if (args.length == 42) {
+ a = 34;
+ } else {
+ staticField = 32;
+ a = 22;
+ }
+ if (a < 25) {
+ staticField = 12;
+ } else {
+ staticField = 54;
+ }
+ }
+
+ // Test when comparing non constants.
+
+ /// CHECK-START: void Main.testNonConstantEqual(java.lang.String[]) dead_code_elimination (before)
+ /// CHECK-DAG: <<Const34:i\d+>> IntConstant 34
+ /// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
+ /// CHECK-DAG: If
+ /// CHECK-DAG: <<StaticFieldGet:i\d+>> StaticFieldGet
+ /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Const34>>,<<StaticFieldGet>>]
+ /// CHECK-DAG: <<NotEqual:z\d+>> NotEqual [<<Phi>>,<<StaticFieldGet>>]
+ /// CHECK-DAG: If [<<NotEqual>>]
+
+ /// CHECK-START: void Main.testNonConstantEqual(java.lang.String[]) dead_code_elimination (after)
+ /// CHECK-DAG: <<Const34:i\d+>> IntConstant 34
+ /// CHECK-DAG: If
+ /// CHECK-DAG: <<StaticFieldGet:i\d+>> StaticFieldGet
+ /// CHECK-NOT: Phi
+ /// CHECK-DAG: <<NotEqual:z\d+>> NotEqual [<<Const34>>,<<StaticFieldGet>>]
+ /// CHECK-DAG: If [<<NotEqual>>]
+ public static void testNonConstantEqual(String[] args) {
+ int a = 42;
+ int b = otherStaticField;
+ if (args.length == 42) {
+ a = 34;
+ } else {
+ staticField = 32;
+ a = b;
+ }
+ if (a == b) {
+ staticField = 12;
+ } else {
+ staticField = 54;
+ }
+ }
+
+ // Make sure we don't "simplify" a loop and potentially turn it into
+ // an irreducible loop. The suspend check at the loop header prevents
+ // us from doing the simplification.
+
+ /// CHECK-START: void Main.testLoop(boolean) disassembly (after)
+ /// CHECK-DAG: SuspendCheck
+ /// CHECK: irreducible:false
+ /// CHECK-NOT: irreducible:true
+ public static void testLoop(boolean c) {
+ while (true) {
+ if (c) {
+ if ($noinline$foo()) return;
+ c = false;
+ } else {
+ $noinline$foo();
+ c = true;
+ }
+ }
+ }
+
+ static boolean $noinline$foo() {
+ if (doThrow) throw new Error("");
+ return true;
+ }
+
+ /// CHECK-START: void Main.testSwitch(java.lang.String[]) dead_code_elimination (before)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK: If
+
+ /// CHECK-START: void Main.testSwitch(java.lang.String[]) dead_code_elimination (after)
+ /// CHECK: If
+ /// CHECK: If
+ /// CHECK-NOT: If
+ public static void testSwitch(String[] args) {
+ boolean cond = false;
+ switch (args.length) {
+ case 42:
+ staticField = 11;
+ cond = true;
+ break;
+ case 43:
+ staticField = 33;
+ cond = true;
+ break;
+ default:
+ cond = false;
+ break;
+ }
+ if (cond) {
+ // Redirect case 42 and 43 here.
+ staticField = 2;
+ }
+ // Redirect default here.
+ }
+
+ /// CHECK-START: void Main.testFP(java.lang.String[]) dead_code_elimination (before)
+ /// CHECK: If
+ /// CHECK: If
+
+ /// CHECK-START: void Main.testFP(java.lang.String[]) dead_code_elimination (after)
+ /// CHECK: If
+ /// CHECK: If
+ public static void testFP(String[] args) {
+ float f = 2.2f;
+ float nan = $noinline$getNaN();
+ if (args.length == 42) {
+ f = 4.3f;
+ } else {
+ staticField = 33;
+ f = nan;
+ }
+ if (f == nan) {
+ staticField = 5;
+ }
+ }
+
+ // No inline variant to avoid having the compiler see it's a NaN.
+ static float $noinline$getNaN() {
+ if (doThrow) throw new Error("");
+ return Float.NaN;
+ }
+
+ static boolean doThrow;
+ static int staticField;
+ static int otherStaticField;
+}
diff --git a/test/612-jit-dex-cache/expected.txt b/test/612-jit-dex-cache/expected.txt
new file mode 100644
index 0000000000..6a5618ebc6
--- /dev/null
+++ b/test/612-jit-dex-cache/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/612-jit-dex-cache/info.txt b/test/612-jit-dex-cache/info.txt
new file mode 100644
index 0000000000..e80f642f3e
--- /dev/null
+++ b/test/612-jit-dex-cache/info.txt
@@ -0,0 +1,2 @@
+Regression test for the JIT compiler which used to
+wrongly update the dex cache of a class loader.
diff --git a/test/612-jit-dex-cache/src-ex/B.java b/test/612-jit-dex-cache/src-ex/B.java
new file mode 100644
index 0000000000..4da9a1da6b
--- /dev/null
+++ b/test/612-jit-dex-cache/src-ex/B.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class B {
+}
diff --git a/test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java b/test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java
new file mode 100644
index 0000000000..1d6158a593
--- /dev/null
+++ b/test/612-jit-dex-cache/src-ex/LoadedByAppClassLoader.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class LoadedByAppClassLoader {
+ public static void letMeInlineYou(A a) {
+ a.foo();
+ }
+
+ public static ClassLoader areYouB() {
+ // Ensure letMeInlineYou is JITted and tries to do inlining of A.foo.
+ // The compiler used to wrongly update the dex cache of letMeInlineYou's
+ // class loader.
+ Main.ensureJitCompiled(LoadedByAppClassLoader.class, "letMeInlineYou");
+ return OtherClass.getB().getClassLoader();
+ }
+}
+
+class OtherClass {
+ public static Class getB() {
+ // This used to return the B class of another class loader.
+ return B.class;
+ }
+}
diff --git a/test/612-jit-dex-cache/src/A.java b/test/612-jit-dex-cache/src/A.java
new file mode 100644
index 0000000000..415c712477
--- /dev/null
+++ b/test/612-jit-dex-cache/src/A.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class A {
+ public int foo() {
+ return 42;
+ }
+}
diff --git a/test/612-jit-dex-cache/src/B.java b/test/612-jit-dex-cache/src/B.java
new file mode 100644
index 0000000000..46c878b572
--- /dev/null
+++ b/test/612-jit-dex-cache/src/B.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class B extends A {
+}
diff --git a/test/612-jit-dex-cache/src/Main.java b/test/612-jit-dex-cache/src/Main.java
new file mode 100644
index 0000000000..0e4bd2245d
--- /dev/null
+++ b/test/612-jit-dex-cache/src/Main.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 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;
+import java.lang.reflect.InvocationTargetException;
+
+import dalvik.system.PathClassLoader;
+
+// ClassLoader not delegating for non java. packages.
+class DelegateLastPathClassLoader extends PathClassLoader {
+
+ public DelegateLastPathClassLoader(String dexPath, ClassLoader parent) {
+ super(dexPath, parent);
+ }
+
+ @Override
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (!name.startsWith("java.")) {
+ try {
+ return findClass(name);
+ } catch (ClassNotFoundException ignore) {
+ // Ignore and fall through to parent class loader.
+ }
+ }
+ return super.loadClass(name, resolve);
+ }
+}
+
+public class Main {
+
+ private static Class classFromDifferentLoader() throws Exception {
+ final String DEX_FILE = System.getenv("DEX_LOCATION") + "/612-jit-dex-cache-ex.jar";
+ ClassLoader loader = new DelegateLastPathClassLoader(DEX_FILE, Main.class.getClassLoader());
+ return loader.loadClass("LoadedByAppClassLoader");
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.loadLibrary(args[0]);
+ Class cls = classFromDifferentLoader();
+ Method m = cls.getDeclaredMethod("letMeInlineYou", A.class);
+ B b = new B();
+ // Invoke the method enough times to get an inline cache and get JITted.
+ for (int i = 0; i < 10000; ++i) {
+ m.invoke(null, b);
+ }
+ m = cls.getDeclaredMethod("areYouB", null);
+ ClassLoader loader = (ClassLoader) m.invoke(null);
+ if (loader != cls.getClassLoader()) {
+ throw new Error("Wrong class loader");
+ }
+ }
+
+ public static native void ensureJitCompiled(Class cls, String method_name);
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 75e74eca3a..7813d16657 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -47,8 +47,7 @@ LIBARTTEST_COMMON_SRC_FILES := \
570-checker-osr/osr.cc \
595-profile-saving/profile-saving.cc \
596-app-images/app_images.cc \
- 597-deopt-new-string/deopt.cc \
- 604-hot-static-interface/hot_static_interface.cc
+ 597-deopt-new-string/deopt.cc
ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttestd.so
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index dd6b6f3fbc..8f8b667429 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -527,7 +527,7 @@ TEST_ART_BROKEN_INTERPRETER_READ_BARRIER_RUN_TESTS :=
# Tests that should fail in the read barrier configuration with the Optimizing compiler (AOT).
# 484: Baker's fast path based read barrier compiler instrumentation generates code containing
# more parallel moves on x86, thus some Checker assertions may fail.
-# 527: On ARM64, the read barrier instrumentation does not support the HArm64IntermediateAddress
+# 527: On ARM64 and ARM, the read barrier instrumentation does not support the HIntermediateAddress
# instruction yet (b/26601270).
# 537: Expects an array copy to be intrinsified on x86-64, but calling-on-slowpath intrinsics are
# not yet handled in the read barrier configuration.
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index fd41fd281f..e70a95cbb5 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -18,10 +18,14 @@
#include "base/logging.h"
#include "dex_file-inl.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
#include "mirror/class-inl.h"
#include "nth_caller_visitor.h"
+#include "oat_quick_method_header.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
+#include "ScopedUtfChars.h"
#include "stack.h"
#include "thread-inl.h"
@@ -116,4 +120,38 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* e
return JNI_TRUE;
}
+extern "C" JNIEXPORT void JNICALL Java_Main_ensureJitCompiled(JNIEnv* env,
+ jclass,
+ jclass cls,
+ jstring method_name) {
+ jit::Jit* jit = Runtime::Current()->GetJit();
+ if (jit == nullptr) {
+ return;
+ }
+
+ ScopedObjectAccess soa(Thread::Current());
+
+ ScopedUtfChars chars(env, method_name);
+ CHECK(chars.c_str() != nullptr);
+
+ mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ ArtMethod* method = klass->FindDeclaredDirectMethodByName(chars.c_str(), sizeof(void*));
+
+ jit::JitCodeCache* code_cache = jit->GetCodeCache();
+ OatQuickMethodHeader* header = nullptr;
+ // Make sure there is a profiling info, required by the compiler.
+ ProfilingInfo::Create(soa.Self(), method, /* retry_allocation */ true);
+ while (true) {
+ header = OatQuickMethodHeader::FromEntryPoint(method->GetEntryPointFromQuickCompiledCode());
+ if (code_cache->ContainsPc(header->GetCode())) {
+ break;
+ } else {
+ // Sleep to yield to the compiler thread.
+ usleep(1000);
+ // Will either ensure it's compiled or do the compilation itself.
+ jit->CompileMethod(method, soa.Self(), /* osr */ false);
+ }
+ }
+}
+
} // namespace art
diff --git a/test/run-test b/test/run-test
index 3ae063abca..1ef5428726 100755
--- a/test/run-test
+++ b/test/run-test
@@ -37,7 +37,7 @@ test_dir="test-$$"
if [ -z "$TMPDIR" ]; then
tmp_dir="/tmp/$USER/${test_dir}"
else
- tmp_dir="${TMPDIR}/$USER/${test_dir}"
+ tmp_dir="${TMPDIR}/${test_dir}"
fi
checker="${progdir}/../tools/checker/checker.py"
export JAVA="java"
@@ -78,9 +78,14 @@ if [ -z "$ANDROID_BUILD_TOP" ]; then
export ANDROID_BUILD_TOP=$oldwd
fi
+# ANDROID_HOST_OUT is not set in a build environment.
+if [ -z "$ANDROID_HOST_OUT" ]; then
+ export ANDROID_HOST_OUT=${OUT_DIR:-$ANDROID_BUILD_TOP/out/}host/linux-x86
+fi
+
# If JACK_CLASSPATH is not set, assume it only contains core-libart.
if [ -z "$JACK_CLASSPATH" ]; then
- export JACK_CLASSPATH="${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack:${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/common/obj/JAVA_LIBRARIES/core-oj-hostdex_intermediates/classes.jack"
+ export JACK_CLASSPATH="${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack:${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES/core-oj-hostdex_intermediates/classes.jack"
fi
export JACK="$JACK -g -cp $JACK_CLASSPATH"
@@ -462,10 +467,6 @@ if [ "$runtime" = "dalvik" ]; then
fi
elif [ "$runtime" = "art" ]; then
if [ "$target_mode" = "no" ]; then
- # ANDROID_HOST_OUT is not set in a build environment.
- if [ -z "$ANDROID_HOST_OUT" ]; then
- export ANDROID_HOST_OUT=${OUT_DIR:-$ANDROID_BUILD_TOP/out/}host/linux-x86
- fi
guess_host_arch_name
run_args="${run_args} --boot ${ANDROID_HOST_OUT}/framework/core${image_suffix}${pic_image_suffix}${multi_image_suffix}.art"
run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}"