diff options
Diffstat (limited to 'test')
52 files changed, 1105 insertions, 53 deletions
diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt index 49d9cc0d5a..86ab37e1e5 100644 --- a/test/004-JniTest/expected.txt +++ b/test/004-JniTest/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called Super.<init> Super.<init> Subclass.<init> diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc index db0dd32771..be7888b04a 100644 --- a/test/004-JniTest/jni_test.cc +++ b/test/004-JniTest/jni_test.cc @@ -15,8 +15,9 @@ */ #include <assert.h> -#include <stdio.h> +#include <iostream> #include <pthread.h> +#include <stdio.h> #include <vector> #include "jni.h" @@ -27,13 +28,21 @@ static JavaVM* jvm = nullptr; -extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) { +extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void*) { assert(vm != nullptr); assert(jvm == nullptr); jvm = vm; + std::cout << "JNI_OnLoad called" << std::endl; return JNI_VERSION_1_6; } +extern "C" JNIEXPORT void JNI_OnUnload(JavaVM*, void*) { + // std::cout since LOG(INFO) adds extra stuff like pid. + std::cout << "JNI_OnUnload called" << std::endl; + // Clear jvm for assert in test 004-JniTest. + jvm = nullptr; +} + static void* AttachHelper(void* arg) { assert(jvm != nullptr); diff --git a/test/004-ReferenceMap/expected.txt b/test/004-ReferenceMap/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/004-ReferenceMap/expected.txt +++ b/test/004-ReferenceMap/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/004-SignalTest/expected.txt b/test/004-SignalTest/expected.txt index fd5ec00067..b3a0e1cbe0 100644 --- a/test/004-SignalTest/expected.txt +++ b/test/004-SignalTest/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called init signal test Caught NullPointerException Caught StackOverflowError diff --git a/test/004-StackWalk/expected.txt b/test/004-StackWalk/expected.txt index bde00246a3..5af68cd85d 100644 --- a/test/004-StackWalk/expected.txt +++ b/test/004-StackWalk/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called 1st call 172001234567891011121314151617181920652310201919 2nd call diff --git a/test/004-UnsafeTest/expected.txt b/test/004-UnsafeTest/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/004-UnsafeTest/expected.txt +++ b/test/004-UnsafeTest/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt index f86948ad6c..052c8faf1b 100644 --- a/test/044-proxy/expected.txt +++ b/test/044-proxy/expected.txt @@ -93,4 +93,5 @@ Invocation of public abstract java.lang.String NarrowingTest$I2.foo() Got expected exception Proxy narrowed invocation return type passed 5.8 +JNI_OnLoad called callback diff --git a/test/051-thread/expected.txt b/test/051-thread/expected.txt index 54e34af3aa..c6cd4f8bea 100644 --- a/test/051-thread/expected.txt +++ b/test/051-thread/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called thread test starting testThreadCapacity thread count: 512 testThreadDaemons starting thread 'TestDaemonThread' diff --git a/test/088-monitor-verification/expected.txt b/test/088-monitor-verification/expected.txt index 13b8c73970..f252f6f2ee 100644 --- a/test/088-monitor-verification/expected.txt +++ b/test/088-monitor-verification/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called recursiveSync ok nestedMayThrow ok constantLock ok diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt index 372ecd0484..b003307ab7 100644 --- a/test/115-native-bridge/expected.txt +++ b/test/115-native-bridge/expected.txt @@ -17,6 +17,7 @@ Test ART callbacks: all JNI function number is 11. name:testSignal, signature:()I, shorty:I. name:testZeroLengthByteBuffers, signature:()V, shorty:V. trampoline_JNI_OnLoad called! +JNI_OnLoad called Getting trampoline for Java_Main_testFindClassOnAttachedNativeThread with shorty V. trampoline_Java_Main_testFindClassOnAttachedNativeThread called! Getting trampoline for Java_Main_testFindFieldOnAttachedNativeThreadNative with shorty V. diff --git a/test/116-nodex2oat/expected.txt b/test/116-nodex2oat/expected.txt index 05b1c2f387..157dfc4ea4 100644 --- a/test/116-nodex2oat/expected.txt +++ b/test/116-nodex2oat/expected.txt @@ -1,6 +1,9 @@ Run -Xnodex2oat +JNI_OnLoad called Has oat is false, is dex2oat enabled is false. Run -Xdex2oat +JNI_OnLoad called Has oat is true, is dex2oat enabled is true. Run default +JNI_OnLoad called Has oat is true, is dex2oat enabled is true. diff --git a/test/117-nopatchoat/expected.txt b/test/117-nopatchoat/expected.txt index 5cc02d1662..0cd4715d09 100644 --- a/test/117-nopatchoat/expected.txt +++ b/test/117-nopatchoat/expected.txt @@ -1,9 +1,12 @@ Run without dex2oat/patchoat +JNI_OnLoad called dex2oat & patchoat are disabled, has oat is true, has executable oat is expected. This is a function call Run with dexoat/patchoat +JNI_OnLoad called dex2oat & patchoat are enabled, has oat is true, has executable oat is expected. This is a function call Run default +JNI_OnLoad called dex2oat & patchoat are enabled, has oat is true, has executable oat is expected. This is a function call diff --git a/test/118-noimage-dex2oat/expected.txt b/test/118-noimage-dex2oat/expected.txt index 0103e899f6..166481e96a 100644 --- a/test/118-noimage-dex2oat/expected.txt +++ b/test/118-noimage-dex2oat/expected.txt @@ -1,11 +1,14 @@ Run -Xnoimage-dex2oat +JNI_OnLoad called Has image is false, is image dex2oat enabled is false, is BOOTCLASSPATH on disk is false. testB18485243 PASS Run -Xnoimage-dex2oat -Xno-dex-file-fallback Failed to initialize runtime (check log for details) Run -Ximage-dex2oat +JNI_OnLoad called Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true. testB18485243 PASS Run default +JNI_OnLoad called Has image is true, is image dex2oat enabled is true, is BOOTCLASSPATH on disk is true. testB18485243 PASS diff --git a/test/119-noimage-patchoat/expected.txt b/test/119-noimage-patchoat/expected.txt index ed136621c3..9b9db58fcd 100644 --- a/test/119-noimage-patchoat/expected.txt +++ b/test/119-noimage-patchoat/expected.txt @@ -1,8 +1,11 @@ Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false +JNI_OnLoad called Has image is false, is image dex2oat enabled is false. Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false -Xno-dex-file-fallback Failed to initialize runtime (check log for details) Run -Ximage-dex2oat +JNI_OnLoad called Has image is true, is image dex2oat enabled is true. Run default +JNI_OnLoad called Has image is true, is image dex2oat enabled is true. diff --git a/test/137-cfi/expected.txt b/test/137-cfi/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/137-cfi/expected.txt +++ b/test/137-cfi/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/139-register-natives/expected.txt b/test/139-register-natives/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/139-register-natives/expected.txt +++ b/test/139-register-natives/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/141-class-unload/expected.txt b/test/141-class-unload/expected.txt new file mode 100644 index 0000000000..ff65a70b12 --- /dev/null +++ b/test/141-class-unload/expected.txt @@ -0,0 +1,18 @@ +1 +2 +JNI_OnLoad called +JNI_OnUnload called +1 +2 +JNI_OnLoad called +JNI_OnUnload called +null +null +JNI_OnLoad called +JNI_OnUnload called +null +loader null false +loader null false +JNI_OnLoad called +JNI_OnUnload called +null diff --git a/test/141-class-unload/info.txt b/test/141-class-unload/info.txt new file mode 100644 index 0000000000..d8dd381dc7 --- /dev/null +++ b/test/141-class-unload/info.txt @@ -0,0 +1 @@ +Test that classes get freed after they are no longer reachable. diff --git a/test/141-class-unload/jni_unload.cc b/test/141-class-unload/jni_unload.cc new file mode 100644 index 0000000000..d913efe53e --- /dev/null +++ b/test/141-class-unload/jni_unload.cc @@ -0,0 +1,37 @@ +/* + * 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 "jni.h" + +#include <iostream> + +#include "jit/jit.h" +#include "jit/jit_instrumentation.h" +#include "runtime.h" +#include "thread-inl.h" + +namespace art { +namespace { + +extern "C" JNIEXPORT void JNICALL Java_IntHolder_waitForCompilation(JNIEnv*, jclass) { + jit::Jit* jit = Runtime::Current()->GetJit(); + if (jit != nullptr) { + jit->GetInstrumentationCache()->WaitForCompilationToFinish(Thread::Current()); + } +} + +} // namespace +} // namespace art diff --git a/test/141-class-unload/src-ex/IntHolder.java b/test/141-class-unload/src-ex/IntHolder.java new file mode 100644 index 0000000000..e4aa6b8949 --- /dev/null +++ b/test/141-class-unload/src-ex/IntHolder.java @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// Simple class that holds a static int for testing that class unloading works +// and re-runs the class initializer. +public class IntHolder { + private static int value = 1; + + public static void setValue(int newValue) { + value = newValue; + } + + public static int getValue() { + return value; + } + + public static void runGC() { + Runtime.getRuntime().gc(); + } + + public static void loadLibrary(String name) { + System.loadLibrary(name); + } + + public static native void waitForCompilation(); +} diff --git a/test/141-class-unload/src/Main.java b/test/141-class-unload/src/Main.java new file mode 100644 index 0000000000..105a2b981c --- /dev/null +++ b/test/141-class-unload/src/Main.java @@ -0,0 +1,154 @@ +/* + * 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.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +public class Main { + static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/141-class-unload-ex.jar"; + static String nativeLibraryName; + + public static void main(String[] args) throws Exception { + nativeLibraryName = args[0]; + Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); + if (pathClassLoader == null) { + throw new AssertionError("Couldn't find path class loader class"); + } + Constructor constructor = + pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class); + try { + testUnloadClass(constructor); + testUnloadLoader(constructor); + // Test that we don't unload if we have a Method keeping the class live. + testNoUnloadInvoke(constructor); + // Test that we don't unload if we have an instance. + testNoUnloadInstance(constructor); + // Test JNI_OnLoad and JNI_OnUnload. + testLoadAndUnloadLibrary(constructor); + // Stress test to make sure we dont leak memory. + stressTest(constructor); + } catch (Exception e) { + System.out.println(e); + } + } + + private static void stressTest(Constructor constructor) throws Exception { + for (int i = 0; i <= 100; ++i) { + setUpUnloadLoader(constructor, false); + if (i % 10 == 0) { + Runtime.getRuntime().gc(); + } + } + } + + private static void testUnloadClass(Constructor constructor) throws Exception { + WeakReference<Class> klass = setUpUnloadClass(constructor); + // No strong refernces to class loader, should get unloaded. + Runtime.getRuntime().gc(); + WeakReference<Class> klass2 = setUpUnloadClass(constructor); + Runtime.getRuntime().gc(); + // If the weak reference is cleared, then it was unloaded. + System.out.println(klass.get()); + System.out.println(klass2.get()); + } + + private static void testUnloadLoader(Constructor constructor) + throws Exception { + WeakReference<ClassLoader> loader = setUpUnloadLoader(constructor, true); + // No strong refernces to class loader, should get unloaded. + Runtime.getRuntime().gc(); + // If the weak reference is cleared, then it was unloaded. + System.out.println(loader.get()); + } + + private static void testLoadAndUnloadLibrary(Constructor constructor) throws Exception { + WeakReference<ClassLoader> loader = setUpLoadLibrary(constructor); + // No strong refernces to class loader, should get unloaded. + Runtime.getRuntime().gc(); + // If the weak reference is cleared, then it was unloaded. + System.out.println(loader.get()); + } + + private static void testNoUnloadInvoke(Constructor constructor) throws Exception { + WeakReference<ClassLoader> loader = + new WeakReference((ClassLoader) constructor.newInstance( + DEX_FILE, ClassLoader.getSystemClassLoader())); + WeakReference<Class> intHolder = new WeakReference(loader.get().loadClass("IntHolder")); + intHolder.get().getDeclaredMethod("runGC").invoke(intHolder.get()); + boolean isNull = loader.get() == null; + System.out.println("loader null " + isNull); + } + + private static void testNoUnloadInstance(Constructor constructor) throws Exception { + WeakReference<ClassLoader> loader = + new WeakReference((ClassLoader) constructor.newInstance( + DEX_FILE, ClassLoader.getSystemClassLoader())); + WeakReference<Class> intHolder = new WeakReference(loader.get().loadClass("IntHolder")); + Object o = intHolder.get().newInstance(); + Runtime.getRuntime().gc(); + boolean isNull = loader.get() == null; + System.out.println("loader null " + isNull); + } + + private static WeakReference<Class> setUpUnloadClass(Constructor constructor) throws Exception { + ClassLoader loader = (ClassLoader) constructor.newInstance( + DEX_FILE, ClassLoader.getSystemClassLoader()); + Class intHolder = loader.loadClass("IntHolder"); + Method getValue = intHolder.getDeclaredMethod("getValue"); + Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE); + // Make sure we don't accidentally preserve the value in the int holder, the class + // initializer should be re-run. + System.out.println((int) getValue.invoke(intHolder)); + setValue.invoke(intHolder, 2); + System.out.println((int) getValue.invoke(intHolder)); + waitForCompilation(intHolder); + return new WeakReference(intHolder); + } + + private static WeakReference<ClassLoader> setUpUnloadLoader(Constructor constructor, + boolean waitForCompilation) + throws Exception { + ClassLoader loader = (ClassLoader) constructor.newInstance( + DEX_FILE, ClassLoader.getSystemClassLoader()); + Class intHolder = loader.loadClass("IntHolder"); + Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE); + setValue.invoke(intHolder, 2); + if (waitForCompilation) { + waitForCompilation(intHolder); + } + return new WeakReference(loader); + } + + private static void waitForCompilation(Class intHolder) throws Exception { + // Load the native library so that we can call waitForCompilation. + Method loadLibrary = intHolder.getDeclaredMethod("loadLibrary", String.class); + loadLibrary.invoke(intHolder, nativeLibraryName); + // Wait for JIT compilation to finish since the async threads may prevent unloading. + Method waitForCompilation = intHolder.getDeclaredMethod("waitForCompilation"); + waitForCompilation.invoke(intHolder); + } + + private static WeakReference<ClassLoader> setUpLoadLibrary(Constructor constructor) + throws Exception { + ClassLoader loader = (ClassLoader) constructor.newInstance( + DEX_FILE, ClassLoader.getSystemClassLoader()); + Class intHolder = loader.loadClass("IntHolder"); + Method loadLibrary = intHolder.getDeclaredMethod("loadLibrary", String.class); + loadLibrary.invoke(intHolder, nativeLibraryName); + return new WeakReference(loader); + } +} diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java index a746664160..f06c250dc7 100644 --- a/test/449-checker-bce/src/Main.java +++ b/test/449-checker-bce/src/Main.java @@ -249,6 +249,25 @@ public class Main { array[Integer.MAX_VALUE - 998] = 1; } + /// CHECK-START: void Main.constantIndexing6(int[]) BCE (before) + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + + /// CHECK-START: void Main.constantIndexing6(int[]) BCE (after) + /// CHECK: Deoptimize + + static void constantIndexing6(int[] array) { + array[3] = 1; + array[4] = 1; + } + + // A helper into which the actual throwing function should be inlined. + static void constantIndexingForward6(int[] array) { + constantIndexing6(array); + } + /// CHECK-START: void Main.loopPattern1(int[]) BCE (before) /// CHECK: BoundsCheck /// CHECK: ArraySet @@ -602,7 +621,12 @@ public class Main { // This will cause AIOOBE. constantIndexing2(new int[3]); } catch (ArrayIndexOutOfBoundsException e) { - return 99; + try { + // This will cause AIOOBE. + constantIndexingForward6(new int[3]); + } catch (ArrayIndexOutOfBoundsException e2) { + return 99; + } } return 0; } diff --git a/test/454-get-vreg/expected.txt b/test/454-get-vreg/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/454-get-vreg/expected.txt +++ b/test/454-get-vreg/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/455-set-vreg/expected.txt b/test/455-set-vreg/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/455-set-vreg/expected.txt +++ b/test/455-set-vreg/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/457-regs/expected.txt b/test/457-regs/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/457-regs/expected.txt +++ b/test/457-regs/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/461-get-reference-vreg/expected.txt b/test/461-get-reference-vreg/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/461-get-reference-vreg/expected.txt +++ b/test/461-get-reference-vreg/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/466-get-live-vreg/expected.txt b/test/466-get-live-vreg/expected.txt index e69de29bb2..6a5618ebc6 100644 --- a/test/466-get-live-vreg/expected.txt +++ b/test/466-get-live-vreg/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/485-checker-dce-switch/expected.txt b/test/485-checker-dce-switch/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/485-checker-dce-switch/expected.txt diff --git a/test/485-checker-dce-switch/info.txt b/test/485-checker-dce-switch/info.txt new file mode 100644 index 0000000000..6653526827 --- /dev/null +++ b/test/485-checker-dce-switch/info.txt @@ -0,0 +1 @@ +Tests that DCE can remove a packed switch. diff --git a/test/485-checker-dce-switch/src/Main.java b/test/485-checker-dce-switch/src/Main.java new file mode 100644 index 0000000000..019d876ec8 --- /dev/null +++ b/test/485-checker-dce-switch/src/Main.java @@ -0,0 +1,192 @@ +/* + * 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 int $inline$method() { + return 5; + } + + /// CHECK-START: int Main.wholeSwitchDead(int) dead_code_elimination_final (before) + /// CHECK-DAG: PackedSwitch + + /// CHECK-START: int Main.wholeSwitchDead(int) dead_code_elimination_final (after) + /// CHECK-DAG: <<Const100:i\d+>> IntConstant 100 + /// CHECK-DAG: Return [<<Const100>>] + + /// CHECK-START: int Main.wholeSwitchDead(int) dead_code_elimination_final (after) + /// CHECK-NOT: PackedSwitch + + public static int wholeSwitchDead(int j) { + int i = $inline$method(); + int l = 100; + if (i > 100) { + switch(j) { + case 1: + i++; + break; + case 2: + i = 99; + break; + case 3: + i = 100; + break; + case 4: + i = -100; + break; + case 5: + i = 7; + break; + case 6: + i = -9; + break; + } + l += i; + } + + return l; + } + + /// CHECK-START: int Main.constantSwitch_InRange() dead_code_elimination_final (before) + /// CHECK-DAG: PackedSwitch + + /// CHECK-START: int Main.constantSwitch_InRange() dead_code_elimination_final (after) + /// CHECK-DAG: <<Const7:i\d+>> IntConstant 7 + /// CHECK-DAG: Return [<<Const7>>] + + /// CHECK-START: int Main.constantSwitch_InRange() dead_code_elimination_final (after) + /// CHECK-NOT: PackedSwitch + + public static int constantSwitch_InRange() { + int i = $inline$method(); + switch(i) { + case 1: + i++; + break; + case 2: + i = 99; + break; + case 3: + i = 100; + break; + case 4: + i = -100; + break; + case 5: + i = 7; + break; + case 6: + i = -9; + break; + } + + return i; + } + + /// CHECK-START: int Main.constantSwitch_AboveRange() dead_code_elimination_final (before) + /// CHECK-DAG: PackedSwitch + + /// CHECK-START: int Main.constantSwitch_AboveRange() dead_code_elimination_final (after) + /// CHECK-DAG: <<Const15:i\d+>> IntConstant 15 + /// CHECK-DAG: Return [<<Const15>>] + + /// CHECK-START: int Main.constantSwitch_AboveRange() dead_code_elimination_final (after) + /// CHECK-NOT: PackedSwitch + + public static int constantSwitch_AboveRange() { + int i = $inline$method() + 10; + switch(i) { + case 1: + i++; + break; + case 2: + i = 99; + break; + case 3: + i = 100; + break; + case 4: + i = -100; + break; + case 5: + i = 7; + break; + case 6: + i = -9; + break; + } + + return i; + } + + /// CHECK-START: int Main.constantSwitch_BelowRange() dead_code_elimination_final (before) + /// CHECK-DAG: PackedSwitch + + /// CHECK-START: int Main.constantSwitch_BelowRange() dead_code_elimination_final (after) + /// CHECK-DAG: <<ConstM5:i\d+>> IntConstant -5 + /// CHECK-DAG: Return [<<ConstM5>>] + + /// CHECK-START: int Main.constantSwitch_BelowRange() dead_code_elimination_final (after) + /// CHECK-NOT: PackedSwitch + + public static int constantSwitch_BelowRange() { + int i = $inline$method() - 10; + switch(i) { + case 1: + i++; + break; + case 2: + i = 99; + break; + case 3: + i = 100; + break; + case 4: + i = -100; + break; + case 5: + i = 7; + break; + case 6: + i = -9; + break; + } + + return i; + } + + public static void main(String[] args) throws Exception { + int ret_val = wholeSwitchDead(10); + if (ret_val != 100) { + throw new Error("Incorrect return value from wholeSwitchDead:" + ret_val); + } + + ret_val = constantSwitch_InRange(); + if (ret_val != 7) { + throw new Error("Incorrect return value from constantSwitch_InRange:" + ret_val); + } + + ret_val = constantSwitch_AboveRange(); + if (ret_val != 15) { + throw new Error("Incorrect return value from constantSwitch_AboveRange:" + ret_val); + } + + ret_val = constantSwitch_BelowRange(); + if (ret_val != -5) { + throw new Error("Incorrect return value from constantSwitch_BelowRange:" + ret_val); + } + } +} diff --git a/test/497-inlining-and-class-loader/expected.txt b/test/497-inlining-and-class-loader/expected.txt index f5b9fe07de..905dbfd2cb 100644 --- a/test/497-inlining-and-class-loader/expected.txt +++ b/test/497-inlining-and-class-loader/expected.txt @@ -1,3 +1,4 @@ +JNI_OnLoad called java.lang.Exception at Main.$noinline$bar(Main.java:124) at Level2.$inline$bar(Level1.java:25) diff --git a/test/526-checker-caller-callee-regs/src/Main.java b/test/526-checker-caller-callee-regs/src/Main.java index a1f33014ef..f402c2cd48 100644 --- a/test/526-checker-caller-callee-regs/src/Main.java +++ b/test/526-checker-caller-callee-regs/src/Main.java @@ -36,6 +36,8 @@ public class Main { // ------------------------------|------------------------|----------------- // ARM64 callee-saved registers | [x20-x29] | x2[0-9] // ARM callee-saved registers | [r5-r8,r10,r11] | r([5-8]|10|11) + // X86 callee-saved registers | [ebp,esi,edi] | e(bp|si|di) + // X86_64 callee-saved registers | [rbx,rbp,r12-15] | r(bx|bp|1[2-5]) /** * Check that a value live across a function call is allocated in a callee @@ -58,7 +60,21 @@ public class Main { /// CHECK: Sub [<<t1>>,<<t2>>] /// CHECK: Return - // TODO: Add tests for other architectures. + /// CHECK-START-X86: int Main.$opt$LiveInCall(int) register (after) + /// CHECK-DAG: <<Arg:i\d+>> ParameterValue + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<t1:i\d+>> Add [<<Arg>>,<<Const1>>] {{.*->e(bp|si|di)}} + /// CHECK: <<t2:i\d+>> InvokeStaticOrDirect + /// CHECK: Sub [<<t1>>,<<t2>>] + /// CHECK: Return + + /// CHECK-START-X86_64: int Main.$opt$LiveInCall(int) register (after) + /// CHECK-DAG: <<Arg:i\d+>> ParameterValue + /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<t1:i\d+>> Add [<<Arg>>,<<Const1>>] {{.*->r(bx|bp|1[2-5])}} + /// CHECK: <<t2:i\d+>> InvokeStaticOrDirect + /// CHECK: Sub [<<t1>>,<<t2>>] + /// CHECK: Return public static int $opt$LiveInCall(int arg) { int t1 = arg + 1; diff --git a/test/532-checker-nonnull-arrayset/expected.txt b/test/532-checker-nonnull-arrayset/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/532-checker-nonnull-arrayset/expected.txt diff --git a/test/532-checker-nonnull-arrayset/info.txt b/test/532-checker-nonnull-arrayset/info.txt new file mode 100644 index 0000000000..e1578c8f14 --- /dev/null +++ b/test/532-checker-nonnull-arrayset/info.txt @@ -0,0 +1 @@ +Test that we optimize ArraySet when the value is not null. diff --git a/test/532-checker-nonnull-arrayset/src/Main.java b/test/532-checker-nonnull-arrayset/src/Main.java new file mode 100644 index 0000000000..7d8fff46ba --- /dev/null +++ b/test/532-checker-nonnull-arrayset/src/Main.java @@ -0,0 +1,39 @@ +/* + * 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 { + + // Check that we don't put a null check in the card marking code. + + /// CHECK-START: void Main.test() instruction_simplifier (before) + /// CHECK: ArraySet value_can_be_null:true + + /// CHECK-START: void Main.test() instruction_simplifier (after) + /// CHECK: ArraySet value_can_be_null:false + + /// CHECK-START-X86: void Main.test() disassembly (after) + /// CHECK: ArraySet value_can_be_null:false + /// CHECK-NOT: test + /// CHECK: ReturnVoid + public static void test() { + Object[] array = new Object[1]; + Object nonNull = array[0]; + nonNull.getClass(); // Ensure nonNull has an implicit null check. + array[0] = nonNull; + } + + public static void main(String[] args) {} +} diff --git a/test/533-regression-debugphi/expected.txt b/test/533-regression-debugphi/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/533-regression-debugphi/expected.txt diff --git a/test/533-regression-debugphi/info.txt b/test/533-regression-debugphi/info.txt new file mode 100644 index 0000000000..a4d4857035 --- /dev/null +++ b/test/533-regression-debugphi/info.txt @@ -0,0 +1,2 @@ +Test a regression where DeadPhiHandling would infinitely loop over +complicated phi dependencies. diff --git a/test/533-regression-debugphi/smali/TestCase.smali b/test/533-regression-debugphi/smali/TestCase.smali new file mode 100644 index 0000000000..1908e72c57 --- /dev/null +++ b/test/533-regression-debugphi/smali/TestCase.smali @@ -0,0 +1,72 @@ +# 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 LTestCase; +.super Ljava/lang/Object; + +# This is a reduced test case that used to trigger an infinite loop +# in the DeadPhiHandling phase of the optimizing compiler (only used +# with debuggable flag). +.method public static testCase(IILjava/lang/Object;)V + .registers 5 + const/4 v0, 0x0 + + :B4 + invoke-static {}, Ljava/lang/System;->nanoTime()J + goto :B7 + + :B7 + invoke-static {}, Ljava/lang/System;->nanoTime()J + if-nez p2, :Btmp + goto :B111 + + :Btmp + invoke-static {}, Ljava/lang/System;->nanoTime()J + if-nez p2, :B9 + goto :B110 + + :B13 + invoke-static {}, Ljava/lang/System;->nanoTime()J + add-int v0, p0, p1 + goto :B7 + + :B110 + invoke-static {}, Ljava/lang/System;->nanoTime()J + add-int v0, p0, p1 + goto :B111 + + :B111 + invoke-static {}, Ljava/lang/System;->nanoTime()J + goto :B4 + + :B9 + invoke-static {}, Ljava/lang/System;->nanoTime()J + if-nez p2, :B10 + + :B11 + invoke-static {}, Ljava/lang/System;->nanoTime()J + move v1, v0 + goto :B12 + + :B10 + invoke-static {}, Ljava/lang/System;->nanoTime()J + move-object v1, p2 + goto :B12 + + :B12 + invoke-static {}, Ljava/lang/System;->nanoTime()J + goto :B13 + + return-void +.end method diff --git a/test/533-regression-debugphi/src/Main.java b/test/533-regression-debugphi/src/Main.java new file mode 100644 index 0000000000..858770f508 --- /dev/null +++ b/test/533-regression-debugphi/src/Main.java @@ -0,0 +1,22 @@ +/* + * 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 { + // Workaround for b/18051191. + class InnerClass {} + + public static void main(String[] args) {} +} diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt index 6568eac29f..17c1f00c41 100644 --- a/test/800-smali/expected.txt +++ b/test/800-smali/expected.txt @@ -1,4 +1,6 @@ PackedSwitch +PackedSwitch key INT_MAX +PackedSwitch key overflow b/17790197 FloatBadArgReg negLong diff --git a/test/800-smali/smali/PackedSwitch.smali b/test/800-smali/smali/PackedSwitch.smali index 6a3e5f00ba..95659fb16f 100644 --- a/test/800-smali/smali/PackedSwitch.smali +++ b/test/800-smali/smali/PackedSwitch.smali @@ -24,3 +24,29 @@ goto :return .end method + +.method public static packedSwitch_INT_MAX(I)I + .registers 2 + + const/4 v0, 0 + packed-switch v0, :switch_data + goto :default + + :switch_data + .packed-switch 0x7FFFFFFE + :case1 # key = INT_MAX - 1 + :case2 # key = INT_MAX + .end packed-switch + + :return + return v1 + + :default + goto :return + + :case1 + goto :return + :case2 + goto :return + +.end method diff --git a/test/800-smali/smali/b_24399945.smali b/test/800-smali/smali/b_24399945.smali new file mode 100644 index 0000000000..68f59d0387 --- /dev/null +++ b/test/800-smali/smali/b_24399945.smali @@ -0,0 +1,32 @@ +.class public Lb_24399945; + +.super Ljava/lang/Object; + +.method public static packedSwitch_overflow(I)I + .registers 2 + + const/4 v0, 0 + packed-switch v0, :switch_data + goto :default + + :switch_data + .packed-switch 0x7FFFFFFE + :case1 # key = INT_MAX - 1 + :case2 # key = INT_MAX + :case3 # key = INT_MIN (overflow!) + .end packed-switch + + :return + return v1 + + :default + goto :return + + :case1 + goto :return + :case2 + goto :return + :case3 + goto :return + +.end method diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java index ba4990a76e..f75747d5c5 100644 --- a/test/800-smali/src/Main.java +++ b/test/800-smali/src/Main.java @@ -51,6 +51,10 @@ public class Main { testCases = new LinkedList<TestCase>(); testCases.add(new TestCase("PackedSwitch", "PackedSwitch", "packedSwitch", new Object[]{123}, null, 123)); + testCases.add(new TestCase("PackedSwitch key INT_MAX", "PackedSwitch", + "packedSwitch_INT_MAX", new Object[]{123}, null, 123)); + testCases.add(new TestCase("PackedSwitch key overflow", "b_24399945", + "packedSwitch_overflow", new Object[]{123}, new VerifyError(), null)); testCases.add(new TestCase("b/17790197", "B17790197", "getInt", null, null, 100)); testCases.add(new TestCase("FloatBadArgReg", "FloatBadArgReg", "getInt", diff --git a/test/955-lambda-smali/expected.txt b/test/955-lambda-smali/expected.txt index 36370998f4..16381e4b46 100644 --- a/test/955-lambda-smali/expected.txt +++ b/test/955-lambda-smali/expected.txt @@ -16,3 +16,13 @@ Caught NPE (MoveResult) testF success (MoveResult) testD success (MoveResult) testL success +(CaptureVariables) (0-args, 1 captured variable 'Z'): value is true +(CaptureVariables) (0-args, 1 captured variable 'B'): value is R +(CaptureVariables) (0-args, 1 captured variable 'C'): value is ∂ +(CaptureVariables) (0-args, 1 captured variable 'S'): value is 1000 +(CaptureVariables) (0-args, 1 captured variable 'I'): value is 12345678 +(CaptureVariables) (0-args, 1 captured variable 'J'): value is 3287471278325742 +(CaptureVariables) (0-args, 1 captured variable 'F'): value is Infinity +(CaptureVariables) (0-args, 1 captured variable 'D'): value is -Infinity +(CaptureVariables) (0-args, 8 captured variable 'ZBCSIJFD'): value is true,R,∂,1000,12345678,3287471278325742,Infinity,-Infinity +(CaptureVariables) Caught NPE diff --git a/test/955-lambda-smali/smali/BoxUnbox.smali b/test/955-lambda-smali/smali/BoxUnbox.smali index 108b5fafbc..915de2d55d 100644 --- a/test/955-lambda-smali/smali/BoxUnbox.smali +++ b/test/955-lambda-smali/smali/BoxUnbox.smali @@ -1,4 +1,3 @@ -# # Copyright (C) 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,8 +35,8 @@ .end method #TODO: should use a closure type instead of ArtMethod. -.method public static doHelloWorld(Ljava/lang/reflect/ArtMethod;)V - .registers 3 # 1 parameters, 2 locals +.method public static doHelloWorld(J)V + .registers 4 # 1 wide parameters, 2 locals const-string v0, "(BoxUnbox) Hello boxing world! (0-args, no closure)" @@ -51,9 +50,9 @@ .method private static testBox()V .registers 3 - create-lambda v0, LBoxUnbox;->doHelloWorld(Ljava/lang/reflect/ArtMethod;)V + create-lambda v0, LBoxUnbox;->doHelloWorld(J)V box-lambda v2, v0 # v2 = box(v0) - unbox-lambda v0, v2, Ljava/lang/reflect/ArtMethod; # v0 = unbox(v2) + unbox-lambda v0, v2, J # v0 = unbox(v2) invoke-lambda v0, {} return-void @@ -63,7 +62,7 @@ .method private static testBoxEquality()V .registers 6 # 0 parameters, 6 locals - create-lambda v0, LBoxUnbox;->doHelloWorld(Ljava/lang/reflect/ArtMethod;)V + create-lambda v0, LBoxUnbox;->doHelloWorld(J)V box-lambda v2, v0 # v2 = box(v0) box-lambda v3, v0 # v3 = box(v0) @@ -95,7 +94,7 @@ const v0, 0 # v0 = null const v1, 0 # v1 = null :start - unbox-lambda v2, v0, Ljava/lang/reflect/ArtMethod; + unbox-lambda v2, v0, J # attempting to unbox a null lambda will throw NPE :end return-void @@ -140,7 +139,7 @@ const-string v0, "This is not a boxed lambda" :start # TODO: use \FunctionalType; here instead - unbox-lambda v2, v0, Ljava/lang/reflect/ArtMethod; + unbox-lambda v2, v0, J # can't use a string, expects a lambda object here. throws ClassCastException. :end return-void diff --git a/test/955-lambda-smali/smali/CaptureVariables.smali b/test/955-lambda-smali/smali/CaptureVariables.smali new file mode 100644 index 0000000000..f18b7ff741 --- /dev/null +++ b/test/955-lambda-smali/smali/CaptureVariables.smali @@ -0,0 +1,311 @@ +# +# 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 LCaptureVariables; +.super Ljava/lang/Object; + +.method public constructor <init>()V +.registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public static run()V +.registers 8 + # Test boolean capture + const v2, 1 # v2 = true + capture-variable v2, "Z" + create-lambda v0, LCaptureVariables;->printCapturedVariable_Z(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + # Test byte capture + const v2, 82 # v2 = 82, 'R' + capture-variable v2, "B" + create-lambda v0, LCaptureVariables;->printCapturedVariable_B(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + # Test char capture + const v2, 0x2202 # v2 = 0x2202, '∂' + capture-variable v2, "C" + create-lambda v0, LCaptureVariables;->printCapturedVariable_C(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + # Test short capture + const v2, 1000 # v2 = 1000 + capture-variable v2, "S" + create-lambda v0, LCaptureVariables;->printCapturedVariable_S(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + # Test int capture + const v2, 12345678 + capture-variable v2, "I" + create-lambda v0, LCaptureVariables;->printCapturedVariable_I(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + # Test long capture + const-wide v2, 0x0badf00dc0ffeeL # v2 = 3287471278325742 + capture-variable v2, "J" + create-lambda v0, LCaptureVariables;->printCapturedVariable_J(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + # Test float capture + const v2, infinityf + capture-variable v2, "F" + create-lambda v0, LCaptureVariables;->printCapturedVariable_F(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + # Test double capture + const-wide v2, -infinity + capture-variable v2, "D" + create-lambda v0, LCaptureVariables;->printCapturedVariable_D(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + + #TODO: capture objects and lambdas once we have support for it + + # Test capturing multiple variables + invoke-static {}, LCaptureVariables;->testMultipleCaptures()V + + # Test failures + invoke-static {}, LCaptureVariables;->testFailures()V + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_Z(J)V + .registers 5 # 1 wide parameter, 3 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'Z'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "Z" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(Z)V + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_B(J)V + .registers 5 # 1 wide parameter, 3 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'B'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "B" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(C)V # no println(B), use char instead. + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_C(J)V + .registers 5 # 1 wide parameter, 3 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'C'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "C" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(C)V + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_S(J)V + .registers 5 # 1 wide parameter, 3 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'S'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "S" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(I)V # no println(S), use int instead + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_I(J)V + .registers 5 # 1 wide parameter, 3 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'I'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "I" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(I)V + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_J(J)V + .registers 6 # 1 wide parameter, 4 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'J'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "J" + invoke-virtual {v1, v2, v3}, Ljava/io/PrintStream;->println(J)V + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_F(J)V + .registers 5 # 1 parameter, 4 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'F'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "F" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->println(F)V + + return-void +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_D(J)V + .registers 6 # 1 wide parameter, 4 locals + + const-string v0, "(CaptureVariables) (0-args, 1 captured variable 'D'): value is " + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "D" + invoke-virtual {v1, v2, v3}, Ljava/io/PrintStream;->println(D)V + + return-void +.end method + +# Test capturing more than one variable. +.method private static testMultipleCaptures()V + .registers 4 # 0 parameters, 4 locals + + const v2, 1 # v2 = true + capture-variable v2, "Z" + + const v2, 82 # v2 = 82, 'R' + capture-variable v2, "B" + + const v2, 0x2202 # v2 = 0x2202, '∂' + capture-variable v2, "C" + + const v2, 1000 # v2 = 1000 + capture-variable v2, "S" + + const v2, 12345678 + capture-variable v2, "I" + + const-wide v2, 0x0badf00dc0ffeeL # v2 = 3287471278325742 + capture-variable v2, "J" + + const v2, infinityf + capture-variable v2, "F" + + const-wide v2, -infinity + capture-variable v2, "D" + + create-lambda v0, LCaptureVariables;->printCapturedVariable_ZBCSIJFD(J)V + # TODO: create-lambda should not write to both v0 and v1 + invoke-lambda v0, {} + +.end method + +#TODO: should use a closure type instead of a long +.method public static printCapturedVariable_ZBCSIJFD(J)V + .registers 7 # 1 wide parameter, 5 locals + + const-string v0, "(CaptureVariables) (0-args, 8 captured variable 'ZBCSIJFD'): value is " + const-string v4, "," + + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "Z" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->print(Z)V + invoke-virtual {v1, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "B" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->print(C)V + invoke-virtual {v1, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "C" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->print(C)V + invoke-virtual {v1, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "S" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->print(I)V + invoke-virtual {v1, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "I" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->print(I)V + invoke-virtual {v1, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "J" + invoke-virtual {v1, v2, v3}, Ljava/io/PrintStream;->print(J)V + invoke-virtual {v1, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "F" + invoke-virtual {v1, v2}, Ljava/io/PrintStream;->print(F)V + invoke-virtual {v1, v4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + + liberate-variable v2, p0, "D" + invoke-virtual {v1, v2, v3}, Ljava/io/PrintStream;->println(D)V + + return-void +.end method + +# Test exceptions are thrown as expected when used opcodes incorrectly +.method private static testFailures()V + .registers 4 # 0 parameters, 4 locals + + const v0, 0 # v0 = null + const v1, 0 # v1 = null +:start + liberate-variable v0, v2, "Z" # invoking a null lambda shall raise an NPE +:end + return-void + +:handler + const-string v2, "(CaptureVariables) Caught NPE" + sget-object v3, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v3, v2}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V + + return-void + + .catch Ljava/lang/NullPointerException; {:start .. :end} :handler +.end method diff --git a/test/955-lambda-smali/smali/Main.smali b/test/955-lambda-smali/smali/Main.smali index 5d2aabb386..9892d6124e 100644 --- a/test/955-lambda-smali/smali/Main.smali +++ b/test/955-lambda-smali/smali/Main.smali @@ -24,6 +24,7 @@ invoke-static {}, LTrivialHelloWorld;->run()V invoke-static {}, LBoxUnbox;->run()V invoke-static {}, LMoveResult;->run()V + invoke-static {}, LCaptureVariables;->run()V # TODO: add tests when verification fails diff --git a/test/955-lambda-smali/smali/MoveResult.smali b/test/955-lambda-smali/smali/MoveResult.smali index 1725da3044..52f7ba363b 100644 --- a/test/955-lambda-smali/smali/MoveResult.smali +++ b/test/955-lambda-smali/smali/MoveResult.smali @@ -41,7 +41,7 @@ .method public static testZ()V .registers 6 - create-lambda v0, LMoveResult;->lambdaZ(Ljava/lang/reflect/ArtMethod;)Z + create-lambda v0, LMoveResult;->lambdaZ(J)Z invoke-lambda v0, {} move-result v2 const v3, 1 @@ -61,7 +61,7 @@ .end method # Lambda target for testZ. Always returns "true". -.method public static lambdaZ(Ljava/lang/reflect/ArtMethod;)Z +.method public static lambdaZ(J)Z .registers 3 const v0, 1 @@ -73,7 +73,7 @@ .method public static testB()V .registers 6 - create-lambda v0, LMoveResult;->lambdaB(Ljava/lang/reflect/ArtMethod;)B + create-lambda v0, LMoveResult;->lambdaB(J)B invoke-lambda v0, {} move-result v2 const v3, 15 @@ -93,7 +93,7 @@ .end method # Lambda target for testB. Always returns "15". -.method public static lambdaB(Ljava/lang/reflect/ArtMethod;)B +.method public static lambdaB(J)B .registers 3 # 1 parameters, 2 locals const v0, 15 @@ -105,7 +105,7 @@ .method public static testS()V .registers 6 - create-lambda v0, LMoveResult;->lambdaS(Ljava/lang/reflect/ArtMethod;)S + create-lambda v0, LMoveResult;->lambdaS(J)S invoke-lambda v0, {} move-result v2 const/16 v3, 31000 @@ -125,7 +125,7 @@ .end method # Lambda target for testS. Always returns "31000". -.method public static lambdaS(Ljava/lang/reflect/ArtMethod;)S +.method public static lambdaS(J)S .registers 3 const/16 v0, 31000 @@ -137,7 +137,7 @@ .method public static testI()V .registers 6 - create-lambda v0, LMoveResult;->lambdaI(Ljava/lang/reflect/ArtMethod;)I + create-lambda v0, LMoveResult;->lambdaI(J)I invoke-lambda v0, {} move-result v2 const v3, 128000 @@ -157,7 +157,7 @@ .end method # Lambda target for testI. Always returns "128000". -.method public static lambdaI(Ljava/lang/reflect/ArtMethod;)I +.method public static lambdaI(J)I .registers 3 const v0, 128000 @@ -167,9 +167,9 @@ # Test that chars are returned correctly via move-result. .method public static testC()V - .registers 6 + .registers 7 - create-lambda v0, LMoveResult;->lambdaC(Ljava/lang/reflect/ArtMethod;)C + create-lambda v0, LMoveResult;->lambdaC(J)C invoke-lambda v0, {} move-result v2 const v3, 65535 @@ -189,7 +189,7 @@ .end method # Lambda target for testC. Always returns "65535". -.method public static lambdaC(Ljava/lang/reflect/ArtMethod;)C +.method public static lambdaC(J)C .registers 3 const v0, 65535 @@ -199,12 +199,12 @@ # Test that longs are returned correctly via move-result. .method public static testJ()V - .registers 8 + .registers 9 - create-lambda v0, LMoveResult;->lambdaJ(Ljava/lang/reflect/ArtMethod;)J + create-lambda v0, LMoveResult;->lambdaJ(J)J invoke-lambda v0, {} move-result v2 - const-wide v4, 0xdeadf00dc0ffee + const-wide v4, 0xdeadf00dc0ffeeL if-ne v4, v2, :is_not_equal const-string v6, "(MoveResult) testJ success" @@ -220,11 +220,11 @@ .end method -# Lambda target for testC. Always returns "0xdeadf00dc0ffee". -.method public static lambdaJ(Ljava/lang/reflect/ArtMethod;)J - .registers 4 +# Lambda target for testC. Always returns "0xdeadf00dc0ffeeL". +.method public static lambdaJ(J)J + .registers 5 - const-wide v0, 0xdeadf00dc0ffee + const-wide v0, 0xdeadf00dc0ffeeL return-wide v0 .end method @@ -233,7 +233,7 @@ .method public static testF()V .registers 6 - create-lambda v0, LMoveResult;->lambdaF(Ljava/lang/reflect/ArtMethod;)F + create-lambda v0, LMoveResult;->lambdaF(J)F invoke-lambda v0, {} move-result v2 const v3, infinityf @@ -253,8 +253,8 @@ .end method # Lambda target for testF. Always returns "infinityf". -.method public static lambdaF(Ljava/lang/reflect/ArtMethod;)F - .registers 3 +.method public static lambdaF(J)F + .registers 4 const v0, infinityf return v0 @@ -265,10 +265,10 @@ .method public static testD()V .registers 8 - create-lambda v0, LMoveResult;->lambdaD(Ljava/lang/reflect/ArtMethod;)D + create-lambda v0, LMoveResult;->lambdaD(J)D invoke-lambda v0, {} move-result-wide v2 - const-wide v4, infinity + const-wide v4, -infinity if-ne v4, v2, :is_not_equal const-string v6, "(MoveResult) testD success" @@ -285,10 +285,10 @@ .end method # Lambda target for testD. Always returns "infinity". -.method public static lambdaD(Ljava/lang/reflect/ArtMethod;)D - .registers 4 +.method public static lambdaD(J)D + .registers 5 - const-wide v0, infinity # 123.456789 + const-wide v0, -infinity return-wide v0 .end method @@ -298,7 +298,7 @@ .method public static testL()V .registers 8 - create-lambda v0, LMoveResult;->lambdaL(Ljava/lang/reflect/ArtMethod;)Ljava/lang/String; + create-lambda v0, LMoveResult;->lambdaL(J)Ljava/lang/String; invoke-lambda v0, {} move-result-object v2 const-string v4, "Interned string" @@ -319,8 +319,8 @@ .end method # Lambda target for testL. Always returns "Interned string" (string). -.method public static lambdaL(Ljava/lang/reflect/ArtMethod;)Ljava/lang/String; - .registers 4 +.method public static lambdaL(J)Ljava/lang/String; + .registers 5 const-string v0, "Interned string" return-object v0 diff --git a/test/955-lambda-smali/smali/TrivialHelloWorld.smali b/test/955-lambda-smali/smali/TrivialHelloWorld.smali index 38ee95ac7e..3444b13a65 100644 --- a/test/955-lambda-smali/smali/TrivialHelloWorld.smali +++ b/test/955-lambda-smali/smali/TrivialHelloWorld.smali @@ -25,12 +25,12 @@ .method public static run()V .registers 8 # Trivial 0-arg hello world - create-lambda v0, LTrivialHelloWorld;->doHelloWorld(Ljava/lang/reflect/ArtMethod;)V + create-lambda v0, LTrivialHelloWorld;->doHelloWorld(J)V # TODO: create-lambda should not write to both v0 and v1 invoke-lambda v0, {} # Slightly more interesting 4-arg hello world - create-lambda v2, doHelloWorldArgs(Ljava/lang/reflect/ArtMethod;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + create-lambda v2, doHelloWorldArgs(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V # TODO: create-lambda should not write to both v2 and v3 const-string v4, "A" const-string v5, "B" @@ -43,9 +43,9 @@ return-void .end method -#TODO: should use a closure type instead of ArtMethod. -.method public static doHelloWorld(Ljava/lang/reflect/ArtMethod;)V - .registers 3 # 1 parameters, 2 locals +#TODO: should use a closure type instead of jlong. +.method public static doHelloWorld(J)V + .registers 5 # 1 wide parameters, 3 locals const-string v0, "Hello world! (0-args, no closure)" @@ -55,17 +55,17 @@ return-void .end method -#TODO: should use a closure type instead of ArtMethod. -.method public static doHelloWorldArgs(Ljava/lang/reflect/ArtMethod;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - .registers 7 # 5 parameters, 2 locals +#TODO: should use a closure type instead of jlong. +.method public static doHelloWorldArgs(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + .registers 9 # 1 wide parameter, 4 narrow parameters, 3 locals const-string v0, " Hello world! (4-args, no closure)" sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; - invoke-virtual {v1, p1}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V invoke-virtual {v1, p2}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V invoke-virtual {v1, p3}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V invoke-virtual {v1, p4}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V + invoke-virtual {v1, p5}, Ljava/io/PrintStream;->print(Ljava/lang/String;)V invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk index 7f05a043d8..e43ea90ba6 100644 --- a/test/Android.libarttest.mk +++ b/test/Android.libarttest.mk @@ -33,6 +33,7 @@ LIBARTTEST_COMMON_SRC_FILES := \ 1337-gc-coverage/gc_coverage.cc \ 137-cfi/cfi.cc \ 139-register-natives/regnative.cc \ + 141-class-unload/jni_unload.cc \ 454-get-vreg/get_vreg_jni.cc \ 455-set-vreg/set_vreg_jni.cc \ 457-regs/regs_jni.cc \ diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 29e015f534..4397ea4b52 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -370,6 +370,7 @@ TEST_ART_BROKEN_FALLBACK_RUN_TESTS := # when already tracing, and writes an error message that we do not want to check for. TEST_ART_BROKEN_TRACING_RUN_TESTS := \ 137-cfi \ + 141-class-unload \ 802-deoptimization ifneq (,$(filter trace stream,$(TRACE_TYPES))) diff --git a/test/run-test b/test/run-test index 828939d247..a5b6e92869 100755 --- a/test/run-test +++ b/test/run-test @@ -392,7 +392,7 @@ fi # Most interesting target architecture variables are Makefile variables, not environment variables. # Try to map the suffix64 flag and what we find in ${ANDROID_PRODUCT_OUT}/data/art-test to an architecture name. -function guess_arch_name() { +function guess_target_arch_name() { grep32bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm|x86|mips)$'` grep64bit=`ls ${ANDROID_PRODUCT_OUT}/data/art-test | grep -E '^(arm64|x86_64|mips64)$'` if [ "x${suffix64}" = "x64" ]; then @@ -402,6 +402,14 @@ function guess_arch_name() { fi } +function guess_host_arch_name() { + if [ "x${suffix64}" = "x64" ]; then + host_arch_name="x86_64" + else + host_arch_name="x86" + fi +} + if [ "$target_mode" = "no" ]; then if [ "$runtime" = "jvm" ]; then if [ "$prebuild_mode" = "yes" ]; then @@ -437,10 +445,11 @@ elif [ "$runtime" = "art" ]; then if [ -z "$ANDROID_HOST_OUT" ]; then export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86 fi + guess_host_arch_name run_args="${run_args} --boot ${ANDROID_HOST_OUT}/framework/core${image_suffix}${pic_image_suffix}.art" run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}" else - guess_arch_name + guess_target_arch_name run_args="${run_args} --runtime-option -Djava.library.path=/data/art-test/${target_arch_name}" run_args="${run_args} --boot /data/art-test/core${image_suffix}${pic_image_suffix}.art" fi @@ -635,7 +644,7 @@ if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]]; then run_checker="yes" if [ "$target_mode" = "no" ]; then cfg_output_dir="$tmp_dir" - checker_arch_option= + checker_arch_option="--arch=${host_arch_name^^}" else cfg_output_dir="$DEX_LOCATION" checker_arch_option="--arch=${target_arch_name^^}" |