diff options
Diffstat (limited to 'test')
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 |