summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/004-NativeAllocations/src/Main.java30
-rw-r--r--test/098-ddmc/src/Main.java16
-rw-r--r--test/135-MirandaDispatch/expected.txt1
-rw-r--r--test/135-MirandaDispatch/smali/b_21646347.smali15
-rw-r--r--test/135-MirandaDispatch/src/Main.java9
-rw-r--r--test/137-cfi/cfi.cc35
-rw-r--r--test/137-cfi/src/Main.java25
-rw-r--r--test/441-checker-inliner/src/Main.java12
-rw-r--r--test/449-checker-bce/src/Main.java167
-rw-r--r--test/450-checker-types/src/Main.java31
-rw-r--r--test/478-checker-clinit-check-pruning/src/Main.java6
-rw-r--r--test/482-checker-loop-back-edge-use/src/Main.java30
-rw-r--r--test/491-current-method/expected.txt0
-rw-r--r--test/491-current-method/info.txt2
-rw-r--r--test/491-current-method/src/Main.java70
-rw-r--r--test/492-checker-inline-invoke-interface/expected.txt5
-rw-r--r--test/492-checker-inline-invoke-interface/info.txt1
-rw-r--r--test/492-checker-inline-invoke-interface/src/Main.java50
-rw-r--r--test/493-checker-inline-invoke-interface/expected.txt5
-rw-r--r--test/493-checker-inline-invoke-interface/info.txt2
-rw-r--r--test/493-checker-inline-invoke-interface/src/Main.java48
-rw-r--r--test/494-checker-instanceof-tests/expected.txt0
-rw-r--r--test/494-checker-instanceof-tests/info.txt1
-rw-r--r--test/494-checker-instanceof-tests/src/Main.java203
-rw-r--r--test/495-checker-checkcast-tests/expected.txt0
-rw-r--r--test/495-checker-checkcast-tests/info.txt1
-rw-r--r--test/495-checker-checkcast-tests/src/Main.java204
-rw-r--r--test/496-checker-inlining-and-class-loader/expected.txt4
-rw-r--r--test/496-checker-inlining-and-class-loader/info.txt2
-rw-r--r--test/496-checker-inlining-and-class-loader/src/Main.java125
-rw-r--r--test/497-inlining-and-class-loader/clear_dex_cache.cc46
-rw-r--r--test/497-inlining-and-class-loader/expected.txt7
-rw-r--r--test/497-inlining-and-class-loader/info.txt2
-rw-r--r--test/497-inlining-and-class-loader/src/Level1.java27
-rw-r--r--test/497-inlining-and-class-loader/src/Main.java133
-rw-r--r--test/498-type-propagation/expected.txt1
-rw-r--r--test/498-type-propagation/info.txt2
-rw-r--r--test/498-type-propagation/smali/TypePropagation.smali30
-rw-r--r--test/498-type-propagation/src/Main.java29
-rw-r--r--test/800-smali/expected.txt1
-rw-r--r--test/800-smali/smali/b_17410612.smali14
-rw-r--r--test/800-smali/src/Main.java2
-rw-r--r--test/Android.libarttest.mk4
-rw-r--r--test/Android.libnativebridgetest.mk1
-rw-r--r--test/Android.run-test.mk28
-rwxr-xr-xtest/etc/run-test-jar4
-rwxr-xr-xtest/run-test7
47 files changed, 1359 insertions, 79 deletions
diff --git a/test/004-NativeAllocations/src/Main.java b/test/004-NativeAllocations/src/Main.java
index a99fe92081..92f4e21f40 100644
--- a/test/004-NativeAllocations/src/Main.java
+++ b/test/004-NativeAllocations/src/Main.java
@@ -19,6 +19,8 @@ import java.lang.Runtime;
public class Main {
static Object nativeLock = new Object();
+ static Object deadlockLock = new Object();
+ static boolean aboutToDeadlockLock = false;
static int nativeBytes = 0;
static Object runtime;
static Method register_native_allocation;
@@ -28,13 +30,15 @@ public class Main {
static class NativeAllocation {
private int bytes;
- NativeAllocation(int bytes) throws Exception {
+ NativeAllocation(int bytes, boolean testingDeadlock) throws Exception {
this.bytes = bytes;
register_native_allocation.invoke(runtime, bytes);
synchronized (nativeLock) {
- nativeBytes += bytes;
- if (nativeBytes > maxMem) {
- throw new OutOfMemoryError();
+ if (!testingDeadlock) {
+ nativeBytes += bytes;
+ if (nativeBytes > maxMem) {
+ throw new OutOfMemoryError();
+ }
}
}
}
@@ -44,6 +48,9 @@ public class Main {
nativeBytes -= bytes;
}
register_native_free.invoke(runtime, bytes);
+ aboutToDeadlockLock = true;
+ synchronized (deadlockLock) {
+ }
}
}
@@ -59,7 +66,20 @@ public class Main {
int allocation_count = 256;
NativeAllocation[] allocations = new NativeAllocation[count];
for (int i = 0; i < allocation_count; ++i) {
- allocations[i % count] = new NativeAllocation(size);
+ allocations[i % count] = new NativeAllocation(size, false);
+ }
+ // Test that we don't get a deadlock if we are holding nativeLock. If there is no timeout,
+ // then we will get a finalizer timeout exception.
+ aboutToDeadlockLock = false;
+ synchronized (deadlockLock) {
+ for (int i = 0; aboutToDeadlockLock != true; ++i) {
+ allocations[i % count] = new NativeAllocation(size, true);
+ }
+ // Do more allocations now that the finalizer thread is deadlocked so that we force
+ // finalization and timeout.
+ for (int i = 0; i < 10; ++i) {
+ allocations[i % count] = new NativeAllocation(size, true);
+ }
}
System.out.println("Test complete");
}
diff --git a/test/098-ddmc/src/Main.java b/test/098-ddmc/src/Main.java
index f41ff2a94a..4914ba2289 100644
--- a/test/098-ddmc/src/Main.java
+++ b/test/098-ddmc/src/Main.java
@@ -43,14 +43,24 @@ public class Main {
System.out.println("Confirm when we overflow, we don't roll over to zero. b/17392248");
final int overflowAllocations = 64 * 1024; // Won't fit in unsigned 16-bit value.
+ // TODO: Temporary fix. Keep the new objects live so they are not garbage collected.
+ // This will cause OOM exception for GC stress tests. The root cause is changed behaviour of
+ // getRecentAllocations(). Working on restoring its old behaviour. b/20037135
+ Object[] objects = new Object[overflowAllocations];
for (int i = 0; i < overflowAllocations; i++) {
- new Object();
+ objects[i] = new Object();
}
Allocations after = new Allocations(DdmVmInternal.getRecentAllocations());
System.out.println("before < overflowAllocations=" + (before.numberOfEntries < overflowAllocations));
System.out.println("after > before=" + (after.numberOfEntries > before.numberOfEntries));
System.out.println("after.numberOfEntries=" + after.numberOfEntries);
+ // TODO: Temporary fix as above. b/20037135
+ objects = null;
+ Runtime.getRuntime().gc();
+ final int fillerStrings = 16 * 1024;
+ String[] strings = new String[fillerStrings];
+
System.out.println("Disable and confirm back to empty");
DdmVmInternal.enableRecentAllocations(false);
System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
@@ -66,8 +76,8 @@ public class Main {
System.out.println("Confirm we can reenable twice in a row without losing allocations");
DdmVmInternal.enableRecentAllocations(true);
System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
- for (int i = 0; i < 16 * 1024; i++) {
- new String("fnord");
+ for (int i = 0; i < fillerStrings; i++) {
+ strings[i] = new String("fnord");
}
Allocations first = new Allocations(DdmVmInternal.getRecentAllocations());
DdmVmInternal.enableRecentAllocations(true);
diff --git a/test/135-MirandaDispatch/expected.txt b/test/135-MirandaDispatch/expected.txt
index 134d8d0b47..5b098e5fac 100644
--- a/test/135-MirandaDispatch/expected.txt
+++ b/test/135-MirandaDispatch/expected.txt
@@ -1 +1,2 @@
+b/21646347
Finishing
diff --git a/test/135-MirandaDispatch/smali/b_21646347.smali b/test/135-MirandaDispatch/smali/b_21646347.smali
new file mode 100644
index 0000000000..b4979a5357
--- /dev/null
+++ b/test/135-MirandaDispatch/smali/b_21646347.smali
@@ -0,0 +1,15 @@
+.class public LB21646347;
+
+# If an invoke-virtual dispatches to a miranda method, ensure that we test for the receiver
+# being a subclass of the abstract class, not postpone the check because the miranda method's
+# declaring class is an interface.
+
+.super Ljava/lang/Object;
+
+.method public static run(LB21646347;)V
+ .registers 1
+ # Invoke the miranda method on an object of this class. This should fail type-checking,
+ # instead of letting this pass as the declaring class is an interface.
+ invoke-virtual {v0}, LMain$AbstractClass;->m()V
+ return-void
+.end method
diff --git a/test/135-MirandaDispatch/src/Main.java b/test/135-MirandaDispatch/src/Main.java
index bb005b0103..ada8cefead 100644
--- a/test/135-MirandaDispatch/src/Main.java
+++ b/test/135-MirandaDispatch/src/Main.java
@@ -46,6 +46,15 @@ public class Main {
if (counter != loopIterations * loopIterations) {
System.out.println("Expected " + loopIterations * loopIterations + " got " + counter);
}
+
+ try {
+ Class<?> b21646347 = Class.forName("B21646347");
+ throw new RuntimeException("Expected a VerifyError");
+ } catch (VerifyError expected) {
+ System.out.println("b/21646347");
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
System.out.println("Finishing");
}
}
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index b2d7e55214..601fbaaea8 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -29,6 +29,9 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
+#include "oat_file.h"
#include "utils.h"
namespace art {
@@ -73,18 +76,45 @@ static bool CheckStack(Backtrace* bt, const std::vector<std::string>& seq) {
}
}
+ printf("Can not find %s in backtrace:\n", seq[cur_search_index].c_str());
+ for (Backtrace::const_iterator it = bt->begin(); it != bt->end(); ++it) {
+ if (BacktraceMap::IsValid(it->map)) {
+ printf(" %s\n", it->func_name.c_str());
+ }
+ }
+
return false;
}
#endif
+// Currently we have to fall back to our own loader for the boot image when it's compiled PIC
+// because its base is zero. Thus in-process unwinding through it won't work. This is a helper
+// detecting this.
+#if __linux__
+static bool IsPicImage() {
+ gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
+ CHECK(image_space != nullptr); // We should be running with an image.
+ const OatFile* oat_file = image_space->GetOatFile();
+ CHECK(oat_file != nullptr); // We should have an oat file to go with the image.
+ return oat_file->IsPic();
+}
+#endif
+
extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(JNIEnv*, jobject, jint, jboolean) {
#if __linux__
+ if (IsPicImage()) {
+ LOG(INFO) << "Image is pic, in-process unwinding check bypassed.";
+ return JNI_TRUE;
+ }
+
// TODO: What to do on Valgrind?
std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));
if (!bt->Unwind(0, nullptr)) {
+ printf("Can not unwind in process.\n");
return JNI_FALSE;
} else if (bt->NumFrames() == 0) {
+ printf("No frames for unwind in process.\n");
return JNI_FALSE;
}
@@ -94,6 +124,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(JNIEnv*, jobject
std::vector<std::string> seq = {
"Java_Main_unwindInProcess", // This function.
"boolean Main.unwindInProcess(int, boolean)", // The corresponding Java native method frame.
+ "int java.util.Arrays.binarySearch(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)", // Framework method.
"void Main.main(java.lang.String[])" // The Java entry method.
};
@@ -155,6 +186,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jobj
if (ptrace(PTRACE_ATTACH, pid, 0, 0)) {
// Were not able to attach, bad.
+ printf("Failed to attach to other process.\n");
PLOG(ERROR) << "Failed to attach.";
kill(pid, SIGCONT);
return JNI_FALSE;
@@ -172,8 +204,10 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jobj
std::unique_ptr<Backtrace> bt(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
bool result = true;
if (!bt->Unwind(0, nullptr)) {
+ printf("Can not unwind other process.\n");
result = false;
} else if (bt->NumFrames() == 0) {
+ printf("No frames for unwind of other process.\n");
result = false;
}
@@ -185,6 +219,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jobj
// Note: For some reason, the name isn't
// resolved, so don't look for it right now.
"boolean Main.sleep(int, boolean, double)", // The corresponding Java native method frame.
+ "int java.util.Arrays.binarySearch(java.lang.Object[], int, int, java.lang.Object, java.util.Comparator)", // Framework method.
"void Main.main(java.lang.String[])" // The Java entry method.
};
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index e184e66e6f..658ba53099 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -20,8 +20,10 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
-public class Main {
+public class Main implements Comparator<Main> {
// Whether to test local unwinding. Libunwind uses linker info to find executables. As we do
// not dlopen at the moment, this doesn't work, so keep it off for now.
public final static boolean TEST_LOCAL_UNWINDING = false;
@@ -32,6 +34,8 @@ public class Main {
private boolean secondary;
+ private boolean passed;
+
public Main(boolean secondary) {
this.secondary = secondary;
}
@@ -60,13 +64,13 @@ public class Main {
}
private void runSecondary() {
- foo(true);
+ foo();
throw new RuntimeException("Didn't expect to get back...");
}
private void runPrimary() {
// First do the in-process unwinding.
- if (TEST_LOCAL_UNWINDING && !foo(false)) {
+ if (TEST_LOCAL_UNWINDING && !foo()) {
System.out.println("Unwinding self failed.");
}
@@ -134,8 +138,19 @@ public class Main {
}
}
- public boolean foo(boolean b) {
- return bar(b);
+ public boolean foo() {
+ // Call bar via Arrays.binarySearch.
+ // This tests that we can unwind from framework code.
+ Main[] array = { this, this, this };
+ Arrays.binarySearch(array, 0, 3, this /* value */, this /* comparator */);
+ return passed;
+ }
+
+ public int compare(Main lhs, Main rhs) {
+ passed = bar(secondary);
+ // Returning "equal" ensures that we terminate search
+ // after first item and thus call bar() only once.
+ return 0;
}
public boolean bar(boolean b) {
diff --git a/test/441-checker-inliner/src/Main.java b/test/441-checker-inliner/src/Main.java
index df969a488e..3899d7fb26 100644
--- a/test/441-checker-inliner/src/Main.java
+++ b/test/441-checker-inliner/src/Main.java
@@ -19,7 +19,7 @@ public class Main {
/// CHECK-START: void Main.InlineVoid() inliner (before)
/// CHECK-DAG: <<Const42:i\d+>> IntConstant 42
/// CHECK-DAG: InvokeStaticOrDirect
- /// CHECK-DAG: InvokeStaticOrDirect [<<Const42>>]
+ /// CHECK-DAG: InvokeStaticOrDirect [<<Const42>>,{{[ij]\d+}}]
/// CHECK-START: void Main.InlineVoid() inliner (after)
/// CHECK-NOT: InvokeStaticOrDirect
@@ -31,7 +31,7 @@ public class Main {
/// CHECK-START: int Main.InlineParameter(int) inliner (before)
/// CHECK-DAG: <<Param:i\d+>> ParameterValue
- /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Param>>]
+ /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Param>>,{{[ij]\d+}}]
/// CHECK-DAG: Return [<<Result>>]
/// CHECK-START: int Main.InlineParameter(int) inliner (after)
@@ -44,7 +44,7 @@ public class Main {
/// CHECK-START: long Main.InlineWideParameter(long) inliner (before)
/// CHECK-DAG: <<Param:j\d+>> ParameterValue
- /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<Param>>]
+ /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<Param>>,{{[ij]\d+}}]
/// CHECK-DAG: Return [<<Result>>]
/// CHECK-START: long Main.InlineWideParameter(long) inliner (after)
@@ -57,7 +57,7 @@ public class Main {
/// CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (before)
/// CHECK-DAG: <<Param:l\d+>> ParameterValue
- /// CHECK-DAG: <<Result:l\d+>> InvokeStaticOrDirect [<<Param>>]
+ /// CHECK-DAG: <<Result:l\d+>> InvokeStaticOrDirect [<<Param>>,{{[ij]\d+}}]
/// CHECK-DAG: Return [<<Result>>]
/// CHECK-START: java.lang.Object Main.InlineReferenceParameter(java.lang.Object) inliner (after)
@@ -130,8 +130,8 @@ public class Main {
/// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
/// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
/// CHECK-DAG: <<Const5:i\d+>> IntConstant 5
- /// CHECK-DAG: <<Add:i\d+>> InvokeStaticOrDirect [<<Const1>>,<<Const3>>]
- /// CHECK-DAG: <<Sub:i\d+>> InvokeStaticOrDirect [<<Const5>>,<<Const3>>]
+ /// CHECK-DAG: <<Add:i\d+>> InvokeStaticOrDirect [<<Const1>>,<<Const3>>,{{[ij]\d+}}]
+ /// CHECK-DAG: <<Sub:i\d+>> InvokeStaticOrDirect [<<Const5>>,<<Const3>>,{{[ij]\d+}}]
/// CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Sub>>]
/// CHECK-DAG: Return [<<Phi>>]
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 8960df896b..ed6fc1ee2b 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -617,15 +617,21 @@ public class Main {
/// CHECK: ArrayGet
/// CHECK-START: void Main.foo1(int[], int, int) BCE (after)
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK-NOT: Deoptimize
/// CHECK: Phi
/// CHECK-NOT: BoundsCheck
/// CHECK: ArraySet
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ /// CHECK: Phi
+ /// CHECK: Goto
void foo1(int[] array, int start, int end) {
// Three HDeoptimize will be added. One for
@@ -646,15 +652,21 @@ public class Main {
/// CHECK: ArrayGet
/// CHECK-START: void Main.foo2(int[], int, int) BCE (after)
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK-NOT: Deoptimize
/// CHECK: Phi
/// CHECK-NOT: BoundsCheck
/// CHECK: ArraySet
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ /// CHECK: Phi
+ /// CHECK: Goto
void foo2(int[] array, int start, int end) {
// Three HDeoptimize will be added. One for
@@ -675,14 +687,20 @@ public class Main {
/// CHECK: ArrayGet
/// CHECK-START: void Main.foo3(int[], int) BCE (after)
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK-NOT: Deoptimize
/// CHECK: Phi
/// CHECK-NOT: BoundsCheck
/// CHECK: ArraySet
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ /// CHECK: Phi
+ /// CHECK: Goto
void foo3(int[] array, int end) {
// Two HDeoptimize will be added. One for end < array.length,
@@ -694,6 +712,7 @@ public class Main {
}
}
+
/// CHECK-START: void Main.foo4(int[], int) BCE (before)
/// CHECK: BoundsCheck
/// CHECK: ArraySet
@@ -701,14 +720,20 @@ public class Main {
/// CHECK: ArrayGet
/// CHECK-START: void Main.foo4(int[], int) BCE (after)
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK-NOT: Deoptimize
/// CHECK: Phi
/// CHECK-NOT: BoundsCheck
/// CHECK: ArraySet
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ /// CHECK: Phi
+ /// CHECK: Goto
void foo4(int[] array, int end) {
// Two HDeoptimize will be added. One for end <= array.length,
@@ -734,8 +759,6 @@ public class Main {
/// CHECK-START: void Main.foo5(int[], int) BCE (after)
/// CHECK-NOT: BoundsCheck
/// CHECK: ArraySet
- /// CHECK: Deoptimize
- /// CHECK-NOT: Deoptimize
/// CHECK: Phi
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
@@ -743,6 +766,15 @@ public class Main {
/// CHECK: ArrayGet
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ // array.length is defined before the loop header so no phi is needed.
+ /// CHECK-NOT: Phi
+ /// CHECK: Goto
void foo5(int[] array, int end) {
// Bounds check in this loop can be eliminated without deoptimization.
@@ -774,10 +806,6 @@ public class Main {
/// CHECK: ArraySet
/// CHECK-START: void Main.foo6(int[], int, int) BCE (after)
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK-NOT: Deoptimize
/// CHECK: Phi
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
@@ -791,6 +819,17 @@ public class Main {
/// CHECK: ArrayGet
/// CHECK-NOT: BoundsCheck
/// CHECK: ArraySet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ /// CHECK: Phi
+ /// CHECK: Goto
+ /// CHECK-NOT: Deoptimize
void foo6(int[] array, int start, int end) {
// Three HDeoptimize will be added. One for
@@ -810,15 +849,21 @@ public class Main {
/// CHECK: ArrayGet
/// CHECK-START: void Main.foo7(int[], int, int, boolean) BCE (after)
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK: Deoptimize
- /// CHECK-NOT: Deoptimize
/// CHECK: Phi
/// CHECK: BoundsCheck
/// CHECK: ArrayGet
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ /// CHECK: Phi
+ /// CHECK: Goto
void foo7(int[] array, int start, int end, boolean lowEnd) {
// Three HDeoptimize will be added. One for
@@ -837,6 +882,73 @@ public class Main {
}
+ /// CHECK-START: void Main.foo8(int[][], int, int) BCE (before)
+ /// CHECK: BoundsCheck
+ /// CHECK: ArrayGet
+ /// CHECK: BoundsCheck
+ /// CHECK: ArraySet
+
+ /// CHECK-START: void Main.foo8(int[][], int, int) BCE (after)
+ /// CHECK: Phi
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK: ArrayGet
+ /// CHECK: Phi
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK: ArraySet
+ // Added blocks for deoptimization.
+ /// CHECK: If
+ /// CHECK: Goto
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Goto
+ /// CHECK: Phi
+ /// CHECK: Goto
+
+ void foo8(int[][] matrix, int start, int end) {
+ // Three HDeoptimize will be added for the outer loop.
+ // start >= 0, end <= matrix.length, and null check on matrix.
+ // Three HDeoptimize will be added for the inner loop
+ // start >= 0 (TODO: this may be optimized away),
+ // end <= row.length, and null check on row.
+ for (int i = start; i < end; i++) {
+ int[] row = matrix[i];
+ for (int j = start; j < end; j++) {
+ row[j] = 1;
+ }
+ }
+ }
+
+
+ /// CHECK-START: void Main.foo9(int[]) BCE (before)
+ /// CHECK: NullCheck
+ /// CHECK: BoundsCheck
+ /// CHECK: ArrayGet
+
+ /// CHECK-START: void Main.foo9(int[]) BCE (after)
+ // The loop is guaranteed to be entered. No need to transform the
+ // loop for loop body entry test.
+ /// CHECK: Deoptimize
+ /// CHECK: Deoptimize
+ /// CHECK-NOT: Deoptimize
+ /// CHECK: Phi
+ /// CHECK-NOT: NullCheck
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK: ArrayGet
+
+ void foo9(int[] array) {
+ // Two HDeoptimize will be added. One for
+ // 10 <= array.length, and one for null check on array.
+ for (int i = 0 ; i < 10; i++) {
+ sum += array[i];
+ }
+ }
+
+
/// CHECK-START: void Main.partialLooping(int[], int, int) BCE (before)
/// CHECK: BoundsCheck
/// CHECK: ArraySet
@@ -951,6 +1063,13 @@ public class Main {
main.foo6(new int[10], 2, 7);
main = new Main();
+ int[] array9 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ main.foo9(array9);
+ if (main.sum != 45) {
+ System.out.println("foo9 failed!");
+ }
+
+ main = new Main();
int[] array = new int[4];
main.partialLooping(new int[3], 0, 4);
if ((array[0] != 1) && (array[1] != 1) &&
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index 4056275d3d..9070627f1c 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -364,6 +364,37 @@ public class Main {
((SubclassA)b).$noinline$g();
}
+ public SubclassA $noinline$getSubclass() { throw new RuntimeException(); }
+
+ /// CHECK-START: void Main.testArraySimpleRemove() instruction_simplifier_after_types (before)
+ /// CHECK: CheckCast
+
+ /// CHECK-START: void Main.testArraySimpleRemove() instruction_simplifier_after_types (after)
+ /// CHECK-NOT: CheckCast
+ public void testArraySimpleRemove() {
+ Super[] b = new SubclassA[10];
+ SubclassA[] c = (SubclassA[])b;
+ }
+
+ /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier_after_types (before)
+ /// CHECK: CheckCast
+
+ /// CHECK-START: void Main.testInvokeSimpleRemove() instruction_simplifier_after_types (after)
+ /// CHECK-NOT: CheckCast
+ public void testInvokeSimpleRemove() {
+ Super b = $noinline$getSubclass();
+ ((SubclassA)b).$noinline$g();
+ }
+ /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier_after_types (before)
+ /// CHECK: CheckCast
+
+ /// CHECK-START: void Main.testArrayGetSimpleRemove() instruction_simplifier_after_types (after)
+ /// CHECK-NOT: CheckCast
+ public void testArrayGetSimpleRemove() {
+ Super[] a = new SubclassA[10];
+ ((SubclassA)a[0]).$noinline$g();
+ }
+
public static void main(String[] args) {
}
}
diff --git a/test/478-checker-clinit-check-pruning/src/Main.java b/test/478-checker-clinit-check-pruning/src/Main.java
index a2c98c9363..e6aab630f9 100644
--- a/test/478-checker-clinit-check-pruning/src/Main.java
+++ b/test/478-checker-clinit-check-pruning/src/Main.java
@@ -26,7 +26,7 @@ public class Main {
/// CHECK-START: void Main.invokeStaticInlined() builder (after)
/// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
/// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
- /// CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
+ /// CHECK-DAG: InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
/// CHECK-START: void Main.invokeStaticInlined() inliner (after)
/// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
@@ -69,12 +69,12 @@ public class Main {
/// CHECK-START: void Main.invokeStaticNotInlined() builder (after)
/// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
/// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
- /// CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
+ /// CHECK-DAG: InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
/// CHECK-START: void Main.invokeStaticNotInlined() inliner (after)
/// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false
/// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>]
- /// CHECK-DAG: InvokeStaticOrDirect [<<ClinitCheck>>]
+ /// CHECK-DAG: InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>]
// The following checks ensure the clinit check and load class
// instructions added by the builder are pruned by the
diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java
index 5754723d8a..a4280de749 100644
--- a/test/482-checker-loop-back-edge-use/src/Main.java
+++ b/test/482-checker-loop-back-edge-use/src/Main.java
@@ -36,8 +36,8 @@ public class Main {
}
/// CHECK-START: void Main.loop3(boolean) liveness (after)
- /// CHECK: ParameterValue liveness:4 ranges:{[4,62)} uses:[58,62]
- /// CHECK: Goto liveness:60
+ /// CHECK: ParameterValue liveness:4 ranges:{[4,64)} uses:[60,64]
+ /// CHECK: Goto liveness:62
/// CHECK-START: void Main.loop3(boolean) liveness (after)
/// CHECK-NOT: Goto liveness:56
@@ -63,9 +63,9 @@ public class Main {
}
/// CHECK-START: void Main.loop5(boolean) liveness (after)
- /// CHECK: ParameterValue liveness:4 ranges:{[4,52)} uses:[35,44,48,52]
- /// CHECK: Goto liveness:46
- /// CHECK: Goto liveness:50
+ /// CHECK: ParameterValue liveness:4 ranges:{[4,54)} uses:[37,46,50,54]
+ /// CHECK: Goto liveness:48
+ /// CHECK: Goto liveness:52
public static void loop5(boolean incoming) {
// 'incoming' must have a use at both back edges.
while (Runtime.getRuntime() != null) {
@@ -76,8 +76,8 @@ public class Main {
}
/// CHECK-START: void Main.loop6(boolean) liveness (after)
- /// CHECK: ParameterValue liveness:4 ranges:{[4,48)} uses:[26,48]
- /// CHECK: Goto liveness:46
+ /// CHECK: ParameterValue liveness:4 ranges:{[4,50)} uses:[26,50]
+ /// CHECK: Goto liveness:48
/// CHECK-START: void Main.loop6(boolean) liveness (after)
/// CHECK-NOT: Goto liveness:24
@@ -90,9 +90,9 @@ public class Main {
}
/// CHECK-START: void Main.loop7(boolean) liveness (after)
- /// CHECK: ParameterValue liveness:4 ranges:{[4,52)} uses:[34,43,48,52]
- /// CHECK: Goto liveness:46
- /// CHECK: Goto liveness:50
+ /// CHECK: ParameterValue liveness:4 ranges:{[4,54)} uses:[36,45,50,54]
+ /// CHECK: Goto liveness:48
+ /// CHECK: Goto liveness:52
public static void loop7(boolean incoming) {
// 'incoming' must have a use at both back edges.
while (Runtime.getRuntime() != null) {
@@ -102,9 +102,9 @@ public class Main {
}
/// CHECK-START: void Main.loop8() liveness (after)
- /// CHECK: StaticFieldGet liveness:14 ranges:{[14,46)} uses:[37,42,46]
- /// CHECK: Goto liveness:40
- /// CHECK: Goto liveness:44
+ /// CHECK: StaticFieldGet liveness:14 ranges:{[14,48)} uses:[39,44,48]
+ /// CHECK: Goto liveness:42
+ /// CHECK: Goto liveness:46
public static void loop8() {
// 'incoming' must have a use at both back edges.
boolean incoming = field;
@@ -114,8 +114,8 @@ public class Main {
}
/// CHECK-START: void Main.loop9() liveness (after)
- /// CHECK: StaticFieldGet liveness:24 ranges:{[24,38)} uses:[33,38]
- /// CHECK: Goto liveness:40
+ /// CHECK: StaticFieldGet liveness:26 ranges:{[26,40)} uses:[35,40]
+ /// CHECK: Goto liveness:42
public static void loop9() {
while (Runtime.getRuntime() != null) {
// 'incoming' must only have a use in the inner loop.
diff --git a/test/491-current-method/expected.txt b/test/491-current-method/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/491-current-method/expected.txt
diff --git a/test/491-current-method/info.txt b/test/491-current-method/info.txt
new file mode 100644
index 0000000000..e9678da769
--- /dev/null
+++ b/test/491-current-method/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing that used to
+crash in the presence of slow paths with intrinsics.
diff --git a/test/491-current-method/src/Main.java b/test/491-current-method/src/Main.java
new file mode 100644
index 0000000000..87ef05218d
--- /dev/null
+++ b/test/491-current-method/src/Main.java
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+class Main {
+
+ // The code below is written in a way that will crash
+ // the generated code at the time of submission of this test.
+ // Therefore, changes to the register allocator may
+ // affect the reproducibility of the crash.
+ public static void $noinline$foo(int a, int b, int c) {
+ // The division on x86 will take EAX and EDX, leaving ECX
+ // to put the ART current method.
+ c = c / 42;
+ // We use the empty string for forcing the slow path.
+ // The slow path for charAt when it is intrinsified, will
+ // move the parameter to ECX, and therefore overwrite the ART
+ // current method.
+ "".charAt(c);
+
+ // Do more things in the method to prevent inlining.
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ c = c / 42;
+ "".charAt(c);
+ }
+
+ public static void main(String[] args) {
+ boolean didThrow = false;
+ try {
+ $noinline$foo(1, 2, 3);
+ } catch (Throwable e) {
+ didThrow = true;
+ }
+
+ if (!didThrow) {
+ throw new Error("Expected an exception from charAt");
+ }
+ }
+}
diff --git a/test/492-checker-inline-invoke-interface/expected.txt b/test/492-checker-inline-invoke-interface/expected.txt
new file mode 100644
index 0000000000..b0014d7529
--- /dev/null
+++ b/test/492-checker-inline-invoke-interface/expected.txt
@@ -0,0 +1,5 @@
+Hello from clinit
+java.lang.Exception
+ at ForceStatic.<clinit>(Main.java:24)
+ at Main.$inline$foo(Main.java:31)
+ at Main.main(Main.java:48)
diff --git a/test/492-checker-inline-invoke-interface/info.txt b/test/492-checker-inline-invoke-interface/info.txt
new file mode 100644
index 0000000000..4a0a5ff1d3
--- /dev/null
+++ b/test/492-checker-inline-invoke-interface/info.txt
@@ -0,0 +1 @@
+Checker test to ensure we can inline interface calls.
diff --git a/test/492-checker-inline-invoke-interface/src/Main.java b/test/492-checker-inline-invoke-interface/src/Main.java
new file mode 100644
index 0000000000..9a4548542b
--- /dev/null
+++ b/test/492-checker-inline-invoke-interface/src/Main.java
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+interface Itf {
+ public void $inline$foo();
+}
+
+class ForceStatic {
+ static {
+ System.out.println("Hello from clinit");
+ new Exception().printStackTrace();
+ }
+ static int field;
+}
+
+public class Main implements Itf {
+ public void $inline$foo() {
+ int a = ForceStatic.field;
+ }
+
+ /// CHECK-START: void Main.main(java.lang.String[]) inliner (before)
+ /// CHECK: InvokeStaticOrDirect
+ /// CHECK: InvokeStaticOrDirect
+
+ /// CHECK-START: void Main.main(java.lang.String[]) inliner (before)
+ /// CHECK-NOT: ClinitCheck
+
+ /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect
+
+ /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
+ /// CHECK: ClinitCheck
+ public static void main(String[] args) {
+ Itf itf = new Main();
+ itf.$inline$foo();
+ }
+}
diff --git a/test/493-checker-inline-invoke-interface/expected.txt b/test/493-checker-inline-invoke-interface/expected.txt
new file mode 100644
index 0000000000..93620a6fb5
--- /dev/null
+++ b/test/493-checker-inline-invoke-interface/expected.txt
@@ -0,0 +1,5 @@
+Hello from clinit
+java.lang.Exception
+ at ForceStatic.<clinit>(Main.java:24)
+ at Main.foo(Main.java:31)
+ at Main.main(Main.java:42)
diff --git a/test/493-checker-inline-invoke-interface/info.txt b/test/493-checker-inline-invoke-interface/info.txt
new file mode 100644
index 0000000000..bac9c82c9d
--- /dev/null
+++ b/test/493-checker-inline-invoke-interface/info.txt
@@ -0,0 +1,2 @@
+Check that we can optimize interface calls without
+requiring the verifier to sharpen them.
diff --git a/test/493-checker-inline-invoke-interface/src/Main.java b/test/493-checker-inline-invoke-interface/src/Main.java
new file mode 100644
index 0000000000..44b727fe55
--- /dev/null
+++ b/test/493-checker-inline-invoke-interface/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+interface Itf {
+ public void foo();
+}
+
+class ForceStatic {
+ static {
+ System.out.println("Hello from clinit");
+ new Exception().printStackTrace();
+ }
+ static int field;
+}
+
+public class Main implements Itf {
+ public void foo() {
+ int a = ForceStatic.field;
+ }
+
+ /// CHECK-START: void Main.main(java.lang.String[]) inliner (before)
+ /// CHECK: InvokeStaticOrDirect
+ /// CHECK: InvokeInterface
+
+ /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
+ /// CHECK-NOT: Invoke{{.*}}
+ public static void main(String[] args) {
+ Itf itf = bar();
+ itf.foo();
+ }
+
+ public static Itf bar() {
+ return new Main();
+ }
+}
diff --git a/test/494-checker-instanceof-tests/expected.txt b/test/494-checker-instanceof-tests/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/494-checker-instanceof-tests/expected.txt
diff --git a/test/494-checker-instanceof-tests/info.txt b/test/494-checker-instanceof-tests/info.txt
new file mode 100644
index 0000000000..59e20bd6a9
--- /dev/null
+++ b/test/494-checker-instanceof-tests/info.txt
@@ -0,0 +1 @@
+Checker test for optimizations on instanceof.
diff --git a/test/494-checker-instanceof-tests/src/Main.java b/test/494-checker-instanceof-tests/src/Main.java
new file mode 100644
index 0000000000..bff9c72ded
--- /dev/null
+++ b/test/494-checker-instanceof-tests/src/Main.java
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+public class Main {
+ public static boolean $inline$classTypeTest(Object o) {
+ return o instanceof SubMain;
+ }
+
+ public static boolean $inline$interfaceTypeTest(Object o) {
+ return o instanceof Itf;
+ }
+
+ public static SubMain subMain;
+ public static Main mainField;
+ public static Unrelated unrelatedField;
+ public static FinalUnrelated finalUnrelatedField;
+
+ /// CHECK-START: boolean Main.classTypeTestNull() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean classTypeTestNull() {
+ return $inline$classTypeTest(null);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestExactMain() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean classTypeTestExactMain() {
+ return $inline$classTypeTest(new Main());
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestExactSubMain() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 1
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean classTypeTestExactSubMain() {
+ return $inline$classTypeTest(new SubMain());
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestSubMainOrNull() register (after)
+ /// CHECK-DAG: <<Value:z\d+>> NotEqual
+ /// CHECK-DAG: Return [<<Value>>]
+ public static boolean classTypeTestSubMainOrNull() {
+ return $inline$classTypeTest(subMain);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestMainOrNull() register (after)
+ /// CHECK-DAG: <<Value:z\d+>> InstanceOf
+ /// CHECK-DAG: Return [<<Value>>]
+ public static boolean classTypeTestMainOrNull() {
+ return $inline$classTypeTest(mainField);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestUnrelated() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean classTypeTestUnrelated() {
+ return $inline$classTypeTest(unrelatedField);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestFinalUnrelated() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean classTypeTestFinalUnrelated() {
+ return $inline$classTypeTest(finalUnrelatedField);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestNull() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean interfaceTypeTestNull() {
+ return $inline$interfaceTypeTest(null);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestExactMain() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean interfaceTypeTestExactMain() {
+ return $inline$interfaceTypeTest(new Main());
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestExactSubMain() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 1
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean interfaceTypeTestExactSubMain() {
+ return $inline$interfaceTypeTest(new SubMain());
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestSubMainOrNull() register (after)
+ /// CHECK-DAG: <<Value:z\d+>> NotEqual
+ /// CHECK-DAG: Return [<<Value>>]
+ public static boolean interfaceTypeTestSubMainOrNull() {
+ return $inline$interfaceTypeTest(subMain);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestMainOrNull() register (after)
+ /// CHECK-DAG: <<Value:z\d+>> InstanceOf
+ /// CHECK-DAG: Return [<<Value>>]
+ public static boolean interfaceTypeTestMainOrNull() {
+ return $inline$interfaceTypeTest(mainField);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestUnrelated() register (after)
+ /// CHECK-DAG: <<Value:z\d+>> InstanceOf
+ /// CHECK-DAG: Return [<<Value>>]
+ public static boolean interfaceTypeTestUnrelated() {
+ // This method is the main difference between doing an instanceof on an interface
+ // or a class. We have to keep the instanceof in case a subclass of Unrelated
+ // implements the interface.
+ return $inline$interfaceTypeTest(unrelatedField);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestFinalUnrelated() register (after)
+ /// CHECK-DAG: <<Const:i\d+>> IntConstant 0
+ /// CHECK-DAG: Return [<<Const>>]
+ public static boolean interfaceTypeTestFinalUnrelated() {
+ return $inline$interfaceTypeTest(finalUnrelatedField);
+ }
+
+ public static void expect(boolean expected, boolean actual) {
+ if (expected != actual) {
+ throw new Error("Unexpected result");
+ }
+ }
+
+ public static void main(String[] args) {
+ expect(false, classTypeTestNull());
+ expect(false, classTypeTestExactMain());
+ expect(true, classTypeTestExactSubMain());
+
+ subMain = null;
+ expect(false, classTypeTestSubMainOrNull());
+ subMain = new SubMain();
+ expect(true, classTypeTestSubMainOrNull());
+
+ mainField = null;
+ expect(false, classTypeTestMainOrNull());
+ mainField = new Main();
+ expect(false, classTypeTestMainOrNull());
+ mainField = new SubMain();
+ expect(true, classTypeTestMainOrNull());
+
+ unrelatedField = null;
+ expect(false, classTypeTestUnrelated());
+ unrelatedField = new Unrelated();
+ expect(false, classTypeTestUnrelated());
+
+ finalUnrelatedField = null;
+ expect(false, classTypeTestFinalUnrelated());
+ finalUnrelatedField = new FinalUnrelated();
+ expect(false, classTypeTestFinalUnrelated());
+
+ expect(false, interfaceTypeTestNull());
+ expect(false, interfaceTypeTestExactMain());
+ expect(true, interfaceTypeTestExactSubMain());
+
+ subMain = null;
+ expect(false, interfaceTypeTestSubMainOrNull());
+ subMain = new SubMain();
+ expect(true, interfaceTypeTestSubMainOrNull());
+
+ mainField = null;
+ expect(false, interfaceTypeTestMainOrNull());
+ mainField = new Main();
+ expect(false, interfaceTypeTestMainOrNull());
+ mainField = new SubMain();
+ expect(true, interfaceTypeTestMainOrNull());
+
+ unrelatedField = null;
+ expect(false, interfaceTypeTestUnrelated());
+ unrelatedField = new Unrelated();
+ expect(false, interfaceTypeTestUnrelated());
+
+ finalUnrelatedField = null;
+ expect(false, interfaceTypeTestFinalUnrelated());
+ finalUnrelatedField = new FinalUnrelated();
+ expect(false, interfaceTypeTestFinalUnrelated());
+ }
+}
+
+interface Itf {
+}
+
+class SubMain extends Main implements Itf {
+}
+
+class Unrelated {
+}
+
+final class FinalUnrelated {
+}
diff --git a/test/495-checker-checkcast-tests/expected.txt b/test/495-checker-checkcast-tests/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/495-checker-checkcast-tests/expected.txt
diff --git a/test/495-checker-checkcast-tests/info.txt b/test/495-checker-checkcast-tests/info.txt
new file mode 100644
index 0000000000..4517b22c69
--- /dev/null
+++ b/test/495-checker-checkcast-tests/info.txt
@@ -0,0 +1 @@
+Checker tests for optimizations on checkcast.
diff --git a/test/495-checker-checkcast-tests/src/Main.java b/test/495-checker-checkcast-tests/src/Main.java
new file mode 100644
index 0000000000..aa6d5a75f7
--- /dev/null
+++ b/test/495-checker-checkcast-tests/src/Main.java
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+public class Main {
+ public static boolean $inline$classTypeTest(Object o) {
+ return ((SubMain)o) == o;
+ }
+
+ public static boolean $inline$interfaceTypeTest(Object o) {
+ return ((Itf)o) == o;
+ }
+
+ public static SubMain subMain;
+ public static Main mainField;
+ public static Unrelated unrelatedField;
+ public static FinalUnrelated finalUnrelatedField;
+
+ /// CHECK-START: boolean Main.classTypeTestNull() register (after)
+ /// CHECK-NOT: CheckCast
+ public static boolean classTypeTestNull() {
+ return $inline$classTypeTest(null);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestExactMain() register (after)
+ /// CHECK: CheckCast
+ public static boolean classTypeTestExactMain() {
+ return $inline$classTypeTest(new Main());
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestExactSubMain() register (after)
+ /// CHECK-NOT: CheckCast
+ public static boolean classTypeTestExactSubMain() {
+ return $inline$classTypeTest(new SubMain());
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestSubMainOrNull() register (after)
+ /// CHECK-NOT: CheckCast
+ public static boolean classTypeTestSubMainOrNull() {
+ return $inline$classTypeTest(subMain);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestMainOrNull() register (after)
+ /// CHECK: CheckCast
+ public static boolean classTypeTestMainOrNull() {
+ return $inline$classTypeTest(mainField);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestUnrelated() register (after)
+ /// CHECK: CheckCast
+ public static boolean classTypeTestUnrelated() {
+ return $inline$classTypeTest(unrelatedField);
+ }
+
+ /// CHECK-START: boolean Main.classTypeTestFinalUnrelated() register (after)
+ /// CHECK: CheckCast
+ public static boolean classTypeTestFinalUnrelated() {
+ return $inline$classTypeTest(finalUnrelatedField);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestNull() register (after)
+ /// CHECK-NOT: CheckCast
+ public static boolean interfaceTypeTestNull() {
+ return $inline$interfaceTypeTest(null);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestExactMain() register (after)
+ /// CHECK: CheckCast
+ public static boolean interfaceTypeTestExactMain() {
+ return $inline$interfaceTypeTest(new Main());
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestExactSubMain() register (after)
+ /// CHECK-NOT: CheckCast
+ public static boolean interfaceTypeTestExactSubMain() {
+ return $inline$interfaceTypeTest(new SubMain());
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestSubMainOrNull() register (after)
+ /// CHECK-NOT: CheckCast
+ public static boolean interfaceTypeTestSubMainOrNull() {
+ return $inline$interfaceTypeTest(subMain);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestMainOrNull() register (after)
+ /// CHECK: CheckCast
+ public static boolean interfaceTypeTestMainOrNull() {
+ return $inline$interfaceTypeTest(mainField);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestUnrelated() register (after)
+ /// CHECK: CheckCast
+ public static boolean interfaceTypeTestUnrelated() {
+ return $inline$interfaceTypeTest(unrelatedField);
+ }
+
+ /// CHECK-START: boolean Main.interfaceTypeTestFinalUnrelated() register (after)
+ /// CHECK: CheckCast
+ public static boolean interfaceTypeTestFinalUnrelated() {
+ return $inline$interfaceTypeTest(finalUnrelatedField);
+ }
+
+ public static void main(String[] args) {
+ classTypeTestNull();
+ try {
+ classTypeTestExactMain();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+ classTypeTestExactSubMain();
+
+ subMain = null;
+ classTypeTestSubMainOrNull();
+ subMain = new SubMain();
+ classTypeTestSubMainOrNull();
+
+ mainField = null;
+ classTypeTestMainOrNull();
+ mainField = new Main();
+ try {
+ classTypeTestMainOrNull();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+ mainField = new SubMain();
+ classTypeTestMainOrNull();
+
+ unrelatedField = null;
+ classTypeTestUnrelated();
+ unrelatedField = new Unrelated();
+ try {
+ classTypeTestUnrelated();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+
+ finalUnrelatedField = null;
+ classTypeTestFinalUnrelated();
+ finalUnrelatedField = new FinalUnrelated();
+ try {
+ classTypeTestFinalUnrelated();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+
+ interfaceTypeTestNull();
+ try {
+ interfaceTypeTestExactMain();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+ interfaceTypeTestExactSubMain();
+
+ subMain = null;
+ interfaceTypeTestSubMainOrNull();
+ subMain = new SubMain();
+ interfaceTypeTestSubMainOrNull();
+
+ mainField = null;
+ interfaceTypeTestMainOrNull();
+ mainField = new Main();
+ try {
+ interfaceTypeTestMainOrNull();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+ mainField = new SubMain();
+ interfaceTypeTestMainOrNull();
+
+ unrelatedField = null;
+ interfaceTypeTestUnrelated();
+ unrelatedField = new Unrelated();
+ try {
+ interfaceTypeTestUnrelated();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+
+ finalUnrelatedField = null;
+ interfaceTypeTestFinalUnrelated();
+ finalUnrelatedField = new FinalUnrelated();
+ try {
+ interfaceTypeTestFinalUnrelated();
+ throw new Error("ClassCastException expected");
+ } catch (ClassCastException e) {}
+ }
+}
+
+interface Itf {
+}
+
+class SubMain extends Main implements Itf {
+}
+
+class Unrelated {
+}
+
+final class FinalUnrelated {
+}
diff --git a/test/496-checker-inlining-and-class-loader/expected.txt b/test/496-checker-inlining-and-class-loader/expected.txt
new file mode 100644
index 0000000000..c6fcb51ecf
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/expected.txt
@@ -0,0 +1,4 @@
+Request for LoadedByMyClassLoader
+Request for Main
+In between the two calls.
+In $noinline$bar
diff --git a/test/496-checker-inlining-and-class-loader/info.txt b/test/496-checker-inlining-and-class-loader/info.txt
new file mode 100644
index 0000000000..aa4b256207
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/info.txt
@@ -0,0 +1,2 @@
+Regression test to ensure compilers preserve JLS
+semantics of class loading.
diff --git a/test/496-checker-inlining-and-class-loader/src/Main.java b/test/496-checker-inlining-and-class-loader/src/Main.java
new file mode 100644
index 0000000000..f6d0b41a58
--- /dev/null
+++ b/test/496-checker-inlining-and-class-loader/src/Main.java
@@ -0,0 +1,125 @@
+/*
+ * 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.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+class MyClassLoader extends ClassLoader {
+ MyClassLoader() throws Exception {
+ super(MyClassLoader.class.getClassLoader());
+
+ // Some magic to get access to the pathList field of BaseDexClassLoader.
+ ClassLoader loader = getClass().getClassLoader();
+ Class<?> baseDexClassLoader = loader.getClass().getSuperclass();
+ Field f = baseDexClassLoader.getDeclaredField("pathList");
+ f.setAccessible(true);
+ Object pathList = f.get(loader);
+
+ // Some magic to get access to the dexField field of pathList.
+ f = pathList.getClass().getDeclaredField("dexElements");
+ f.setAccessible(true);
+ dexElements = (Object[]) f.get(pathList);
+ dexFileField = dexElements[0].getClass().getDeclaredField("dexFile");
+ dexFileField.setAccessible(true);
+ }
+
+ Object[] dexElements;
+ Field dexFileField;
+
+ protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
+ System.out.println("Request for " + className);
+
+ // We're only going to handle LoadedByMyClassLoader.
+ if (className != "LoadedByMyClassLoader") {
+ return getParent().loadClass(className);
+ }
+
+ // Mimic what DexPathList.findClass is doing.
+ try {
+ for (Object element : dexElements) {
+ Object dex = dexFileField.get(element);
+ Method method = dex.getClass().getDeclaredMethod(
+ "loadClassBinaryName", String.class, ClassLoader.class, List.class);
+
+ if (dex != null) {
+ Class clazz = (Class)method.invoke(dex, className, this, null);
+ if (clazz != null) {
+ return clazz;
+ }
+ }
+ }
+ } catch (Exception e) { /* Ignore */ }
+ return null;
+ }
+}
+
+class LoadedByMyClassLoader {
+ /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (before)
+ /// CHECK: LoadClass
+ /// CHECK-NEXT: ClinitCheck
+ /// CHECK-NEXT: InvokeStaticOrDirect
+ /// CHECK-NEXT: LoadClass
+ /// CHECK-NEXT: ClinitCheck
+ /// CHECK-NEXT: StaticFieldGet
+ /// CHECK-NEXT: LoadString
+ /// CHECK-NEXT: NullCheck
+ /// CHECK-NEXT: InvokeVirtual
+
+ /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (after)
+ /// CHECK: LoadClass
+ /// CHECK-NEXT: ClinitCheck
+ /* We inlined Main.$inline$bar */
+ /// CHECK-NEXT: LoadClass
+ /// CHECK-NEXT: ClinitCheck
+ /// CHECK-NEXT: StaticFieldGet
+ /// CHECK-NEXT: LoadString
+ /// CHECK-NEXT: NullCheck
+ /// CHECK-NEXT: InvokeVirtual
+
+ /// CHECK-START: void LoadedByMyClassLoader.bar() register (before)
+ /* Load and initialize Main */
+ /// CHECK: LoadClass gen_clinit_check:true
+ /* Load and initialize System */
+ /// CHECK-NEXT: LoadClass gen_clinit_check:true
+ /// CHECK-NEXT: StaticFieldGet
+ /// CHECK-NEXT: LoadString
+ /// CHECK-NEXT: NullCheck
+ /// CHECK-NEXT: InvokeVirtual
+ public static void bar() {
+ Main.$inline$bar();
+ System.out.println("In between the two calls.");
+ Main.$noinline$bar();
+ }
+}
+
+class Main {
+ public static void main(String[] args) throws Exception {
+ MyClassLoader o = new MyClassLoader();
+ Class foo = o.loadClass("LoadedByMyClassLoader");
+ Method m = foo.getDeclaredMethod("bar");
+ m.invoke(null);
+ }
+
+ public static void $inline$bar() {
+ }
+
+ public static void $noinline$bar() {
+ try {
+ System.out.println("In $noinline$bar");
+ } catch (Throwable t) { /* Ignore */ }
+ }
+}
diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc
new file mode 100644
index 0000000000..f9b33a2874
--- /dev/null
+++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+#include "art_method-inl.h"
+#include "jni.h"
+#include "scoped_thread_state_change.h"
+#include "stack.h"
+#include "thread.h"
+
+namespace art {
+
+namespace {
+
+extern "C" JNIEXPORT jobject JNICALL Java_Main_cloneResolvedMethods(JNIEnv*, jclass, jclass cls) {
+ ScopedObjectAccess soa(Thread::Current());
+ return soa.Vm()->AddGlobalRef(
+ soa.Self(),
+ soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetResolvedMethods()->Clone(soa.Self()));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_restoreResolvedMethods(
+ JNIEnv*, jclass, jclass cls, jobject old_cache) {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::PointerArray* now = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetResolvedMethods();
+ mirror::PointerArray* old = soa.Decode<mirror::PointerArray*>(old_cache);
+ for (size_t i = 0, e = old->GetLength(); i < e; ++i) {
+ now->SetElementPtrSize(i, old->GetElementPtrSize<void*>(i, sizeof(void*)), sizeof(void*));
+ }
+}
+
+} // namespace
+
+} // namespace art
diff --git a/test/497-inlining-and-class-loader/expected.txt b/test/497-inlining-and-class-loader/expected.txt
new file mode 100644
index 0000000000..3e1d85e309
--- /dev/null
+++ b/test/497-inlining-and-class-loader/expected.txt
@@ -0,0 +1,7 @@
+java.lang.Exception
+ at Main.$noinline$bar(Main.java:127)
+ at Level2.$inline$bar(Level1.java:25)
+ at Level1.$inline$bar(Level1.java:19)
+ at LoadedByMyClassLoader.bar(Main.java:82)
+ at java.lang.reflect.Method.invoke(Native Method)
+ at Main.main(Main.java:101)
diff --git a/test/497-inlining-and-class-loader/info.txt b/test/497-inlining-and-class-loader/info.txt
new file mode 100644
index 0000000000..e7f02aaf34
--- /dev/null
+++ b/test/497-inlining-and-class-loader/info.txt
@@ -0,0 +1,2 @@
+Regression test for optimizing to ensure it is using
+the correct class loader when walking inlined frames.
diff --git a/test/497-inlining-and-class-loader/src/Level1.java b/test/497-inlining-and-class-loader/src/Level1.java
new file mode 100644
index 0000000000..977af8321e
--- /dev/null
+++ b/test/497-inlining-and-class-loader/src/Level1.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+public class Level1 {
+ public static void $inline$bar() {
+ Level2.$inline$bar();
+ }
+}
+
+class Level2 {
+ public static void $inline$bar() {
+ Main.$noinline$bar();
+ }
+}
diff --git a/test/497-inlining-and-class-loader/src/Main.java b/test/497-inlining-and-class-loader/src/Main.java
new file mode 100644
index 0000000000..0f7eb599cb
--- /dev/null
+++ b/test/497-inlining-and-class-loader/src/Main.java
@@ -0,0 +1,133 @@
+/*
+ * 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.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+class MyClassLoader extends ClassLoader {
+ MyClassLoader() throws Exception {
+ super(MyClassLoader.class.getClassLoader());
+
+ // Some magic to get access to the pathList field of BaseDexClassLoader.
+ ClassLoader loader = getClass().getClassLoader();
+ Class<?> baseDexClassLoader = loader.getClass().getSuperclass();
+ Field f = baseDexClassLoader.getDeclaredField("pathList");
+ f.setAccessible(true);
+ Object pathList = f.get(loader);
+
+ // Some magic to get access to the dexField field of pathList.
+ f = pathList.getClass().getDeclaredField("dexElements");
+ f.setAccessible(true);
+ dexElements = (Object[]) f.get(pathList);
+ dexFileField = dexElements[0].getClass().getDeclaredField("dexFile");
+ dexFileField.setAccessible(true);
+ }
+
+ Object[] dexElements;
+ Field dexFileField;
+
+ static ClassLoader level1ClassLoader;
+
+ protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
+ if (this != level1ClassLoader) {
+ if (className.equals("Level1")) {
+ return level1ClassLoader.loadClass(className);
+ } else if (className.equals("Level2")) {
+ throw new ClassNotFoundException("None of my methods require Level2!");
+ } else if (!className.equals("LoadedByMyClassLoader")) {
+ // We're only going to handle LoadedByMyClassLoader.
+ return getParent().loadClass(className);
+ }
+ } else {
+ if (className != "Level1" && className != "Level2") {
+ return getParent().loadClass(className);
+ }
+ }
+
+ // Mimic what DexPathList.findClass is doing.
+ try {
+ for (Object element : dexElements) {
+ Object dex = dexFileField.get(element);
+ Method method = dex.getClass().getDeclaredMethod(
+ "loadClassBinaryName", String.class, ClassLoader.class, List.class);
+
+ if (dex != null) {
+ Class clazz = (Class)method.invoke(dex, className, this, null);
+ if (clazz != null) {
+ return clazz;
+ }
+ }
+ }
+ } catch (Exception e) { /* Ignore */ }
+ return null;
+ }
+}
+
+class LoadedByMyClassLoader {
+ public static void bar() {
+ Level1.$inline$bar();
+ }
+}
+
+class Main {
+ static {
+ System.loadLibrary("arttest");
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Clone resolved methods, to restore the original version just
+ // before we walk the stack in $noinline$bar.
+ savedResolvedMethods = cloneResolvedMethods(Main.class);
+
+ MyClassLoader o = new MyClassLoader();
+ MyClassLoader.level1ClassLoader = new MyClassLoader();
+ Class foo = o.loadClass("LoadedByMyClassLoader");
+ Method m = foo.getDeclaredMethod("bar");
+ try {
+ m.invoke(null);
+ } catch (Error e) { /* Ignore */ }
+ }
+
+ public static void $inline$bar() {
+ }
+
+ public static void $noinline$bar() {
+ try {
+ // Be evil and clear all dex cache entries.
+ Field f = Class.class.getDeclaredField("dexCache");
+ f.setAccessible(true);
+ Object dexCache = f.get(Main.class);
+ f = dexCache.getClass().getDeclaredField("resolvedTypes");
+ f.setAccessible(true);
+ Object[] array = (Object[]) f.get(dexCache);
+ for (int i = 0; i < array.length; i++) {
+ array[i] = null;
+ }
+ restoreResolvedMethods(Main.class, savedResolvedMethods);
+ } catch (Throwable t) { /* Ignore */ }
+
+ // This will walk the stack, trying to resolve methods in it.
+ // Because we cleared dex cache entries, we will have to find
+ // classes again, which require to use the correct class loader
+ // in the presence of inlining.
+ new Exception().printStackTrace();
+ }
+ static Object savedResolvedMethods;
+
+ static native Object cloneResolvedMethods(Class<?> cls);
+ static native void restoreResolvedMethods(Class<?> cls, Object saved);
+}
diff --git a/test/498-type-propagation/expected.txt b/test/498-type-propagation/expected.txt
new file mode 100644
index 0000000000..ccaf6f8f0f
--- /dev/null
+++ b/test/498-type-propagation/expected.txt
@@ -0,0 +1 @@
+Enter
diff --git a/test/498-type-propagation/info.txt b/test/498-type-propagation/info.txt
new file mode 100644
index 0000000000..b895e91f9d
--- /dev/null
+++ b/test/498-type-propagation/info.txt
@@ -0,0 +1,2 @@
+Regression test for the SSA building of the optimizing
+compiler. See comment in smali file.
diff --git a/test/498-type-propagation/smali/TypePropagation.smali b/test/498-type-propagation/smali/TypePropagation.smali
new file mode 100644
index 0000000000..088ca89985
--- /dev/null
+++ b/test/498-type-propagation/smali/TypePropagation.smali
@@ -0,0 +1,30 @@
+# 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.
+
+.class public LTypePropagation;
+
+.super Ljava/lang/Object;
+
+.method public static method([I)V
+ .registers 2
+ const/4 v0, 0
+ # When building the SSA graph, we will create a phi for v0, which will be of type
+ # integer. Only when we get rid of that phi in the redundant phi elimination will
+ # we realize it's just null.
+ :start
+ if-eq v1, v0, :end
+ if-eq v1, v0, :start
+ :end
+ return-void
+.end method
diff --git a/test/498-type-propagation/src/Main.java b/test/498-type-propagation/src/Main.java
new file mode 100644
index 0000000000..7a14172bf5
--- /dev/null
+++ b/test/498-type-propagation/src/Main.java
@@ -0,0 +1,29 @@
+/*
+ * 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 static void main(String[] args) throws Exception {
+ // Workaround for b/18051191.
+ System.out.println("Enter");
+ Class<?> c = Class.forName("TypePropagation");
+ Method m = c.getMethod("method", int[].class);
+ int[] array = new int[7];
+ Object[] arguments = { array };
+ m.invoke(null, arguments);
+ }
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index a6b216bf3a..85656374c5 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -16,4 +16,5 @@ MoveExc
MoveExceptionOnEntry
EmptySparseSwitch
b/20224106
+b/17410612
Done!
diff --git a/test/800-smali/smali/b_17410612.smali b/test/800-smali/smali/b_17410612.smali
new file mode 100644
index 0000000000..17718cbf60
--- /dev/null
+++ b/test/800-smali/smali/b_17410612.smali
@@ -0,0 +1,14 @@
+.class public LB17410612;
+
+# Test that an invoke with a long parameter has the long parameter in
+# a pair. This should fail in the verifier and not an abort in the compiler.
+
+.super Ljava/lang/Object;
+
+.method public static run()V
+ .registers 4
+ const-wide v0, 0 # Make (v0, v1) a long
+ const-wide v2, 0 # Make (v2, v3) a long
+ invoke-static {v0, v3}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;
+ return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 3e88364089..33df06d87a 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -81,6 +81,8 @@ public class Main {
null));
testCases.add(new TestCase("b/20224106", "B20224106", "run", null, new VerifyError(),
0));
+ testCases.add(new TestCase("b/17410612", "B17410612", "run", null, new VerifyError(),
+ 0));
}
public void runTests() {
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index 57d06c49cd..fcb9f8a779 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -34,7 +34,8 @@ LIBARTTEST_COMMON_SRC_FILES := \
455-set-vreg/set_vreg_jni.cc \
457-regs/regs_jni.cc \
461-get-reference-vreg/get_reference_vreg_jni.cc \
- 466-get-live-vreg/get_live_vreg_jni.cc
+ 466-get-live-vreg/get_live_vreg_jni.cc \
+ 497-inlining-and-class-loader/clear_dex_cache.cc
ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
ifdef TARGET_2ND_ARCH
@@ -74,6 +75,7 @@ define build-libarttest
else # host
LOCAL_CLANG := $(ART_HOST_CLANG)
LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
+ LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS)
LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread
LOCAL_IS_HOST_MODULE := true
LOCAL_MULTILIB := both
diff --git a/test/Android.libnativebridgetest.mk b/test/Android.libnativebridgetest.mk
index 5a5f72584f..e8cc7e45ce 100644
--- a/test/Android.libnativebridgetest.mk
+++ b/test/Android.libnativebridgetest.mk
@@ -60,6 +60,7 @@ define build-libnativebridgetest
else # host
LOCAL_CLANG := $(ART_HOST_CLANG)
LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
+ LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS)
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread
ifeq ($(HOST_OS),linux)
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index fa13fe5c64..469df1f2b6 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -229,16 +229,10 @@ endif
TEST_ART_BROKEN_NO_RELOCATE_TESTS :=
-# Tests that are broken with GC stress.
-TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
-
-ifneq (,$(filter gcstress,$(GC_TYPES)))
- ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
- $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),gcstress,$(JNI_TYPES), \
- $(IMAGE_TYPES), $(PICTEST_TYPES), $(DBEUGGABLE_TYPES), $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(ALL_ADDRESS_SIZES))
-endif
-
-TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
+# 098-ddmc is broken until we restore the old behavior of getRecentAllocation() of DDMS. b/20037135
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+ $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), 098-ddmc, $(ALL_ADDRESS_SIZES))
# 115-native-bridge setup is complicated. Need to implement it correctly for the target.
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES),$(COMPILER_TYPES), \
@@ -259,6 +253,11 @@ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),
$(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),131-structural-change,$(ALL_ADDRESS_SIZES))
+# 138-duplicate-classes-check. Turned off temporarily, b/21333911.
+ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+ $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES),$(IMAGE_TYPES), \
+ $(PICTEST_TYPES),$(DEBUGGABLE_TYPES),138-duplicate-classes-check,$(ALL_ADDRESS_SIZES))
+
# All these tests check that we have sane behavior if we don't have a patchoat or dex2oat.
# Therefore we shouldn't run them in situations where we actually don't have these since they
# explicitly test for them. These all also assume we have an image.
@@ -339,6 +338,7 @@ TEST_ART_BROKEN_NDEBUG_TESTS := \
457-regs \
461-get-reference-vreg \
466-get-live-vreg \
+ 497-inlining-and-class-loader \
ifneq (,$(filter ndebug,$(RUN_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),ndebug,$(PREBUILD_TYPES), \
@@ -377,7 +377,8 @@ TEST_ART_BROKEN_JIT_RUN_TESTS :=
# Known broken tests for the default compiler (Quick).
TEST_ART_BROKEN_DEFAULT_RUN_TESTS := \
- 457-regs
+ 457-regs \
+ 496-checker-inlining-and-class-loader
ifneq (,$(filter default,$(COMPILER_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -468,11 +469,6 @@ endif
TEST_ART_BROKEN_HEAP_POISONING_RUN_TESTS :=
-# Test 137-cfi works in 32-bit only until we enable 64-bit ELF files.
-ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
- $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
- $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES),137-cfi,64)
-
# Clear variables ahead of appending to them when defining tests.
$(foreach target, $(TARGET_TYPES), $(eval ART_RUN_TEST_$(call name-to-var,$(target))_RULES :=))
$(foreach target, $(TARGET_TYPES), \
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 240ed41ff2..09841bfcec 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -296,6 +296,10 @@ if [ "$RELOCATE" = "y" ]; then
else
FLAGS="$FLAGS -Xnorelocate"
COMPILE_FLAGS="${COMPILE_FLAGS} --runtime-arg -Xnorelocate"
+ if [ "$HOST" = "y" ]; then
+ # Increase ulimit to 64MB in case we are running hprof test.
+ ulimit -S 64000 || exit 1
+ fi
fi
if [ "$HOST" = "n" ]; then
diff --git a/test/run-test b/test/run-test
index ed3309923b..ed033217b8 100755
--- a/test/run-test
+++ b/test/run-test
@@ -96,6 +96,7 @@ basic_verify="false"
gc_verify="false"
gc_stress="false"
always_clean="no"
+never_clean="no"
have_dex2oat="yes"
have_patchoat="yes"
have_image="yes"
@@ -270,6 +271,9 @@ while true; do
elif [ "x$1" = "x--always-clean" ]; then
always_clean="yes"
shift
+ elif [ "x$1" = "x--never-clean" ]; then
+ never_clean="yes"
+ shift
elif [ "x$1" = "x--dex2oat-swap" ]; then
run_args="${run_args} --dex2oat-swap"
shift
@@ -472,6 +476,7 @@ if [ "$usage" = "yes" ]; then
echo " --gcstress Run with gc stress testing"
echo " --gcverify Run with gc verification"
echo " --always-clean Delete the test files even if the test fails."
+ echo " --never-clean Keep the test files even if the test succeeds."
echo " --android-root [path] The path on target for the android root. (/system by default)."
echo " --dex2oat-swap Use a dex2oat swap file."
) 1>&2
@@ -668,7 +673,7 @@ fi
) 1>&2
# Clean up test files.
-if [ "$always_clean" = "yes" -o "$good" = "yes" ]; then
+if [ "$always_clean" = "yes" -o "$good" = "yes" ] && [ "$never_clean" = "no" ]; then
cd "$oldwd"
rm -rf "$tmp_dir"
if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then