diff options
Diffstat (limited to 'test')
100 files changed, 4199 insertions, 71 deletions
diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java index dd88db0b7c..ee3a3b9830 100644 --- a/test/004-JniTest/src/Main.java +++ b/test/004-JniTest/src/Main.java @@ -120,7 +120,7 @@ public class Main { private static void testRemoveLocalObject() { removeLocalObject(new Object()); } - + private static native short shortMethod(short s1, short s2, short s3, short s4, short s5, short s6, short s7, short s8, short s9, short s10); diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc index 285df18c72..f8d321cbec 100644 --- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc @@ -22,11 +22,11 @@ namespace art { #define CHECK_REGS_CONTAIN_REFS(dex_pc, abort_if_not_found, ...) do { \ int t[] = {__VA_ARGS__}; \ int t_size = sizeof(t) / sizeof(*t); \ - uintptr_t native_quick_pc = m->ToNativeQuickPc(dex_pc, \ + uintptr_t native_quick_pc = GetCurrentCode().ToNativeQuickPc(dex_pc, \ /* is_catch_handler */ false, \ abort_if_not_found); \ if (native_quick_pc != UINTPTR_MAX) { \ - CheckReferences(t, t_size, m->NativeQuickPcOffset(native_quick_pc)); \ + CheckReferences(t, t_size, GetCurrentCode().NativeQuickPcOffset(native_quick_pc)); \ } \ } while (false); @@ -49,7 +49,7 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { CHECK_REGS_CONTAIN_REFS(0x06U, true, 8, 1); // v8: this, v1: x CHECK_REGS_CONTAIN_REFS(0x08U, true, 8, 3, 1); // v8: this, v3: y, v1: x CHECK_REGS_CONTAIN_REFS(0x0cU, true, 8, 3, 1); // v8: this, v3: y, v1: x - if (!m->IsOptimized(sizeof(void*))) { + if (!GetCurrentCode().IsOptimized(sizeof(void*))) { CHECK_REGS_CONTAIN_REFS(0x0eU, true, 8, 3, 1); // v8: this, v3: y, v1: x } CHECK_REGS_CONTAIN_REFS(0x10U, true, 8, 3, 1); // v8: this, v3: y, v1: x @@ -65,7 +65,7 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { // Note that v0: ex can be eliminated because it's a dead merge of two different exceptions. CHECK_REGS_CONTAIN_REFS(0x18U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex) CHECK_REGS_CONTAIN_REFS(0x1aU, true, 8, 5, 2, 1); // v8: this, v5: x[1], v2: y, v1: x (dead v0: ex) - if (!m->IsOptimized(sizeof(void*))) { + if (!GetCurrentCode().IsOptimized(sizeof(void*))) { // v8: this, v5: x[1], v2: y, v1: x (dead v0: ex) CHECK_REGS_CONTAIN_REFS(0x1dU, true, 8, 5, 2, 1); // v5 is removed from the root set because there is a "merge" operation. @@ -74,7 +74,7 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { } CHECK_REGS_CONTAIN_REFS(0x21U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex) - if (!m->IsOptimized(sizeof(void*))) { + if (!GetCurrentCode().IsOptimized(sizeof(void*))) { CHECK_REGS_CONTAIN_REFS(0x27U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x } CHECK_REGS_CONTAIN_REFS(0x29U, true, 8, 4, 2, 1); // v8: this, v4: ex, v2: y, v1: x diff --git a/test/079-phantom/src/Bitmap.java b/test/079-phantom/src/Bitmap.java index 85eb3ccb97..ff43749e76 100644 --- a/test/079-phantom/src/Bitmap.java +++ b/test/079-phantom/src/Bitmap.java @@ -125,7 +125,6 @@ class PhantomWrapper extends PhantomReference { */ class BitmapWatcher extends Thread { ReferenceQueue<PhantomWrapper> mQueue; - volatile boolean mQuit = false; BitmapWatcher(ReferenceQueue<PhantomWrapper> queue) { mQueue = queue; @@ -133,7 +132,7 @@ class BitmapWatcher extends Thread { } public void run() { - while (!mQuit) { + while (true) { try { PhantomWrapper ref = (PhantomWrapper) mQueue.remove(); //System.out.println("dequeued ref " + ref.mNativeData + @@ -142,12 +141,12 @@ class BitmapWatcher extends Thread { //ref.clear(); } catch (InterruptedException ie) { System.out.println("intr"); + break; } } } public void shutDown() { - mQuit = true; interrupt(); } } diff --git a/test/088-monitor-verification/smali/NullLocks.smali b/test/088-monitor-verification/smali/NullLocks.smali new file mode 100644 index 0000000000..8262f19e22 --- /dev/null +++ b/test/088-monitor-verification/smali/NullLocks.smali @@ -0,0 +1,28 @@ +.class public LNullLocks; + +.super Ljava/lang/Object; + +.method public static run(Z)V + .registers 3 + + invoke-static {}, LMain;->assertIsManaged()V + + if-eqz v2, :Lfalse + + const v0, 0 # Null. + monitor-enter v0 + const v1, 0 # Another null. This should be detected as an alias, such that the exit + # will not fail verification. + monitor-exit v1 + + monitor-enter v0 + monitor-exit v1 + + monitor-enter v1 + monitor-exit v0 + +:Lfalse + + return-void + +.end method diff --git a/test/088-monitor-verification/src/Main.java b/test/088-monitor-verification/src/Main.java index 218805543e..212c894bd5 100644 --- a/test/088-monitor-verification/src/Main.java +++ b/test/088-monitor-verification/src/Main.java @@ -27,6 +27,13 @@ public class Main { */ public static void main(String[] args) { System.loadLibrary(args[0]); + if (!hasOatFile() || runtimeIsSoftFail() || isInterpreted()) { + // Some tests ensure that the verifier was able to guarantee balanced locking by + // asserting that the test function is running as compiled code. But skip this now, + // as this seems to be a non-compiled code test configuration. + disableStackFrameAsserts(); + } + Main m = new Main(); m.recursiveSync(0); @@ -49,7 +56,7 @@ public class Main { Object obj1 = new Object(); Object obj2 = new Object(); - m.twoPath(obj1, obj2, 0); + TwoPath.twoPath(obj1, obj2, 0); System.out.println("twoPath ok"); m.triplet(obj1, obj2, 0); @@ -62,6 +69,7 @@ public class Main { * Recursive synchronized method. */ synchronized void recursiveSync(int iter) { + assertIsManaged(); if (iter < 40) { recursiveSync(iter+1); } else { @@ -73,6 +81,7 @@ public class Main { * Tests simple nesting, with and without a throw. */ void nestedMayThrow(boolean doThrow) { + assertIsManaged(); synchronized (this) { synchronized (Main.class) { synchronized (new Object()) { @@ -90,6 +99,7 @@ public class Main { * Exercises bug 3215458. */ void constantLock() { + assertIsManaged(); Class thing = Thread.class; synchronized (Thread.class) {} } @@ -98,6 +108,7 @@ public class Main { * Confirms that we can have 32 nested monitors on one method. */ void notExcessiveNesting() { + assertIsManaged(); synchronized (this) { // 1 synchronized (this) { // 2 synchronized (this) { // 3 @@ -138,6 +149,7 @@ public class Main { * method. */ void notNested() { + assertIsManaged(); synchronized (this) {} // 1 synchronized (this) {} // 2 synchronized (this) {} // 3 @@ -178,25 +190,6 @@ public class Main { private void doNothing(Object obj) {} /** - * Conditionally uses one of the synchronized objects. - */ - public void twoPath(Object obj1, Object obj2, int x) { - Object localObj; - - synchronized (obj1) { - synchronized(obj2) { - if (x == 0) { - localObj = obj2; - } else { - localObj = obj1; - } - } - } - - doNothing(localObj); - } - - /** * Lock the monitor two or three times, and make use of the locked or * unlocked object. */ @@ -220,19 +213,16 @@ public class Main { // Smali testing code. private static void runSmaliTests() { - if (!hasOatFile() || runtimeIsSoftFail() || isInterpreted()) { - // Skip test, this seems to be a non-compiled code test configuration. - return; - } - runTest("OK", new Object[] { new Object(), new Object() }, null); runTest("TooDeep", new Object[] { new Object() }, null); runTest("NotStructuredOverUnlock", new Object[] { new Object() }, IllegalMonitorStateException.class); - runTest("NotStructuredUnderUnlock", new Object[] { new Object() }, null); - // TODO: new IllegalMonitorStateException()); + runTest("NotStructuredUnderUnlock", new Object[] { new Object() }, + IllegalMonitorStateException.class); runTest("UnbalancedJoin", new Object[] { new Object(), new Object() }, null); runTest("UnbalancedStraight", new Object[] { new Object(), new Object() }, null); + runTest("NullLocks", new Object[] { false }, null); + runTest("NullLocks", new Object[] { true }, NullPointerException.class); } private static void runTest(String className, Object[] parameters, Class<?> excType) { @@ -282,4 +272,5 @@ public class Main { public static native boolean hasOatFile(); public static native boolean runtimeIsSoftFail(); public static native boolean isInterpreted(); + public static native void disableStackFrameAsserts(); } diff --git a/test/088-monitor-verification/src/TwoPath.java b/test/088-monitor-verification/src/TwoPath.java new file mode 100644 index 0000000000..bdc15ad82e --- /dev/null +++ b/test/088-monitor-verification/src/TwoPath.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 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.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/* + * Test case for conditionally using one of two synchronized objects. + * + * This code cannot be verified at the moment, as the join point merges a register with two + * different lock options. Do not put it into Main to avoid the whole class being run in the + * interpreter. + */ +public class TwoPath { + + /** + * Conditionally uses one of the synchronized objects. + */ + public static void twoPath(Object obj1, Object obj2, int x) { + Main.assertIsManaged(); + + Object localObj; + + synchronized (obj1) { + synchronized(obj2) { + if (x == 0) { + localObj = obj2; + } else { + localObj = obj1; + } + } + } + + doNothing(localObj); + } + + private static void doNothing(Object o) { + } +} diff --git a/test/131-structural-change/expected.txt b/test/131-structural-change/expected.txt index cc7713d252..1d19278f1e 100644 --- a/test/131-structural-change/expected.txt +++ b/test/131-structural-change/expected.txt @@ -1,2 +1,3 @@ +JNI_OnLoad called Should really reach here. Done. diff --git a/test/131-structural-change/src/Main.java b/test/131-structural-change/src/Main.java index 6cbbd12387..c7488992df 100644 --- a/test/131-structural-change/src/Main.java +++ b/test/131-structural-change/src/Main.java @@ -35,7 +35,7 @@ public class Main { e.printStackTrace(System.out); } - boolean haveOatFile = hasOat(); + boolean haveOatFile = hasOatFile(); boolean gotError = false; try { Class<?> bClass = getClass().getClassLoader().loadClass("B"); @@ -45,10 +45,10 @@ public class Main { e.printStackTrace(System.out); } if (haveOatFile ^ gotError) { - System.out.println("Did not get expected error."); + System.out.println("Did not get expected error. " + haveOatFile + " " + gotError); } System.out.println("Done."); } - private native static boolean hasOat(); + private native static boolean hasOatFile(); } diff --git a/test/141-class-unload/expected.txt b/test/141-class-unload/expected.txt index 53d7abecaf..11de660c43 100644 --- a/test/141-class-unload/expected.txt +++ b/test/141-class-unload/expected.txt @@ -21,3 +21,4 @@ null JNI_OnLoad called class null false test JNI_OnUnload called +Number of loaded unload-ex maps 0 diff --git a/test/141-class-unload/src/Main.java b/test/141-class-unload/src/Main.java index 3cc43accbe..0640b364c9 100644 --- a/test/141-class-unload/src/Main.java +++ b/test/141-class-unload/src/Main.java @@ -14,6 +14,9 @@ * limitations under the License. */ +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -43,11 +46,28 @@ public class Main { testStackTrace(constructor); // Stress test to make sure we dont leak memory. stressTest(constructor); + // Test that the oat files are unloaded. + testOatFilesUnloaded(getPid()); } catch (Exception e) { System.out.println(e); } } + private static void testOatFilesUnloaded(int pid) throws Exception { + BufferedReader reader = new BufferedReader(new FileReader ("/proc/" + pid + "/maps")); + String line; + int count = 0; + Runtime.getRuntime().gc(); + System.runFinalization(); + while ((line = reader.readLine()) != null) { + if (line.contains("@141-class-unload-ex.jar")) { + System.out.println(line); + ++count; + } + } + System.out.println("Number of loaded unload-ex maps " + count); + } + private static void stressTest(Constructor constructor) throws Exception { for (int i = 0; i <= 100; ++i) { setUpUnloadLoader(constructor, false); @@ -163,4 +183,8 @@ public class Main { loadLibrary.invoke(intHolder, nativeLibraryName); return new WeakReference(loader); } + + private static int getPid() throws Exception { + return Integer.parseInt(new File("/proc/self").getCanonicalFile().getName()); + } } diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc index 9facfdb076..0ee2ff9fda 100644 --- a/test/454-get-vreg/get_vreg_jni.cc +++ b/test/454-get-vreg/get_vreg_jni.cc @@ -15,6 +15,7 @@ */ #include "arch/context.h" +#include "art_code.h" #include "art_method-inl.h" #include "jni.h" #include "scoped_thread_state_change.h" @@ -45,10 +46,14 @@ class TestVisitor : public StackVisitor { CHECK_EQ(value, 42u); bool success = GetVReg(m, 1, kIntVReg, &value); - if (m->IsOptimized(sizeof(void*))) CHECK(!success); + if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + CHECK(!success); + } success = GetVReg(m, 2, kIntVReg, &value); - if (m->IsOptimized(sizeof(void*))) CHECK(!success); + if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + CHECK(!success); + } CHECK(GetVReg(m, 3, kReferenceVReg, &value)); CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_); @@ -78,10 +83,14 @@ class TestVisitor : public StackVisitor { CHECK_EQ(value, 42u); bool success = GetVRegPair(m, 2, kLongLoVReg, kLongHiVReg, &value); - if (m->IsOptimized(sizeof(void*))) CHECK(!success); + if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + CHECK(!success); + } success = GetVRegPair(m, 4, kLongLoVReg, kLongHiVReg, &value); - if (m->IsOptimized(sizeof(void*))) CHECK(!success); + if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + CHECK(!success); + } uint32_t value32 = 0; CHECK(GetVReg(m, 6, kReferenceVReg, &value32)); diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc index c21168b81e..6fcebdb8b5 100644 --- a/test/457-regs/regs_jni.cc +++ b/test/457-regs/regs_jni.cc @@ -15,6 +15,7 @@ */ #include "arch/context.h" +#include "art_code.h" #include "art_method-inl.h" #include "jni.h" #include "scoped_thread_state_change.h" @@ -63,7 +64,9 @@ class TestVisitor : public StackVisitor { CHECK_EQ(value, 1u); bool success = GetVReg(m, 2, kIntVReg, &value); - if (m->IsOptimized(sizeof(void*))) CHECK(!success); + if (!IsCurrentFrameInInterpreter() && GetCurrentCode().IsOptimized(sizeof(void*))) { + CHECK(!success); + } CHECK(GetVReg(m, 3, kReferenceVReg, &value)); CHECK_EQ(value, 1u); diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc index 7e9a583faf..2a56a7fce7 100644 --- a/test/466-get-live-vreg/get_live_vreg_jni.cc +++ b/test/466-get-live-vreg/get_live_vreg_jni.cc @@ -15,6 +15,7 @@ */ #include "arch/context.h" +#include "art_code.h" #include "art_method-inl.h" #include "jni.h" #include "scoped_thread_state_change.h" @@ -43,7 +44,7 @@ class TestVisitor : public StackVisitor { found_method_ = true; uint32_t value = 0; if (GetCurrentQuickFrame() != nullptr && - m->IsOptimized(sizeof(void*)) && + GetCurrentCode().IsOptimized(sizeof(void*)) && !Runtime::Current()->IsDebuggable()) { CHECK_EQ(GetVReg(m, 0, kIntVReg, &value), false); } else { diff --git a/test/529-checker-unresolved/expected.txt b/test/529-checker-unresolved/expected.txt index 358048c75b..1e7dbfed2e 100644 --- a/test/529-checker-unresolved/expected.txt +++ b/test/529-checker-unresolved/expected.txt @@ -3,3 +3,5 @@ UnresolvedClass.staticMethod() UnresolvedClass.virtualMethod() UnresolvedClass.interfaceMethod() UnresolvedClass.superMethod() +instanceof ok +checkcast ok diff --git a/test/529-checker-unresolved/src/Main.java b/test/529-checker-unresolved/src/Main.java index adb5adae82..5219c04c37 100644 --- a/test/529-checker-unresolved/src/Main.java +++ b/test/529-checker-unresolved/src/Main.java @@ -114,16 +114,30 @@ public class Main extends UnresolvedSuperClass { expectEquals(o, c.instanceObject); } + static public void testInstanceOf(Object o) { + if (o instanceof UnresolvedSuperClass) { + System.out.println("instanceof ok"); + } + } + + static public UnresolvedSuperClass testCheckCast(Object o) { + UnresolvedSuperClass c = (UnresolvedSuperClass) o; + System.out.println("checkcast ok"); + return c; + } /// CHECK-START: void Main.main(java.lang.String[]) register (before) /// CHECK: InvokeUnresolved invoke_type:direct static public void main(String[] args) { UnresolvedClass c = new UnresolvedClass(); + Main m = new Main(); callInvokeUnresolvedStatic(); callInvokeUnresolvedVirtual(c); callInvokeUnresolvedInterface(c); - callInvokeUnresolvedSuper(new Main()); + callInvokeUnresolvedSuper(m); callUnresolvedStaticFieldAccess(); callUnresolvedInstanceFieldAccess(c); + testInstanceOf(m); + testCheckCast(m); } public static void expectEquals(byte expected, byte result) { diff --git a/test/529-checker-unresolved/src/Unresolved.java b/test/529-checker-unresolved/src/Unresolved.java index 03ceb6857b..20ac6e0b89 100644 --- a/test/529-checker-unresolved/src/Unresolved.java +++ b/test/529-checker-unresolved/src/Unresolved.java @@ -58,13 +58,3 @@ class UnresolvedClass extends UnresolvedSuperClass implements UnresolvedInterfac public Object instanceObject; } -final class UnresolvedFinalClass { - public void directMethod() { - System.out.println("UnresolvedFinalClass.directMethod()"); - } -} - -class UnresolvedAtRuntime { - public void unresolvedAtRuntime() { } -} - diff --git a/test/536-checker-intrinsic-optimization/expected.txt b/test/536-checker-intrinsic-optimization/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/536-checker-intrinsic-optimization/expected.txt diff --git a/test/536-checker-intrinsic-optimization/info.txt b/test/536-checker-intrinsic-optimization/info.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/536-checker-intrinsic-optimization/info.txt diff --git a/test/536-checker-intrinsic-optimization/src/Main.java b/test/536-checker-intrinsic-optimization/src/Main.java new file mode 100644 index 0000000000..1b784ae367 --- /dev/null +++ b/test/536-checker-intrinsic-optimization/src/Main.java @@ -0,0 +1,71 @@ +/* + * 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 void main(String[] args) { + stringEqualsSame(); + stringArgumentNotNull("Foo"); + } + + /// CHECK-START: boolean Main.stringEqualsSame() instruction_simplifier (before) + /// CHECK: InvokeStaticOrDirect + + /// CHECK-START: boolean Main.stringEqualsSame() register (before) + /// CHECK: <<Const1:i\d+>> IntConstant 1 + /// CHECK: Return [<<Const1>>] + + /// CHECK-START: boolean Main.stringEqualsSame() register (before) + /// CHECK-NOT: InvokeStaticOrDirect + public static boolean stringEqualsSame() { + return $inline$callStringEquals("obj", "obj"); + } + + /// CHECK-START: boolean Main.stringEqualsNull() register (after) + /// CHECK: <<Invoke:z\d+>> InvokeStaticOrDirect + /// CHECK: Return [<<Invoke>>] + public static boolean stringEqualsNull() { + String o = (String)myObject; + return $inline$callStringEquals(o, o); + } + + public static boolean $inline$callStringEquals(String a, String b) { + return a.equals(b); + } + + /// CHECK-START-X86: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after) + /// CHECK: InvokeStaticOrDirect + /// CHECK-NOT: test + public static boolean stringArgumentNotNull(Object obj) { + obj.getClass(); + return "foo".equals(obj); + } + + // Test is very brittle as it depends on the order we emit instructions. + /// CHECK-START-X86: boolean Main.stringArgumentIsString() disassembly (after) + /// CHECK: InvokeStaticOrDirect + /// CHECK: test + /// CHECK: jz/eq + // Check that we don't try to compare the classes. + /// CHECK-NOT: mov + /// CHECK: cmp + public static boolean stringArgumentIsString() { + return "foo".equals(myString); + } + + static String myString; + static Object myObject; +} diff --git a/test/536-checker-needs-access-check/expected.txt b/test/536-checker-needs-access-check/expected.txt new file mode 100644 index 0000000000..4acae95b70 --- /dev/null +++ b/test/536-checker-needs-access-check/expected.txt @@ -0,0 +1,4 @@ +Got expected error instanceof +Got expected error instanceof null +Got expected error checkcast null +Got expected error instanceof (keep LoadClass with access check) diff --git a/test/536-checker-needs-access-check/info.txt b/test/536-checker-needs-access-check/info.txt new file mode 100644 index 0000000000..3413cf3625 --- /dev/null +++ b/test/536-checker-needs-access-check/info.txt @@ -0,0 +1 @@ +Verifies that we don't remove type checks when we need to check for access rights. diff --git a/test/536-checker-needs-access-check/src/Main.java b/test/536-checker-needs-access-check/src/Main.java new file mode 100644 index 0000000000..7bd49c1c8c --- /dev/null +++ b/test/536-checker-needs-access-check/src/Main.java @@ -0,0 +1,82 @@ +/* + * 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 other.InaccessibleClass; +import other.InaccessibleClassProxy; + +public class Main { + public static void main(String[] args) { + try { + testInstanceOf(); + } catch (IllegalAccessError e) { + System.out.println("Got expected error instanceof"); + } + + try { + testInstanceOfNull(); + } catch (IllegalAccessError e) { + System.out.println("Got expected error instanceof null"); + } + + try { + testCheckCastNull(); + } catch (IllegalAccessError e) { + System.out.println("Got expected error checkcast null"); + } + + try { + testDontGvnLoadClassWithAccessChecks(new Object()); + } catch (IllegalAccessError e) { + System.out.println("Got expected error instanceof (keep LoadClass with access check)"); + } + } + + /// CHECK-START: boolean Main.testInstanceOf() register (after) + /// CHECK: InstanceOf + public static boolean testInstanceOf() { + return ic instanceof InaccessibleClass; + } + + /// CHECK-START: boolean Main.testInstanceOfNull() register (after) + /// CHECK: InstanceOf + public static boolean testInstanceOfNull() { + return null instanceof InaccessibleClass; + } + + // TODO: write a test for for CheckCast with not null constant (after RTP can parse arguments). + + /// CHECK-START: other.InaccessibleClass Main.testCheckCastNull() register (after) + /// CHECK: CheckCast + public static InaccessibleClass testCheckCastNull() { + return (InaccessibleClass) null; + } + + /// CHECK-START: boolean Main.testDontGvnLoadClassWithAccessChecks(java.lang.Object) inliner (before) + /// CHECK: InvokeStaticOrDirect + + /// CHECK-START: boolean Main.testDontGvnLoadClassWithAccessChecks(java.lang.Object) inliner (after) + /// CHECK-NOT: InvokeStaticOrDirect + + /// CHECK-START: boolean Main.testDontGvnLoadClassWithAccessChecks(java.lang.Object) GVN (after) + /// CHECK: LoadClass needs_access_check:false + /// CHECK: LoadClass needs_access_check:true + public static boolean testDontGvnLoadClassWithAccessChecks(Object o) { + InaccessibleClassProxy.test(o); + return ic instanceof InaccessibleClass; + } + + public static InaccessibleClass ic; +} diff --git a/test/536-checker-needs-access-check/src/other/InaccessibleClass.java b/test/536-checker-needs-access-check/src/other/InaccessibleClass.java new file mode 100644 index 0000000000..de2e1d7830 --- /dev/null +++ b/test/536-checker-needs-access-check/src/other/InaccessibleClass.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +package other; + +public class InaccessibleClass { +} diff --git a/test/536-checker-needs-access-check/src/other/InaccessibleClassProxy.java b/test/536-checker-needs-access-check/src/other/InaccessibleClassProxy.java new file mode 100644 index 0000000000..4c005e4dfe --- /dev/null +++ b/test/536-checker-needs-access-check/src/other/InaccessibleClassProxy.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package other; + +public class InaccessibleClassProxy { + public static boolean test(Object o) { + return o instanceof InaccessibleClass; + } +} diff --git a/test/536-checker-needs-access-check/src2/other/InaccessibleClass.java b/test/536-checker-needs-access-check/src2/other/InaccessibleClass.java new file mode 100644 index 0000000000..273226375e --- /dev/null +++ b/test/536-checker-needs-access-check/src2/other/InaccessibleClass.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +package other; + +/*package*/ class InaccessibleClass { +} diff --git a/test/536-checker-needs-access-check/src2/other/InaccessibleClassProxy.java b/test/536-checker-needs-access-check/src2/other/InaccessibleClassProxy.java new file mode 100644 index 0000000000..4c005e4dfe --- /dev/null +++ b/test/536-checker-needs-access-check/src2/other/InaccessibleClassProxy.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +package other; + +public class InaccessibleClassProxy { + public static boolean test(Object o) { + return o instanceof InaccessibleClass; + } +} diff --git a/test/537-checker-arraycopy/expected.txt b/test/537-checker-arraycopy/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/537-checker-arraycopy/expected.txt diff --git a/test/537-checker-arraycopy/info.txt b/test/537-checker-arraycopy/info.txt new file mode 100644 index 0000000000..ea88f89306 --- /dev/null +++ b/test/537-checker-arraycopy/info.txt @@ -0,0 +1 @@ +Test for edge cases of System.arraycopy. diff --git a/test/537-checker-arraycopy/src/Main.java b/test/537-checker-arraycopy/src/Main.java new file mode 100644 index 0000000000..30ccc56b80 --- /dev/null +++ b/test/537-checker-arraycopy/src/Main.java @@ -0,0 +1,71 @@ +/* + * 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 void main(String[] args) { + arraycopy(); + try { + arraycopy(new Object()); + throw new Error("Should not be here"); + } catch (ArrayStoreException ase) { + // Ignore. + } + try { + arraycopy(null); + throw new Error("Should not be here"); + } catch (NullPointerException npe) { + // Ignore. + } + + try { + arraycopy(new Object[1]); + throw new Error("Should not be here"); + } catch (ArrayIndexOutOfBoundsException aiooe) { + // Ignore. + } + + arraycopy(new Object[2]); + arraycopy(new Object[2], 0); + + try { + arraycopy(new Object[1], 1); + throw new Error("Should not be here"); + } catch (ArrayIndexOutOfBoundsException aiooe) { + // Ignore. + } + } + + /// CHECK-START-X86_64: void Main.arraycopy() disassembly (after) + /// CHECK: InvokeStaticOrDirect + /// CHECK-NOT: test + /// CHECK-NOT: call + /// CHECK: ReturnVoid + // Checks that the call is intrinsified and that there is no test instruction + // when we know the source and destination are not null. + public static void arraycopy() { + Object[] obj = new Object[4]; + System.arraycopy(obj, 1, obj, 0, 1); + } + + public static void arraycopy(Object obj) { + System.arraycopy(obj, 1, obj, 0, 1); + } + + public static void arraycopy(Object[] obj, int pos) { + System.arraycopy(obj, pos, obj, 0, obj.length); + } +} diff --git a/test/537-checker-debuggable/expected.txt b/test/537-checker-debuggable/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/537-checker-debuggable/expected.txt diff --git a/test/537-checker-debuggable/info.txt b/test/537-checker-debuggable/info.txt new file mode 100644 index 0000000000..25597d3f13 --- /dev/null +++ b/test/537-checker-debuggable/info.txt @@ -0,0 +1 @@ +Test that CHECK-START-DEBUGGABLE runs only on --debuggable code.
\ No newline at end of file diff --git a/test/537-checker-debuggable/smali/TestCase.smali b/test/537-checker-debuggable/smali/TestCase.smali new file mode 100644 index 0000000000..8e6c7ef727 --- /dev/null +++ b/test/537-checker-debuggable/smali/TestCase.smali @@ -0,0 +1,42 @@ +# 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; + +# The phi in this method has no actual uses but one environment use. It will +# be eliminated in normal mode but kept live in debuggable mode. Test that +# Checker runs the correct test for each compilation mode. + +## CHECK-START: int TestCase.deadPhi(int, int, int) ssa_builder (after) +## CHECK-NOT: Phi + +## CHECK-START-DEBUGGABLE: int TestCase.deadPhi(int, int, int) ssa_builder (after) +## CHECK: Phi + +.method public static deadPhi(III)I + .registers 8 + + move v0, p1 + if-eqz p0, :after + move v0, p2 + :after + # v0 = Phi [p1, p2] with no uses + + invoke-static {}, Ljava/lang/System;->nanoTime()J # create an env use + + :return + return p2 +.end method diff --git a/test/537-checker-debuggable/src/Main.java b/test/537-checker-debuggable/src/Main.java new file mode 100644 index 0000000000..a572648109 --- /dev/null +++ b/test/537-checker-debuggable/src/Main.java @@ -0,0 +1,23 @@ +/* + * 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/537-checker-inline-and-unverified/expected.txt b/test/537-checker-inline-and-unverified/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/537-checker-inline-and-unverified/expected.txt diff --git a/test/537-checker-inline-and-unverified/info.txt b/test/537-checker-inline-and-unverified/info.txt new file mode 100644 index 0000000000..ec12327408 --- /dev/null +++ b/test/537-checker-inline-and-unverified/info.txt @@ -0,0 +1 @@ +Checks that unverified methods are not inlined. diff --git a/test/537-checker-inline-and-unverified/src/Main.java b/test/537-checker-inline-and-unverified/src/Main.java new file mode 100644 index 0000000000..bdc14b027c --- /dev/null +++ b/test/537-checker-inline-and-unverified/src/Main.java @@ -0,0 +1,59 @@ +/* + * 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 other.InaccessibleClass; + +public class Main { + public static void main(String[] args) { + try { + testNoInline(); + } catch (IllegalAccessError e) { + // expected + } + testInline(); + } + + /// CHECK-START: void Main.testNoInline() inliner (before) + /// CHECK: InvokeStaticOrDirect method_name:Main.$opt$noinline$testNoInline + + /// CHECK-START: void Main.testNoInline() inliner (after) + /// CHECK: InvokeStaticOrDirect method_name:Main.$opt$noinline$testNoInline + public static void testNoInline() { + $opt$noinline$testNoInline(); + } + + /// CHECK-START: void Main.testInline() inliner (before) + /// CHECK: InvokeStaticOrDirect method_name:Main.$opt$inline$testInline + + /// CHECK-START: void Main.testInline() inliner (after) + /// CHECK-NOT: InvokeStaticOrDirect + public static void testInline() { + $opt$inline$testInline(); + } + + public static boolean $opt$noinline$testNoInline() { + try { + return null instanceof InaccessibleClass; + } catch (IllegalAccessError e) { + // expected + } + return false; + } + + public static boolean $opt$inline$testInline() { + return null instanceof Main; + } +} diff --git a/test/537-checker-inline-and-unverified/src/other/InaccessibleClass.java b/test/537-checker-inline-and-unverified/src/other/InaccessibleClass.java new file mode 100644 index 0000000000..de2e1d7830 --- /dev/null +++ b/test/537-checker-inline-and-unverified/src/other/InaccessibleClass.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +package other; + +public class InaccessibleClass { +} diff --git a/test/537-checker-inline-and-unverified/src2/other/InaccessibleClass.java b/test/537-checker-inline-and-unverified/src2/other/InaccessibleClass.java new file mode 100644 index 0000000000..ff11d7adc9 --- /dev/null +++ b/test/537-checker-inline-and-unverified/src2/other/InaccessibleClass.java @@ -0,0 +1,20 @@ +/* + * 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. + */ + +package other; + +/* package */ class InaccessibleClass { +} diff --git a/test/538-checker-embed-constants/expected.txt b/test/538-checker-embed-constants/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/538-checker-embed-constants/expected.txt diff --git a/test/538-checker-embed-constants/info.txt b/test/538-checker-embed-constants/info.txt new file mode 100644 index 0000000000..5a722ecf12 --- /dev/null +++ b/test/538-checker-embed-constants/info.txt @@ -0,0 +1 @@ +Test embedding of constants in assembler instructions. diff --git a/test/538-checker-embed-constants/src/Main.java b/test/538-checker-embed-constants/src/Main.java new file mode 100644 index 0000000000..d8618e30fb --- /dev/null +++ b/test/538-checker-embed-constants/src/Main.java @@ -0,0 +1,290 @@ +/* + * 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 void assertIntEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void assertLongEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + /// CHECK-START-ARM: int Main.and255(int) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #255 + /// CHECK: and {{r\d+}}, {{r\d+}}, #255 + + public static int and255(int arg) { + return arg & 255; + } + + /// CHECK-START-ARM: int Main.and511(int) disassembly (after) + /// CHECK: movw {{r\d+}}, #511 + /// CHECK: and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + + public static int and511(int arg) { + return arg & 511; + } + + /// CHECK-START-ARM: int Main.andNot15(int) disassembly (after) + /// CHECK-NOT: mvn {{r\d+}}, #15 + /// CHECK: bic {{r\d+}}, {{r\d+}}, #15 + + public static int andNot15(int arg) { + return arg & ~15; + } + + /// CHECK-START-ARM: int Main.or255(int) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #255 + /// CHECK: orr {{r\d+}}, {{r\d+}}, #255 + + public static int or255(int arg) { + return arg | 255; + } + + /// CHECK-START-ARM: int Main.or511(int) disassembly (after) + /// CHECK: movw {{r\d+}}, #511 + /// CHECK: orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + + public static int or511(int arg) { + return arg | 511; + } + + /// CHECK-START-ARM: int Main.orNot15(int) disassembly (after) + /// CHECK-NOT: mvn {{r\d+}}, #15 + /// CHECK: orn {{r\d+}}, {{r\d+}}, #15 + + public static int orNot15(int arg) { + return arg | ~15; + } + + /// CHECK-START-ARM: int Main.xor255(int) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #255 + /// CHECK: eor {{r\d+}}, {{r\d+}}, #255 + + public static int xor255(int arg) { + return arg ^ 255; + } + + /// CHECK-START-ARM: int Main.xor511(int) disassembly (after) + /// CHECK: movw {{r\d+}}, #511 + /// CHECK: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + + public static int xor511(int arg) { + return arg ^ 511; + } + + /// CHECK-START-ARM: int Main.xorNot15(int) disassembly (after) + /// CHECK: mvn {{r\d+}}, #15 + /// CHECK: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + + public static int xorNot15(int arg) { + return arg ^ ~15; + } + + /// CHECK-START-ARM: long Main.and255(long) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #255 + /// CHECK-NOT: and + /// CHECK-NOT: bic + /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #255 + /// CHECK-DAG: movs {{r\d+}}, #0 + /// CHECK-NOT: and + /// CHECK-NOT: bic + + public static long and255(long arg) { + return arg & 255L; + } + + /// CHECK-START-ARM: long Main.and511(long) disassembly (after) + /// CHECK: movw {{r\d+}}, #511 + /// CHECK-NOT: and + /// CHECK-NOT: bic + /// CHECK-DAG: and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + /// CHECK-DAG: movs {{r\d+}}, #0 + /// CHECK-NOT: and + /// CHECK-NOT: bic + + public static long and511(long arg) { + return arg & 511L; + } + + /// CHECK-START-ARM: long Main.andNot15(long) disassembly (after) + /// CHECK-NOT: mvn {{r\d+}}, #15 + /// CHECK-NOT: and + /// CHECK-NOT: bic + /// CHECK: bic {{r\d+}}, {{r\d+}}, #15 + /// CHECK-NOT: and + /// CHECK-NOT: bic + + public static long andNot15(long arg) { + return arg & ~15L; + } + + /// CHECK-START-ARM: long Main.and0xfffffff00000000f(long) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #15 + /// CHECK-NOT: mvn {{r\d+}}, #15 + /// CHECK-NOT: and + /// CHECK-NOT: bic + /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #15 + /// CHECK-DAG: bic {{r\d+}}, {{r\d+}}, #15 + /// CHECK-NOT: and + /// CHECK-NOT: bic + + public static long and0xfffffff00000000f(long arg) { + return arg & 0xfffffff00000000fL; + } + + /// CHECK-START-ARM: long Main.or255(long) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #255 + /// CHECK-NOT: orr + /// CHECK-NOT: orn + /// CHECK: orr {{r\d+}}, {{r\d+}}, #255 + /// CHECK-NOT: orr + /// CHECK-NOT: orn + + public static long or255(long arg) { + return arg | 255L; + } + + /// CHECK-START-ARM: long Main.or511(long) disassembly (after) + /// CHECK: movw {{r\d+}}, #511 + /// CHECK-NOT: orr + /// CHECK-NOT: orn + /// CHECK: orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + /// CHECK-NOT: orr + /// CHECK-NOT: orn + + public static long or511(long arg) { + return arg | 511L; + } + + /// CHECK-START-ARM: long Main.orNot15(long) disassembly (after) + /// CHECK-NOT: mvn {{r\d+}}, #15 + /// CHECK-NOT: orr + /// CHECK-NOT: orn + /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15 + /// CHECK-DAG: mvn {{r\d+}}, #0 + /// CHECK-NOT: orr + /// CHECK-NOT: orn + + public static long orNot15(long arg) { + return arg | ~15L; + } + + /// CHECK-START-ARM: long Main.or0xfffffff00000000f(long) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #15 + /// CHECK-NOT: mvn {{r\d+}}, #15 + /// CHECK-NOT: orr + /// CHECK-NOT: orn + /// CHECK-DAG: orr {{r\d+}}, {{r\d+}}, #15 + /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15 + /// CHECK-NOT: orr + /// CHECK-NOT: orn + + public static long or0xfffffff00000000f(long arg) { + return arg | 0xfffffff00000000fL; + } + + /// CHECK-START-ARM: long Main.xor255(long) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #255 + /// CHECK-NOT: eor + /// CHECK: eor {{r\d+}}, {{r\d+}}, #255 + /// CHECK-NOT: eor + + public static long xor255(long arg) { + return arg ^ 255L; + } + + /// CHECK-START-ARM: long Main.xor511(long) disassembly (after) + /// CHECK: movw {{r\d+}}, #511 + /// CHECK-NOT: eor + /// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + /// CHECK-NOT: eor + + public static long xor511(long arg) { + return arg ^ 511L; + } + + /// CHECK-START-ARM: long Main.xorNot15(long) disassembly (after) + /// CHECK-DAG: mvn {{r\d+}}, #15 + /// CHECK-DAG: mov.w {{r\d+}}, #-1 + /// CHECK-NOT: eor + /// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + /// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + /// CHECK-NOT: eor + + public static long xorNot15(long arg) { + return arg ^ ~15L; + } + + // Note: No support for partial long constant embedding. + /// CHECK-START-ARM: long Main.xor0xfffffff00000000f(long) disassembly (after) + /// CHECK-DAG: movs {{r\d+}}, #15 + /// CHECK-DAG: mvn {{r\d+}}, #15 + /// CHECK-NOT: eor + /// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + /// CHECK-DAG: eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}} + /// CHECK-NOT: eor + + public static long xor0xfffffff00000000f(long arg) { + return arg ^ 0xfffffff00000000fL; + } + + /// CHECK-START-ARM: long Main.xor0xf00000000000000f(long) disassembly (after) + /// CHECK-NOT: movs {{r\d+}}, #15 + /// CHECK-NOT: mov.w {{r\d+}}, #-268435456 + /// CHECK-NOT: eor + /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #15 + /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #-268435456 + /// CHECK-NOT: eor + + public static long xor0xf00000000000000f(long arg) { + return arg ^ 0xf00000000000000fL; + } + + public static void main(String[] args) { + int arg = 0x87654321; + assertIntEquals(and255(arg), 0x21); + assertIntEquals(and511(arg), 0x121); + assertIntEquals(andNot15(arg), 0x87654320); + assertIntEquals(or255(arg), 0x876543ff); + assertIntEquals(or511(arg), 0x876543ff); + assertIntEquals(orNot15(arg), 0xfffffff1); + assertIntEquals(xor255(arg), 0x876543de); + assertIntEquals(xor511(arg), 0x876542de); + assertIntEquals(xorNot15(arg), 0x789abcd1); + + long longArg = 0x1234567887654321L; + assertLongEquals(and255(longArg), 0x21L); + assertLongEquals(and511(longArg), 0x121L); + assertLongEquals(andNot15(longArg), 0x1234567887654320L); + assertLongEquals(and0xfffffff00000000f(longArg), 0x1234567000000001L); + assertLongEquals(or255(longArg), 0x12345678876543ffL); + assertLongEquals(or511(longArg), 0x12345678876543ffL); + assertLongEquals(orNot15(longArg), 0xfffffffffffffff1L); + assertLongEquals(or0xfffffff00000000f(longArg), 0xfffffff88765432fL); + assertLongEquals(xor255(longArg), 0x12345678876543deL); + assertLongEquals(xor511(longArg), 0x12345678876542deL); + assertLongEquals(xorNot15(longArg), 0xedcba987789abcd1L); + assertLongEquals(xor0xfffffff00000000f(longArg), 0xedcba9888765432eL); + assertLongEquals(xor0xf00000000000000f(longArg), 0xe23456788765432eL); + } +} diff --git a/test/539-checker-arm64-encodable-immediates/expected.txt b/test/539-checker-arm64-encodable-immediates/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/539-checker-arm64-encodable-immediates/expected.txt diff --git a/test/539-checker-arm64-encodable-immediates/info.txt b/test/539-checker-arm64-encodable-immediates/info.txt new file mode 100644 index 0000000000..efeef33231 --- /dev/null +++ b/test/539-checker-arm64-encodable-immediates/info.txt @@ -0,0 +1,2 @@ +Basic tests that check the compiler recognizes when constant values can be +encoded in the immediate field of instructions. diff --git a/test/539-checker-arm64-encodable-immediates/src/Main.java b/test/539-checker-arm64-encodable-immediates/src/Main.java new file mode 100644 index 0000000000..7e3ff9fde8 --- /dev/null +++ b/test/539-checker-arm64-encodable-immediates/src/Main.java @@ -0,0 +1,52 @@ +/* + * 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 void assertLongEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + /** + * Test that the `-1` constant is not synthesized in a register and that we + * instead simply switch between `add` and `sub` instructions with the + * constant embedded. + * We need two uses (or more) of the constant because the compiler always + * delegates the immediate value handling to VIXL when there is only one use. + */ + + /// CHECK-START-ARM64: long Main.addM1(long) register (after) + /// CHECK: <<Arg:j\d+>> ParameterValue + /// CHECK: <<ConstM1:j\d+>> LongConstant -1 + /// CHECK-NOT: ParallelMove + /// CHECK: Add [<<Arg>>,<<ConstM1>>] + /// CHECK: Sub [<<Arg>>,<<ConstM1>>] + + /// CHECK-START-ARM64: long Main.addM1(long) disassembly (after) + /// CHECK: sub x{{\d+}}, x{{\d+}}, #0x1 + /// CHECK: add x{{\d+}}, x{{\d+}}, #0x1 + + public static long addM1(long arg) { + return (arg + (-1)) | (arg - (-1)); + } + + public static void main(String[] args) { + assertLongEquals(14, addM1(7)); + } +} diff --git a/test/540-checker-rtp-bug/expected.txt b/test/540-checker-rtp-bug/expected.txt new file mode 100644 index 0000000000..2cf2842aa5 --- /dev/null +++ b/test/540-checker-rtp-bug/expected.txt @@ -0,0 +1 @@ +instanceof failed diff --git a/test/540-checker-rtp-bug/info.txt b/test/540-checker-rtp-bug/info.txt new file mode 100644 index 0000000000..852cd7c1b4 --- /dev/null +++ b/test/540-checker-rtp-bug/info.txt @@ -0,0 +1 @@ +Test that we set the proper types for objects (b/25008765). diff --git a/test/540-checker-rtp-bug/src/Main.java b/test/540-checker-rtp-bug/src/Main.java new file mode 100644 index 0000000000..e9f16c04d9 --- /dev/null +++ b/test/540-checker-rtp-bug/src/Main.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +final class Final { + public String toString() { + return "final"; + } +} + +public class Main { + /// CHECK-START: Final Main.testKeepCheckCast(java.lang.Object, boolean) reference_type_propagation (after) + /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object + /// CHECK: <<Class:l\d+>> LoadClass + /// CHECK: CheckCast [<<Phi>>,<<Class>>] + /// CHECK: <<Ret:l\d+>> BoundType [<<Phi>>] klass:Final + /// CHECK: Return [<<Ret>>] + + /// CHECK-START: Final Main.testKeepCheckCast(java.lang.Object, boolean) instruction_simplifier_after_types (after) + /// CHECK: <<Phi:l\d+>> Phi + /// CHECK: <<Class:l\d+>> LoadClass + /// CHECK: CheckCast [<<Phi>>,<<Class>>] + /// CHECK: <<Ret:l\d+>> BoundType [<<Phi>>] + /// CHECK: Return [<<Ret>>] + public static Final testKeepCheckCast(Object o, boolean cond) { + Object x = new Final(); + while (cond) { + x = o; + cond = false; + } + return (Final) x; + } + + /// CHECK-START: void Main.testKeepInstanceOf(java.lang.Object, boolean) reference_type_propagation (after) + /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object + /// CHECK: <<Class:l\d+>> LoadClass + /// CHECK: InstanceOf [<<Phi>>,<<Class>>] + + /// CHECK-START: void Main.testKeepInstanceOf(java.lang.Object, boolean) dead_code_elimination (after) + /// CHECK: <<Phi:l\d+>> Phi + /// CHECK: <<Class:l\d+>> LoadClass + /// CHECK: InstanceOf [<<Phi>>,<<Class>>] + public static void testKeepInstanceOf(Object o, boolean cond) { + Object x = new Final(); + while (cond) { + x = o; + cond = false; + } + if (x instanceof Final) { + System.out.println("instanceof succeed"); + } else { + System.out.println("instanceof failed"); + } + } + + /// CHECK-START: java.lang.String Main.testNoInline(java.lang.Object, boolean) reference_type_propagation (after) + /// CHECK: <<Phi:l\d+>> Phi klass:java.lang.Object + /// CHECK: <<NC:l\d+>> NullCheck [<<Phi>>] + /// CHECK: <<Ret:l\d+>> InvokeVirtual [<<NC>>] method_name:java.lang.Object.toString + /// CHECK: Return [<<Ret>>] + + /// CHECK-START: java.lang.String Main.testNoInline(java.lang.Object, boolean) inliner (after) + /// CHECK: <<Phi:l\d+>> Phi + /// CHECK: <<NC:l\d+>> NullCheck [<<Phi>>] + /// CHECK: <<Ret:l\d+>> InvokeVirtual [<<NC>>] method_name:java.lang.Object.toString + /// CHECK: Return [<<Ret>>] + public static String testNoInline(Object o, boolean cond) { + Object x = new Final(); + while (cond) { + x = o; + cond = false; + } + return x.toString(); + } + + public static void main(String[] args) { + try { + testKeepCheckCast(new Object(), true); + throw new Error("Expected check cast exception"); + } catch (ClassCastException e) { + // expected + } + + testKeepInstanceOf(new Object(), true); + + if ("final".equals(testNoInline(new Object(), true))) { + throw new Error("Bad inlining"); + } + } +} diff --git a/test/955-lambda-smali/run b/test/955-lambda-smali/run index 2aeca8c8fc..b7546801b9 100755 --- a/test/955-lambda-smali/run +++ b/test/955-lambda-smali/run @@ -15,4 +15,4 @@ # limitations under the License. # Ensure that the lambda experimental opcodes are turned on for dalvikvm and dex2oat -${RUN} "$@" --runtime-option -Xexperimental-lambdas -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental-lambdas +${RUN} "$@" --runtime-option -Xexperimental:lambdas -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:lambdas diff --git a/test/960-default-smali/build b/test/960-default-smali/build new file mode 100755 index 0000000000..c7866878e9 --- /dev/null +++ b/test/960-default-smali/build @@ -0,0 +1,33 @@ +#!/bin/bash +# +# Copyright 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. + +# make us exit on a failure +set -e + +# Generate the smali Main.smali file or fail +./util-src/generate_smali.py ./smali + +if [[ $@ == *"--jvm"* ]]; then + # Build the Java files if we are running a --jvm test + mkdir -p src + mkdir -p classes + ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src + ${JAVAC} -implicit:none -d classes $(find src -name '*.java') +fi + +# Build the smali files and make a dex +${SMALI} -JXmx256m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali') +zip "$TEST_NAME.jar" classes.dex diff --git a/test/960-default-smali/expected.txt b/test/960-default-smali/expected.txt new file mode 100644 index 0000000000..7671eed5de --- /dev/null +++ b/test/960-default-smali/expected.txt @@ -0,0 +1,84 @@ +Testing for type A +A-virtual A.SayHi()='Hi ' +A-interface Greeter.SayHi()='Hi ' +A-virtual A.SayHiTwice()='Hi Hi ' +A-interface Greeter.SayHiTwice()='Hi Hi ' +End testing for type A +Testing for type B +B-virtual B.SayHi()='Hello ' +B-interface Greeter.SayHi()='Hello ' +B-interface Greeter2.SayHi()='Hello ' +B-virtual B.SayHiTwice()='I say Hello Hello ' +B-interface Greeter.SayHiTwice()='I say Hello Hello ' +B-interface Greeter2.SayHiTwice()='I say Hello Hello ' +End testing for type B +Testing for type C +C-virtual A.SayHi()='Hi ' +C-virtual C.SayHi()='Hi ' +C-interface Greeter.SayHi()='Hi ' +C-virtual A.SayHiTwice()='You don't control me' +C-virtual C.SayHiTwice()='You don't control me' +C-interface Greeter.SayHiTwice()='You don't control me' +End testing for type C +Testing for type D +D-virtual D.GetName()='Alex ' +D-interface Greeter3.GetName()='Alex ' +D-virtual D.SayHi()='Hello Alex ' +D-interface Greeter.SayHi()='Hello Alex ' +D-interface Greeter3.SayHi()='Hello Alex ' +D-virtual D.SayHiTwice()='Hello Alex Hello Alex ' +D-interface Greeter.SayHiTwice()='Hello Alex Hello Alex ' +D-interface Greeter3.SayHiTwice()='Hello Alex Hello Alex ' +End testing for type D +Testing for type E +E-virtual A.SayHi()='Hi2 ' +E-virtual E.SayHi()='Hi2 ' +E-interface Greeter.SayHi()='Hi2 ' +E-interface Greeter2.SayHi()='Hi2 ' +E-virtual A.SayHiTwice()='I say Hi2 Hi2 ' +E-virtual E.SayHiTwice()='I say Hi2 Hi2 ' +E-interface Greeter.SayHiTwice()='I say Hi2 Hi2 ' +E-interface Greeter2.SayHiTwice()='I say Hi2 Hi2 ' +End testing for type E +Testing for type F +F-interface Attendant.GetPlace()='android' +F-virtual F.GetPlace()='android' +F-virtual A.SayHi()='Hi ' +F-interface Attendant.SayHi()='Hi ' +F-virtual F.SayHi()='Hi ' +F-interface Greeter.SayHi()='Hi ' +F-virtual A.SayHiTwice()='We can override both interfaces' +F-interface Attendant.SayHiTwice()='We can override both interfaces' +F-virtual F.SayHiTwice()='We can override both interfaces' +F-interface Greeter.SayHiTwice()='We can override both interfaces' +End testing for type F +Testing for type G +G-interface Attendant.GetPlace()='android' +G-virtual G.GetPlace()='android' +G-interface Attendant.SayHi()='welcome to android' +G-virtual G.SayHi()='welcome to android' +G-interface Attendant.SayHiTwice()='welcome to androidwelcome to android' +G-virtual G.SayHiTwice()='welcome to androidwelcome to android' +End testing for type G +Testing for type H +H-interface Extension.SayHi()='welcome ' +H-virtual H.SayHi()='welcome ' +End testing for type H +Testing for type I +I-virtual A.SayHi()='Hi ' +I-interface Greeter.SayHi()='Hi ' +I-interface Greeter2.SayHi()='Hi ' +I-virtual I.SayHi()='Hi ' +I-virtual A.SayHiTwice()='I say Hi Hi ' +I-interface Greeter.SayHiTwice()='I say Hi Hi ' +I-interface Greeter2.SayHiTwice()='I say Hi Hi ' +I-virtual I.SayHiTwice()='I say Hi Hi ' +End testing for type I +Testing for type J +J-virtual A.SayHi()='Hi ' +J-interface Greeter.SayHi()='Hi ' +J-virtual J.SayHi()='Hi ' +J-virtual A.SayHiTwice()='Hi Hi ' +J-interface Greeter.SayHiTwice()='Hi Hi ' +J-virtual J.SayHiTwice()='Hi Hi ' +End testing for type J diff --git a/test/960-default-smali/info.txt b/test/960-default-smali/info.txt new file mode 100644 index 0000000000..eb596e2c9f --- /dev/null +++ b/test/960-default-smali/info.txt @@ -0,0 +1,19 @@ +Smali-based tests for experimental interface default methods. + +Obviously needs to run under ART or a Java 8 Language runtime and compiler. + +When run a Main.smali file will be generated by the util-src/generate_smali.py +script. If we run with --jvm we will use the tools/extract-embedded-java script to +turn the smali into equivalent Java using the embedded Java code. + +When updating be sure to write the equivalent Java code in comments of the smali +files. + +Care should be taken when updating the generate_smali.py script. It must always +return equivalent output when run multiple times. + +To update the test files do the following steps: + <Add new classes/interfaces> + <Add these classes/interfaces to ./smali/classes.xml> + JAVA_HOME="/path/to/java-8-jdk" ../run-test --use-java-home --update --jvm --host 956-default-smali + git add ./smali/classes.xml ./expected.txt diff --git a/test/960-default-smali/run b/test/960-default-smali/run new file mode 100755 index 0000000000..e378b061d9 --- /dev/null +++ b/test/960-default-smali/run @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Copyright 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. + +if echo $@ | grep -q -- "--jvm"; then + ${RUN} "$@" +else + ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods +fi diff --git a/test/960-default-smali/smali/A.smali b/test/960-default-smali/smali/A.smali new file mode 100644 index 0000000000..e755612fbe --- /dev/null +++ b/test/960-default-smali/smali/A.smali @@ -0,0 +1,38 @@ +# /* +# * Copyright 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 LA; +.super Ljava/lang/Object; +.implements LGreeter; + +# class A implements Greeter { +# public String SayHi() { +# return "Hi "; +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public SayHi()Ljava/lang/String; + .registers 1 + + const-string v0, "Hi " + return-object v0 +.end method diff --git a/test/960-default-smali/smali/Attendant.smali b/test/960-default-smali/smali/Attendant.smali new file mode 100644 index 0000000000..ab63aeefcb --- /dev/null +++ b/test/960-default-smali/smali/Attendant.smali @@ -0,0 +1,53 @@ +# /* +# * Copyright 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 abstract interface LAttendant; +.super Ljava/lang/Object; + +# public interface Attendant { +# public default String SayHi() { +# return "welcome to " + GetPlace(); +# } +# public default String SayHiTwice() { +# return SayHi() + SayHi(); +# } +# +# public String GetPlace(); +# } + +.method public SayHi()Ljava/lang/String; + .locals 2 + const-string v0, "welcome to " + invoke-interface {p0}, LAttendant;->GetPlace()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + return-object v0 +.end method + +.method public SayHiTwice()Ljava/lang/String; + .locals 2 + invoke-interface {p0}, LAttendant;->SayHi()Ljava/lang/String; + move-result-object v0 + invoke-interface {p0}, LAttendant;->SayHi()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + return-object v0 +.end method + +.method public abstract GetPlace()Ljava/lang/String; +.end method diff --git a/test/960-default-smali/smali/B.smali b/test/960-default-smali/smali/B.smali new file mode 100644 index 0000000000..d847dd12ff --- /dev/null +++ b/test/960-default-smali/smali/B.smali @@ -0,0 +1,38 @@ +# /* +# * Copyright 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 LB; +.super Ljava/lang/Object; +.implements LGreeter2; + +# class B implements Greeter2 { +# public String SayHi() { +# return "Hello "; +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public SayHi()Ljava/lang/String; + .registers 1 + + const-string v0, "Hello " + return-object v0 +.end method diff --git a/test/960-default-smali/smali/C.smali b/test/960-default-smali/smali/C.smali new file mode 100644 index 0000000000..08a8508be1 --- /dev/null +++ b/test/960-default-smali/smali/C.smali @@ -0,0 +1,37 @@ +# /* +# * Copyright 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 LC; +.super LA; + +# class C extends A { +# public String SayHiTwice() { +# return "You don't control me"; +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, LA;-><init>()V + return-void +.end method + +.method public SayHiTwice()Ljava/lang/String; + .registers 1 + + const-string v0, "You don't control me" + return-object v0 +.end method diff --git a/test/960-default-smali/smali/D.smali b/test/960-default-smali/smali/D.smali new file mode 100644 index 0000000000..32f3b7ec8b --- /dev/null +++ b/test/960-default-smali/smali/D.smali @@ -0,0 +1,38 @@ +# /* +# * Copyright 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 LD; +.super Ljava/lang/Object; +.implements LGreeter3; + +# class D implements Greeter3 { +# public String GetName() { +# return "Alex "; +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public GetName()Ljava/lang/String; + .registers 1 + + const-string v0, "Alex " + return-object v0 +.end method diff --git a/test/960-default-smali/smali/E.smali b/test/960-default-smali/smali/E.smali new file mode 100644 index 0000000000..bae6250414 --- /dev/null +++ b/test/960-default-smali/smali/E.smali @@ -0,0 +1,38 @@ +# /* +# * Copyright 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 LE; +.super LA; +.implements LGreeter2; + +# class E extends A implements Greeter2 { +# public String SayHi() { +# return "Hi2 "; +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, LA;-><init>()V + return-void +.end method + +.method public SayHi()Ljava/lang/String; + .registers 1 + + const-string v0, "Hi2 " + return-object v0 +.end method diff --git a/test/960-default-smali/smali/Extension.smali b/test/960-default-smali/smali/Extension.smali new file mode 100644 index 0000000000..60ffa26ec6 --- /dev/null +++ b/test/960-default-smali/smali/Extension.smali @@ -0,0 +1,30 @@ +# /* +# * Copyright 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 abstract interface LExtension; +.super Ljava/lang/Object; + +# public interface Extension { +# public default String SayHi() { +# return "welcome "; +# } +# } + +.method public SayHi()Ljava/lang/String; + .locals 1 + const-string v0, "welcome " + return-object v0 +.end method diff --git a/test/960-default-smali/smali/F.smali b/test/960-default-smali/smali/F.smali new file mode 100644 index 0000000000..3eaa089e1f --- /dev/null +++ b/test/960-default-smali/smali/F.smali @@ -0,0 +1,47 @@ +# /* +# * Copyright 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 LF; +.super LA; +.implements LAttendant; + +# class F extends A implements Attendant { +# public String GetPlace() { +# return "android"; +# } +# public String SayHiTwice() { +# return "We can override both interfaces"; +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public SayHiTwice()Ljava/lang/String; + .registers 1 + + const-string v0, "We can override both interfaces" + return-object v0 +.end method + +.method public GetPlace()Ljava/lang/String; + .registers 1 + const-string v0, "android" + return-object v0 +.end method diff --git a/test/960-default-smali/smali/G.smali b/test/960-default-smali/smali/G.smali new file mode 100644 index 0000000000..446f2a4c64 --- /dev/null +++ b/test/960-default-smali/smali/G.smali @@ -0,0 +1,37 @@ +# /* +# * Copyright 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 LG; +.super Ljava/lang/Object; +.implements LAttendant; + +# class G implements Attendant { +# public String GetPlace() { +# return "android"; +# } +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public GetPlace()Ljava/lang/String; + .registers 1 + const-string v0, "android" + return-object v0 +.end method diff --git a/test/960-default-smali/smali/Greeter.smali b/test/960-default-smali/smali/Greeter.smali new file mode 100644 index 0000000000..28530ffc6f --- /dev/null +++ b/test/960-default-smali/smali/Greeter.smali @@ -0,0 +1,40 @@ +# /* +# * Copyright 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 abstract interface LGreeter; +.super Ljava/lang/Object; + +# public interface Greeter { +# public String SayHi(); +# +# public default String SayHiTwice() { +# return SayHi() + SayHi(); +# } +# } + +.method public abstract SayHi()Ljava/lang/String; +.end method + +.method public SayHiTwice()Ljava/lang/String; + .locals 2 + invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String; + move-result-object v0 + invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + return-object v0 +.end method diff --git a/test/960-default-smali/smali/Greeter2.smali b/test/960-default-smali/smali/Greeter2.smali new file mode 100644 index 0000000000..ace1798bab --- /dev/null +++ b/test/960-default-smali/smali/Greeter2.smali @@ -0,0 +1,39 @@ +# /* +# * Copyright 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 abstract interface LGreeter2; +.super Ljava/lang/Object; +.implements LGreeter; + +# public interface Greeter2 extends Greeter { +# public default String SayHiTwice() { +# return "I say " + SayHi() + SayHi(); +# } +# } + +.method public SayHiTwice()Ljava/lang/String; + .locals 3 + const-string v0, "I say " + invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + invoke-interface {p0}, LGreeter;->SayHi()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + return-object v0 +.end method diff --git a/test/960-default-smali/smali/Greeter3.smali b/test/960-default-smali/smali/Greeter3.smali new file mode 100644 index 0000000000..31fc2e79ff --- /dev/null +++ b/test/960-default-smali/smali/Greeter3.smali @@ -0,0 +1,40 @@ +# /* +# * Copyright 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 abstract interface LGreeter3; +.super Ljava/lang/Object; +.implements LGreeter; + +# public interface Greeter3 extends Greeter { +# public String GetName(); +# +# public default String SayHi() { +# return "Hello " + GetName(); +# } +# } + +.method public abstract GetName()Ljava/lang/String; +.end method + +.method public SayHi()Ljava/lang/String; + .locals 2 + const-string v0, "Hello " + invoke-interface {p0}, LGreeter3;->GetName()Ljava/lang/String; + move-result-object v1 + invoke-virtual {v0, v1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + return-object v0 +.end method diff --git a/test/960-default-smali/smali/H.smali b/test/960-default-smali/smali/H.smali new file mode 100644 index 0000000000..82065ea49d --- /dev/null +++ b/test/960-default-smali/smali/H.smali @@ -0,0 +1,28 @@ +# /* +# * Copyright 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 LH; +.super Ljava/lang/Object; +.implements LExtension; + +# class H implements Extension { +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method diff --git a/test/960-default-smali/smali/I.smali b/test/960-default-smali/smali/I.smali new file mode 100644 index 0000000000..72fb58afe4 --- /dev/null +++ b/test/960-default-smali/smali/I.smali @@ -0,0 +1,28 @@ +# /* +# * Copyright 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 LI; +.super LA; +.implements LGreeter2; + +# class I extends A implements Greeter2 { +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method diff --git a/test/960-default-smali/smali/J.smali b/test/960-default-smali/smali/J.smali new file mode 100644 index 0000000000..93f3d6231c --- /dev/null +++ b/test/960-default-smali/smali/J.smali @@ -0,0 +1,29 @@ +# /* +# * Copyright 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 LJ; +.super LA; + +# class J extends A { +# } + + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, LA;-><init>()V + return-void +.end method + diff --git a/test/960-default-smali/smali/classes.xml b/test/960-default-smali/smali/classes.xml new file mode 100644 index 0000000000..0aa41f7fb6 --- /dev/null +++ b/test/960-default-smali/smali/classes.xml @@ -0,0 +1,127 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 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. +--> + +<data> + <classes> + <class name="A" super="java/lang/Object"> + <implements> + <item>Greeter</item> + </implements> + <methods> </methods> + </class> + + <class name="B" super="java/lang/Object"> + <implements> + <item>Greeter2</item> + </implements> + <methods> </methods> + </class> + + <class name="C" super="A"> + <implements> </implements> + <methods> </methods> + </class> + + <class name="D" super="java/lang/Object"> + <implements> + <item>Greeter3</item> + </implements> + <methods> </methods> + </class> + + <class name="E" super="A"> + <implements> + <item>Greeter2</item> + </implements> + <methods> </methods> + </class> + + <class name="F" super="A"> + <implements> + <item>Attendant</item> + </implements> + <methods> </methods> + </class> + + <class name="G" super="java/lang/Object"> + <implements> + <item>Attendant</item> + </implements> + <methods> </methods> + </class> + + <class name="H" super="java/lang/Object"> + <implements> + <item>Extension</item> + </implements> + <methods> </methods> + </class> + + <class name="I" super="A"> + <implements> + <item>Greeter2</item> + </implements> + <methods> </methods> + </class> + + <class name="J" super="A"> + <implements> </implements> + <methods> </methods> + </class> + </classes> + + <interfaces> + <interface name="Extension" super="java/lang/Object"> + <implements> </implements> + <methods> + <method type="default">SayHi</method> + </methods> + </interface> + + <interface name="Greeter" super="java/lang/Object"> + <implements> </implements> + <methods> + <method type="abstract">SayHi</method> + <method type="default">SayHiTwice</method> + </methods> + </interface> + + <interface name="Greeter2" super="java/lang/Object"> + <implements> + <item>Greeter</item> + </implements> + <methods> </methods> + </interface> + + <interface name="Greeter3" super="java/lang/Object"> + <implements> + <item>Greeter</item> + </implements> + <methods> + <method type="abstract">GetName</method> + </methods> + </interface> + + <interface name="Attendant" super="java/lang/Object"> + <implements> </implements> + <methods> + <method type="default">SayHi</method> + <method type="default">SayHiTwice</method> + <method type="abstract">GetPlace</method> + </methods> + </interface> + </interfaces> +</data> diff --git a/test/960-default-smali/util-src/generate_smali.py b/test/960-default-smali/util-src/generate_smali.py new file mode 100755 index 0000000000..b2bf1f0761 --- /dev/null +++ b/test/960-default-smali/util-src/generate_smali.py @@ -0,0 +1,376 @@ +#!/usr/bin/python3 +# +# 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. + +""" +Generate Smali Main file for test 960 +""" + +import os +import sys +from pathlib import Path + +BUILD_TOP = os.getenv("ANDROID_BUILD_TOP") +if BUILD_TOP is None: + print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr) + sys.exit(1) + +# Allow us to import utils and mixins. +sys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python")) + +from testgen.utils import get_copyright +import testgen.mixins as mixins + +from collections import namedtuple +import itertools +import functools +import xml.etree.ElementTree as ET + +class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin): + """ + A mainclass and main method for this test. + """ + + MAIN_CLASS_TEMPLATE = """{copyright} +.class public LMain; +.super Ljava/lang/Object; + +# class Main {{ + +.method public constructor <init>()V + .registers 1 + invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V + return-void +.end method + +{test_groups} + +{test_funcs} + +{main_func} + +# }} +""" + + MAIN_FUNCTION_TEMPLATE = """ +# public static void main(String[] args) {{ +.method public static main([Ljava/lang/String;)V + .locals 2 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + {test_group_invoke} + + return-void +.end method +# }} +""" + + TEST_GROUP_INVOKE_TEMPLATE = """ +# {test_name}(); + invoke-static {{}}, {test_name}()V +""" + + def __init__(self): + """ + Initialize this MainClass + """ + self.tests = set() + self.global_funcs = set() + + def add_instance(self, it): + """ + Add an instance test for the given class + """ + self.tests.add(it) + + def add_func(self, f): + """ + Add a function to the class + """ + self.global_funcs.add(f) + + def get_name(self): + """ + Get the name of this class + """ + return "Main" + + def __str__(self): + """ + Print this class + """ + all_tests = sorted(self.tests) + test_invoke = "" + test_groups = "" + for t in all_tests: + test_groups += str(t) + for t in sorted(all_tests): + test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name()) + main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke) + + funcs = "" + for f in self.global_funcs: + funcs += str(f) + return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), + test_groups=test_groups, + main_func=main_func, test_funcs=funcs) + + +class InstanceTest(mixins.Named, mixins.NameComparableMixin): + """ + A method that runs tests for a particular concrete type, It calls the test + cases for running it in all possible ways. + """ + + INSTANCE_TEST_TEMPLATE = """ +# public static void {test_name}() {{ +# System.out.println("Testing for type {ty}"); +# String s = "{ty}"; +# {ty} v = new {ty}(); +.method public static {test_name}()V + .locals 3 + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v0, "Testing for type {ty}" + invoke-virtual {{v2,v0}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + const-string v0, "{ty}" + new-instance v1, L{ty}; + invoke-direct {{v1}}, L{ty};-><init>()V + + {invokes} + + const-string v0, "End testing for type {ty}" + invoke-virtual {{v2,v0}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method +# System.out.println("End testing for type {ty}"); +# }} +""" + + TEST_INVOKE_TEMPLATE = """ +# {fname}(s, v); + invoke-static {{v0, v1}}, {fname}(Ljava/lang/String;L{farg};)V +""" + + def __init__(self, main, ty): + """ + Initialize this test group for the given type + """ + self.ty = ty + self.main = main + self.funcs = set() + self.main.add_instance(self) + + def get_name(self): + """ + Get the name of this test group + """ + return "TEST_NAME_"+self.ty + + def add_func(self, f): + """ + Add a test function to this test group + """ + self.main.add_func(f) + self.funcs.add(f) + + def __str__(self): + """ + Returns the smali code for this function + """ + func_invokes = "" + for f in sorted(self.funcs, key=lambda a: (a.func, a.farg)): + func_invokes += self.TEST_INVOKE_TEMPLATE.format(fname=f.get_name(), + farg=f.farg) + + return self.INSTANCE_TEST_TEMPLATE.format(test_name=self.get_name(), ty=self.ty, + invokes=func_invokes) + +class Func(mixins.Named, mixins.NameComparableMixin): + """ + A single test case that attempts to invoke a function on receiver of a given type. + """ + + TEST_FUNCTION_TEMPLATE = """ +# public static void {fname}(String s, {farg} v) {{ +# try {{ +# System.out.printf("%s-{invoke_type:<9} {farg:>9}.{callfunc}()='%s'\\n", s, v.{callfunc}()); +# return; +# }} catch (Error e) {{ +# System.out.printf("%s-{invoke_type} on {farg}: {callfunc}() threw exception!\\n", s); +# e.printStackTrace(System.out); +# }} +# }} +.method public static {fname}(Ljava/lang/String;L{farg};)V + .locals 7 + :call_{fname}_try_start + const/4 v0, 2 + new-array v1,v0, [Ljava/lang/Object; + const/4 v0, 0 + aput-object p0,v1,v0 + + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v3, "%s-{invoke_type:<9} {farg:>9}.{callfunc}()='%s'\\n" + + invoke-{invoke_type} {{p1}}, L{farg};->{callfunc}()Ljava/lang/String; + move-result-object v4 + const/4 v0, 1 + aput-object v4, v1, v0 + + invoke-virtual {{v2,v3,v1}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; + return-void + :call_{fname}_try_end + .catch Ljava/lang/Error; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start + :error_{fname}_start + move-exception v3 + const/4 v0, 1 + new-array v1,v0, [Ljava/lang/Object; + const/4 v0, 0 + aput-object p0, v1, v0 + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v4, "%s-{invoke_type} on {farg}: {callfunc}() threw exception!\\n" + invoke-virtual {{v2,v4,v1}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; + invoke-virtual {{v3,v2}}, Ljava/lang/Error;->printStackTrace(Ljava/io/PrintStream;)V + return-void +.end method +""" + + def __init__(self, func, farg, invoke): + """ + Initialize this test function for the given invoke type and argument + """ + self.func = func + self.farg = farg + self.invoke = invoke + + def get_name(self): + """ + Get the name of this test + """ + return "Test_Func_{}_{}_{}".format(self.func, self.farg, self.invoke) + + def __str__(self): + """ + Get the smali code for this test function + """ + return self.TEST_FUNCTION_TEMPLATE.format(fname=self.get_name(), + farg=self.farg, + invoke_type=self.invoke, + callfunc=self.func) + +def flatten_classes(classes, c): + """ + Iterate over all the classes 'c' can be used as + """ + while c: + yield c + c = classes.get(c.super_class) + +def flatten_class_methods(classes, c): + """ + Iterate over all the methods 'c' can call + """ + for c1 in flatten_classes(classes, c): + yield from c1.methods + +def flatten_interfaces(dat, c): + """ + Iterate over all the interfaces 'c' transitively implements + """ + def get_ifaces(cl): + for i2 in cl.implements: + yield dat.interfaces[i2] + yield from get_ifaces(dat.interfaces[i2]) + + for cl in flatten_classes(dat.classes, c): + yield from get_ifaces(cl) + +def flatten_interface_methods(dat, i): + """ + Iterate over all the interface methods 'c' can call + """ + yield from i.methods + for i2 in flatten_interfaces(dat, i): + yield from i2.methods + +def make_main_class(dat): + """ + Creates a Main.smali file that runs all the tests + """ + m = MainClass() + for c in dat.classes.values(): + i = InstanceTest(m, c.name) + for clazz in flatten_classes(dat.classes, c): + for meth in flatten_class_methods(dat.classes, clazz): + i.add_func(Func(meth, clazz.name, 'virtual')) + for iface in flatten_interfaces(dat, clazz): + for meth in flatten_interface_methods(dat, iface): + i.add_func(Func(meth, clazz.name, 'virtual')) + i.add_func(Func(meth, iface.name, 'interface')) + return m + +class TestData(namedtuple("TestData", ['classes', 'interfaces'])): + """ + A class representing the classes.xml document. + """ + pass + +class Clazz(namedtuple("Clazz", ["name", "methods", "super_class", "implements"])): + """ + A class representing a class element in the classes.xml document. + """ + pass + +class IFace(namedtuple("IFace", ["name", "methods", "super_class", "implements"])): + """ + A class representing an interface element in the classes.xml document. + """ + pass + +def parse_xml(xml): + """ + Parse the xml description of this test. + """ + classes = dict() + ifaces = dict() + root = ET.fromstring(xml) + for iface in root.find("interfaces"): + name = iface.attrib['name'] + implements = [a.text for a in iface.find("implements")] + methods = [a.text for a in iface.find("methods")] + ifaces[name] = IFace(name = name, + super_class = iface.attrib['super'], + methods = methods, + implements = implements) + for clazz in root.find('classes'): + name = clazz.attrib['name'] + implements = [a.text for a in clazz.find("implements")] + methods = [a.text for a in clazz.find("methods")] + classes[name] = Clazz(name = name, + super_class = clazz.attrib['super'], + methods = methods, + implements = implements) + return TestData(classes, ifaces) + +def main(argv): + smali_dir = Path(argv[1]) + if not smali_dir.exists() or not smali_dir.is_dir(): + print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr) + sys.exit(1) + class_data = parse_xml((smali_dir / "classes.xml").open().read()) + make_main_class(class_data).dump(smali_dir) + +if __name__ == '__main__': + main(sys.argv) diff --git a/test/961-default-iface-resolution-generated/build b/test/961-default-iface-resolution-generated/build new file mode 100755 index 0000000000..707c17e1cf --- /dev/null +++ b/test/961-default-iface-resolution-generated/build @@ -0,0 +1,47 @@ +#!/bin/bash +# +# Copyright 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. + +# make us exit on a failure +set -e + +mkdir -p ./smali + +# We will be making more files than the ulimit is set to allow. Remove it temporarily. +OLD_ULIMIT=`ulimit -S` +ulimit -S unlimited + +restore_ulimit() { + ulimit -S "$OLD_ULIMIT" +} +trap 'restore_ulimit' ERR + +# Generate the smali files and expected.txt or fail +./util-src/generate_smali.py ./smali ./expected.txt + +if [[ $@ == *"--jvm"* ]]; then + # Build the Java files if we are running a --jvm test + mkdir -p src + mkdir -p classes + ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src + ${JAVAC} -implicit:none -d classes $(find src -name '*.java') +fi + +# Build the smali files and make a dex +${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali') +zip $TEST_NAME.jar classes.dex + +# Reset the ulimit back to its initial value +restore_ulimit diff --git a/test/961-default-iface-resolution-generated/expected.txt b/test/961-default-iface-resolution-generated/expected.txt new file mode 100644 index 0000000000..1ddd65d177 --- /dev/null +++ b/test/961-default-iface-resolution-generated/expected.txt @@ -0,0 +1 @@ +This file is generated by util-src/generate_smali.py do not directly modify! diff --git a/test/961-default-iface-resolution-generated/info.txt b/test/961-default-iface-resolution-generated/info.txt new file mode 100644 index 0000000000..2cd2cc75b7 --- /dev/null +++ b/test/961-default-iface-resolution-generated/info.txt @@ -0,0 +1,17 @@ +Smali-based tests for experimental interface default methods. + +This tests that interface method resolution order is correct. + +Obviously needs to run under ART or a Java 8 Language runtime and compiler. + +When run smali test files are generated by the util-src/generate_smali.py +script. If we run with --jvm we will use the +$(ANDROID_BUILD_TOP)/art/tools/extract-embedded-java script to turn the smali +into equivalent Java using the embedded Java code. + +Care should be taken when updating the generate_smali.py script. It should always +return equivalent output when run multiple times and the expected output should +be valid. + +Do not modify the expected.txt file. It is generated on each run by +util-src/generate_smali.py. diff --git a/test/961-default-iface-resolution-generated/run b/test/961-default-iface-resolution-generated/run new file mode 100755 index 0000000000..e378b061d9 --- /dev/null +++ b/test/961-default-iface-resolution-generated/run @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Copyright 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. + +if echo $@ | grep -q -- "--jvm"; then + ${RUN} "$@" +else + ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods +fi diff --git a/test/961-default-iface-resolution-generated/util-src/generate_smali.py b/test/961-default-iface-resolution-generated/util-src/generate_smali.py new file mode 100755 index 0000000000..921a096dd3 --- /dev/null +++ b/test/961-default-iface-resolution-generated/util-src/generate_smali.py @@ -0,0 +1,466 @@ +#!/usr/bin/python3 +# +# 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. + +""" +Generate Smali test files for test 961. +""" + +import os +import sys +from pathlib import Path + +BUILD_TOP = os.getenv("ANDROID_BUILD_TOP") +if BUILD_TOP is None: + print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr) + sys.exit(1) + +# Allow us to import utils and mixins. +sys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python")) + +from testgen.utils import get_copyright, subtree_sizes, gensym, filter_blanks +import testgen.mixins as mixins + +from functools import total_ordering +import itertools +import string + +# The max depth the type tree can have. Includes the class object in the tree. +# Increasing this increases the number of generated files significantly. This +# value was chosen as it is fairly quick to run and very comprehensive, checking +# every possible interface tree up to 5 layers deep. +MAX_IFACE_DEPTH = 5 + +class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin): + """ + A Main.smali file containing the Main class and the main function. It will run + all the test functions we have. + """ + + MAIN_CLASS_TEMPLATE = """{copyright} + +.class public LMain; +.super Ljava/lang/Object; + +# class Main {{ + +.method public constructor <init>()V + .registers 1 + invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V + return-void +.end method + +{test_groups} + +{main_func} + +# }} +""" + + MAIN_FUNCTION_TEMPLATE = """ +# public static void main(String[] args) {{ +.method public static main([Ljava/lang/String;)V + .locals 2 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + {test_group_invoke} + + return-void +.end method +# }} +""" + + TEST_GROUP_INVOKE_TEMPLATE = """ +# {test_name}(); + invoke-static {{}}, {test_name}()V +""" + + def __init__(self): + """ + Initialize this MainClass. We start out with no tests. + """ + self.tests = set() + + def get_expected(self): + """ + Get the expected output of this test. + """ + all_tests = sorted(self.tests) + return filter_blanks("\n".join(a.get_expected() for a in all_tests)) + + def add_test(self, ty): + """ + Add a test for the concrete type 'ty' + """ + self.tests.add(Func(ty)) + + def get_name(self): + """ + Get the name of this class + """ + return "Main" + + def __str__(self): + """ + Print the MainClass smali code. + """ + all_tests = sorted(self.tests) + test_invoke = "" + test_groups = "" + for t in all_tests: + test_groups += str(t) + for t in all_tests: + test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name()) + main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke) + + return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright("smali"), + test_groups = test_groups, + main_func = main_func) + +class Func(mixins.Named, mixins.NameComparableMixin): + """ + A function that tests the functionality of a concrete type. Should only be + constructed by MainClass.add_test. + """ + + TEST_FUNCTION_TEMPLATE = """ +# public static void {fname}() {{ +# try {{ +# {farg} v = new {farg}(); +# System.out.printf("%s calls default method on %s\\n", +# v.CalledClassName(), +# v.CalledInterfaceName()); +# return; +# }} catch (Error e) {{ +# e.printStackTrace(System.out); +# return; +# }} +# }} +.method public static {fname}()V + .locals 7 + :call_{fname}_try_start + new-instance v6, L{farg}; + invoke-direct {{v6}}, L{farg};-><init>()V + + const/4 v0, 2 + new-array v1,v0, [Ljava/lang/Object; + const/4 v0, 0 + invoke-virtual {{v6}}, L{farg};->CalledClassName()Ljava/lang/String; + move-result-object v4 + aput-object v4,v1,v0 + + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v3, "%s calls default method on %s\\n" + + invoke-virtual {{v6}}, L{farg};->CalledInterfaceName()Ljava/lang/String; + move-result-object v4 + const/4 v0, 1 + aput-object v4, v1, v0 + + invoke-virtual {{v2,v3,v1}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; + return-void + :call_{fname}_try_end + .catch Ljava/lang/Error; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start + :error_{fname}_start + move-exception v3 + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {{v3,v2}}, Ljava/lang/Error;->printStackTrace(Ljava/io/PrintStream;)V + return-void +.end method +""" + + def __init__(self, farg): + """ + Initialize a test function for the given argument + """ + self.farg = farg + + def get_expected(self): + """ + Get the expected output calling this function. + """ + return "{tree} calls default method on {iface_tree}".format( + tree = self.farg.get_tree(), iface_tree = self.farg.get_called().get_tree()) + + def get_name(self): + """ + Get the name of this function + """ + return "TEST_FUNC_{}".format(self.farg.get_name()) + + def __str__(self): + """ + Print the smali code of this function. + """ + return self.TEST_FUNCTION_TEMPLATE.format(fname=self.get_name(), farg=self.farg.get_name()) + +class TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): + """ + A class that will be instantiated to test default method resolution order. + """ + + TEST_CLASS_TEMPLATE = """{copyright} + +.class public L{class_name}; +.super Ljava/lang/Object; +.implements L{iface_name}; + +# public class {class_name} implements {iface_name} {{ +# public String CalledClassName() {{ +# return "{tree}"; +# }} +# }} + +.method public constructor <init>()V + .registers 1 + invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V + return-void +.end method + +.method public CalledClassName()Ljava/lang/String; + .locals 1 + const-string v0, "{tree}" + return-object v0 +.end method +""" + + def __init__(self, iface): + """ + Initialize this test class which implements the given interface + """ + self.iface = iface + self.class_name = "CLASS_"+gensym() + + def get_name(self): + """ + Get the name of this class + """ + return self.class_name + + def get_tree(self): + """ + Print out a representation of the type tree of this class + """ + return "[{class_name} {iface_tree}]".format(class_name = self.class_name, + iface_tree = self.iface.get_tree()) + + def __iter__(self): + """ + Step through all interfaces implemented transitively by this class + """ + yield self.iface + yield from self.iface + + def get_called(self): + """ + Get the interface whose default method would be called when calling the + CalledInterfaceName function. + """ + all_ifaces = set(iface for iface in self if iface.default) + for i in all_ifaces: + if all(map(lambda j: i not in j.get_super_types(), all_ifaces)): + return i + raise Exception("UNREACHABLE! Unable to find default method!") + + def __str__(self): + """ + Print the smali code of this class. + """ + return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), + iface_name = self.iface.get_name(), + tree = self.get_tree(), + class_name = self.class_name) + +class TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): + """ + An interface that will be used to test default method resolution order. + """ + + TEST_INTERFACE_TEMPLATE = """{copyright} +.class public abstract interface L{class_name}; +.super Ljava/lang/Object; +{implements_spec} + +# public interface {class_name} {extends} {ifaces} {{ +# public String CalledClassName(); +.method public abstract CalledClassName()Ljava/lang/String; +.end method + +{funcs} + +# }} +""" + + DEFAULT_FUNC_TEMPLATE = """ +# public default String CalledInterfaceName() {{ +# return "{tree}"; +# }} +.method public CalledInterfaceName()Ljava/lang/String; + .locals 1 + const-string v0, "{tree}" + return-object v0 +.end method +""" + + IMPLEMENTS_TEMPLATE = """ +.implements L{iface_name}; +""" + + def __init__(self, ifaces, default): + """ + Initialize interface with the given super-interfaces + """ + self.ifaces = sorted(ifaces) + self.default = default + end = "_DEFAULT" if default else "" + self.class_name = "INTERFACE_"+gensym()+end + + def get_super_types(self): + """ + Returns a set of all the supertypes of this interface + """ + return set(i2 for i2 in self) + + def get_name(self): + """ + Get the name of this class + """ + return self.class_name + + def get_tree(self): + """ + Print out a representation of the type tree of this class + """ + return "[{class_name} {iftree}]".format(class_name = self.get_name(), + iftree = print_tree(self.ifaces)) + + def __iter__(self): + """ + Performs depth-first traversal of the interface tree this interface is the + root of. Does not filter out repeats. + """ + for i in self.ifaces: + yield i + yield from i + + def __str__(self): + """ + Print the smali code of this interface. + """ + s_ifaces = " " + j_ifaces = " " + for i in self.ifaces: + s_ifaces += self.IMPLEMENTS_TEMPLATE.format(iface_name = i.get_name()) + j_ifaces += " {},".format(i.get_name()) + j_ifaces = j_ifaces[0:-1] + if self.default: + funcs = self.DEFAULT_FUNC_TEMPLATE.format(ifaces = j_ifaces, + tree = self.get_tree(), + class_name = self.class_name) + else: + funcs = "" + return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'), + implements_spec = s_ifaces, + extends = "extends" if len(self.ifaces) else "", + ifaces = j_ifaces, + funcs = funcs, + tree = self.get_tree(), + class_name = self.class_name) + +def print_tree(ifaces): + """ + Prints a list of iface trees + """ + return " ".join(i.get_tree() for i in ifaces) + +# The deduplicated output of subtree_sizes for each size up to +# MAX_LEAF_IFACE_PER_OBJECT. +SUBTREES = [set(tuple(sorted(l)) for l in subtree_sizes(i)) + for i in range(MAX_IFACE_DEPTH + 1)] + +def create_interface_trees(): + """ + Return all legal interface trees + """ + def dump_supers(s): + """ + Does depth first traversal of all the interfaces in the list. + """ + for i in s: + yield i + yield from i + + def create_interface_trees_inner(num, allow_default): + for split in SUBTREES[num]: + ifaces = [] + for sub in split: + if sub == 1: + ifaces.append([TestInterface([], allow_default)]) + if allow_default: + ifaces[-1].append(TestInterface([], False)) + else: + ifaces.append(list(create_interface_trees_inner(sub, allow_default))) + for supers in itertools.product(*ifaces): + all_supers = sorted(set(dump_supers(supers)) - set(supers)) + for i in range(len(all_supers) + 1): + for combo in itertools.combinations(all_supers, i): + yield TestInterface(list(combo) + list(supers), allow_default) + if allow_default: + for i in range(len(split)): + ifaces = [] + for sub, cs in zip(split, itertools.count()): + if sub == 1: + ifaces.append([TestInterface([], i == cs)]) + else: + ifaces.append(list(create_interface_trees_inner(sub, i == cs))) + for supers in itertools.product(*ifaces): + all_supers = sorted(set(dump_supers(supers)) - set(supers)) + for i in range(len(all_supers) + 1): + for combo in itertools.combinations(all_supers, i): + yield TestInterface(list(combo) + list(supers), False) + + for num in range(1, MAX_IFACE_DEPTH): + yield from create_interface_trees_inner(num, True) + +def create_all_test_files(): + """ + Creates all the objects representing the files in this test. They just need to + be dumped. + """ + mc = MainClass() + classes = {mc} + for tree in create_interface_trees(): + classes.add(tree) + for i in tree: + classes.add(i) + test_class = TestClass(tree) + mc.add_test(test_class) + classes.add(test_class) + return mc, classes + +def main(argv): + smali_dir = Path(argv[1]) + if not smali_dir.exists() or not smali_dir.is_dir(): + print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr) + sys.exit(1) + expected_txt = Path(argv[2]) + mainclass, all_files = create_all_test_files() + with expected_txt.open('w') as out: + print(mainclass.get_expected(), file=out) + for f in all_files: + f.dump(smali_dir) + +if __name__ == '__main__': + main(sys.argv) diff --git a/test/962-iface-static/build b/test/962-iface-static/build new file mode 100755 index 0000000000..5ad82f70d1 --- /dev/null +++ b/test/962-iface-static/build @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright 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. + +# make us exit on a failure +set -e + +if [[ $@ == *"--jvm"* ]]; then + # Build the Java files if we are running a --jvm test + mkdir -p src + mkdir -p classes + ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src + ${JAVAC} -implicit:none -d classes $(find src -name '*.java') +fi + +# Build the smali files and make a dex +${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali') +zip $TEST_NAME.jar classes.dex diff --git a/test/962-iface-static/expected.txt b/test/962-iface-static/expected.txt new file mode 100644 index 0000000000..6d98ea1571 --- /dev/null +++ b/test/962-iface-static/expected.txt @@ -0,0 +1,3 @@ +init +constructor +Hello diff --git a/test/962-iface-static/info.txt b/test/962-iface-static/info.txt new file mode 100644 index 0000000000..d4732e533d --- /dev/null +++ b/test/962-iface-static/info.txt @@ -0,0 +1,4 @@ +Smali-based tests for experimental interface static methods. + +To run with --jvm you must export JAVA_HOME to a Java 8 Language installation +and pass the --use-java-home to run-test diff --git a/test/962-iface-static/run b/test/962-iface-static/run new file mode 100755 index 0000000000..e713708c18 --- /dev/null +++ b/test/962-iface-static/run @@ -0,0 +1,21 @@ +#!/bin/bash +# +# 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. + +if echo $@ | grep -q -- "--jvm"; then + ${RUN} "$@" +else + ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods +fi diff --git a/test/962-iface-static/smali/Displayer.smali b/test/962-iface-static/smali/Displayer.smali new file mode 100644 index 0000000000..06bec16432 --- /dev/null +++ b/test/962-iface-static/smali/Displayer.smali @@ -0,0 +1,45 @@ +# /* +# * 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 Displayer { +# static { +# System.out.println("init"); +# } +# +# public Displayer() { +# System.out.println("constructor"); +# } +# } + +.class public LDisplayer; +.super Ljava/lang/Object; + +.method public static <clinit>()V + .locals 3 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v0, "init" + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + +.method public constructor <init>()V + .locals 2 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v0, "constructor" + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method diff --git a/test/962-iface-static/smali/Main.smali b/test/962-iface-static/smali/Main.smali new file mode 100644 index 0000000000..72fa5e0e6e --- /dev/null +++ b/test/962-iface-static/smali/Main.smali @@ -0,0 +1,40 @@ +# /* +# * 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 { +# public static void main(String[] args) { +# System.out.println(iface.SayHi()); +# } +# } +.class public LMain; +.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 main([Ljava/lang/String;)V + .locals 2 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + + invoke-static {}, Liface;->SayHi()Ljava/lang/String; + move-result-object v0 + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + return-void +.end method diff --git a/test/962-iface-static/smali/iface.smali b/test/962-iface-static/smali/iface.smali new file mode 100644 index 0000000000..441aae669e --- /dev/null +++ b/test/962-iface-static/smali/iface.smali @@ -0,0 +1,43 @@ +# /* +# * 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 interface iface { +# public static final Displayer f = new Displayer(); +# +# public static String SayHi() { +# return "Hello"; +# } +# } + +.class public abstract interface Liface; +.super Ljava/lang/Object; + +.field public final static f:LDisplayer; + +.method public static <clinit>()V + .locals 3 + new-instance v1, LDisplayer; + invoke-direct {v1}, LDisplayer;-><init>()V + sput-object v1, Liface;->f:LDisplayer; + return-void +.end method + +.method public static SayHi()Ljava/lang/String; + .locals 1 + const-string v0, "Hello" + return-object v0 +.end method + diff --git a/test/963-default-range-smali/build b/test/963-default-range-smali/build new file mode 100755 index 0000000000..5ad82f70d1 --- /dev/null +++ b/test/963-default-range-smali/build @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright 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. + +# make us exit on a failure +set -e + +if [[ $@ == *"--jvm"* ]]; then + # Build the Java files if we are running a --jvm test + mkdir -p src + mkdir -p classes + ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src + ${JAVAC} -implicit:none -d classes $(find src -name '*.java') +fi + +# Build the smali files and make a dex +${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali') +zip $TEST_NAME.jar classes.dex diff --git a/test/963-default-range-smali/expected.txt b/test/963-default-range-smali/expected.txt new file mode 100644 index 0000000000..af17d2f873 --- /dev/null +++ b/test/963-default-range-smali/expected.txt @@ -0,0 +1,2 @@ +Hello +Hello diff --git a/test/963-default-range-smali/info.txt b/test/963-default-range-smali/info.txt new file mode 100644 index 0000000000..d4732e533d --- /dev/null +++ b/test/963-default-range-smali/info.txt @@ -0,0 +1,4 @@ +Smali-based tests for experimental interface static methods. + +To run with --jvm you must export JAVA_HOME to a Java 8 Language installation +and pass the --use-java-home to run-test diff --git a/test/963-default-range-smali/run b/test/963-default-range-smali/run new file mode 100755 index 0000000000..e713708c18 --- /dev/null +++ b/test/963-default-range-smali/run @@ -0,0 +1,21 @@ +#!/bin/bash +# +# 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. + +if echo $@ | grep -q -- "--jvm"; then + ${RUN} "$@" +else + ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods +fi diff --git a/test/963-default-range-smali/smali/A.smali b/test/963-default-range-smali/smali/A.smali new file mode 100644 index 0000000000..b3d91dd76b --- /dev/null +++ b/test/963-default-range-smali/smali/A.smali @@ -0,0 +1,29 @@ +# /* +# * Copyright 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 LA; +.super Ljava/lang/Object; +.implements Liface; + +# class A implements iface { +# } + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + diff --git a/test/963-default-range-smali/smali/Main.smali b/test/963-default-range-smali/smali/Main.smali new file mode 100644 index 0000000000..400fba72d9 --- /dev/null +++ b/test/963-default-range-smali/smali/Main.smali @@ -0,0 +1,77 @@ +# /* +# * 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 { +# public static void main(String[] args) { +# A a = new A(); +# System.out.println(a.SayHi("a string 0", +# "a string 1", +# "a string 2", +# "a string 3", +# "a string 4", +# "a string 5", +# "a string 6", +# "a string 7", +# "a string 8", +# "a string 9")); +# iface b = (iface)a; +# System.out.println(b.SayHi("a string 0", +# "a string 1", +# "a string 2", +# "a string 3", +# "a string 4", +# "a string 5", +# "a string 6", +# "a string 7", +# "a string 8", +# "a string 9")); +# } +# } +.class public LMain; +.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 main([Ljava/lang/String;)V + .locals 15 + sget-object v12, Ljava/lang/System;->out:Ljava/io/PrintStream; + + new-instance v1, LA; + invoke-direct {v1}, LA;-><init>()V + const-string v2, "a string 0" + const-string v3, "a string 1" + const-string v4, "a string 2" + const-string v5, "a string 3" + const-string v6, "a string 4" + const-string v7, "a string 5" + const-string v8, "a string 6" + const-string v9, "a string 7" + const-string v10, "a string 8" + const-string v11, "a string 9" + invoke-virtual/range {v1 .. v11}, LA;->SayHi(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + invoke-virtual {v12,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + invoke-interface/range {v1 .. v11}, Liface;->SayHi(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + invoke-virtual {v12,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + return-void +.end method diff --git a/test/963-default-range-smali/smali/iface.smali b/test/963-default-range-smali/smali/iface.smali new file mode 100644 index 0000000000..c2c3ce69a7 --- /dev/null +++ b/test/963-default-range-smali/smali/iface.smali @@ -0,0 +1,40 @@ +# /* +# * 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 interface iface { +# public default String SayHi(String n1, +# String n2, +# String n3, +# String n4, +# String n5, +# String n6, +# String n7, +# String n8, +# String n9, +# String n0) { +# return "Hello"; +# } +# } + +.class public abstract interface Liface; +.super Ljava/lang/Object; + +.method public SayHi(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; + .locals 1 + const-string v0, "Hello" + return-object v0 +.end method + diff --git a/test/964-default-iface-init-generated/build b/test/964-default-iface-init-generated/build new file mode 100755 index 0000000000..deef803813 --- /dev/null +++ b/test/964-default-iface-init-generated/build @@ -0,0 +1,45 @@ +#!/bin/bash +# +# Copyright 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. + +# make us exit on a failure +set -e + +# We will be making more files than the ulimit is set to allow. Remove it temporarily. +OLD_ULIMIT=`ulimit -S` +ulimit -S unlimited + +restore_ulimit() { + ulimit -S "$OLD_ULIMIT" +} +trap 'restore_ulimit' ERR + +# Generate the smali files and expected.txt or fail +./util-src/generate_smali.py ./smali ./expected.txt + +if [[ $@ == *"--jvm"* ]]; then + # Build the Java files if we are running a --jvm test + mkdir -p src + mkdir -p classes + ${ANDROID_BUILD_TOP}/art/tools/extract-embedded-java ./smali ./src + ${JAVAC} -implicit:none -d classes $(find src -name '*.java') +fi + +# Build the smali files and make a dex +${SMALI} -JXmx512m --experimental --api-level 23 --output classes.dex $(find smali -name '*.smali') +zip $TEST_NAME.jar classes.dex + +# Reset the ulimit back to its initial value +restore_ulimit diff --git a/test/964-default-iface-init-generated/expected.txt b/test/964-default-iface-init-generated/expected.txt new file mode 100644 index 0000000000..1ddd65d177 --- /dev/null +++ b/test/964-default-iface-init-generated/expected.txt @@ -0,0 +1 @@ +This file is generated by util-src/generate_smali.py do not directly modify! diff --git a/test/964-default-iface-init-generated/info.txt b/test/964-default-iface-init-generated/info.txt new file mode 100644 index 0000000000..5805a86854 --- /dev/null +++ b/test/964-default-iface-init-generated/info.txt @@ -0,0 +1,17 @@ +Smali-based tests for interface initialization. + +This tests that interface initialization order is correct. + +Obviously needs to run under ART or a Java 8 Language runtime and compiler. + +When run smali test files are generated by the util-src/generate_smali.py +script. If we run with --jvm we will use the +$(ANDROID_BUILD_TOP)/art/tools/extract-embedded-java script to turn the smali +into equivalent Java using the embedded Java code. + +Care should be taken when updating the generate_smali.py script. It should always +return equivalent output when run multiple times and the expected output should +be valid. + +Do not modify the expected.txt file. It is generated on each run by +util-src/generate_smali.py. diff --git a/test/964-default-iface-init-generated/run b/test/964-default-iface-init-generated/run new file mode 100755 index 0000000000..e378b061d9 --- /dev/null +++ b/test/964-default-iface-init-generated/run @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Copyright 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. + +if echo $@ | grep -q -- "--jvm"; then + ${RUN} "$@" +else + ${RUN} "$@" --runtime-option -Xexperimental:default-methods -Xcompiler-option --runtime-arg -Xcompiler-option -Xexperimental:default-methods +fi diff --git a/test/964-default-iface-init-generated/smali/Displayer.smali b/test/964-default-iface-init-generated/smali/Displayer.smali new file mode 100644 index 0000000000..91280a8a42 --- /dev/null +++ b/test/964-default-iface-init-generated/smali/Displayer.smali @@ -0,0 +1,45 @@ +# /* +# * 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. +# */ +# +# // This class is b/c java does not allow static {} blocks in interfaces. +# public class Displayer { +# public Displayer(String type) { +# System.out.println("initialization of " + type); +# } +# public void touch() { +# return; +# } +# } + +.class public LDisplayer; +.super Ljava/lang/Object; + +.method public constructor <init>(Ljava/lang/String;)V + .locals 2 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + const-string v0, "initialization of " + invoke-virtual {v0, p1}, Ljava/lang/String;->concat(Ljava/lang/String;)Ljava/lang/String; + move-result-object v0 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1,v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + return-void +.end method + +.method public touch()V + .locals 0 + return-void +.end method + diff --git a/test/964-default-iface-init-generated/util-src/generate_smali.py b/test/964-default-iface-init-generated/util-src/generate_smali.py new file mode 100755 index 0000000000..be2d3ba563 --- /dev/null +++ b/test/964-default-iface-init-generated/util-src/generate_smali.py @@ -0,0 +1,531 @@ +#!/usr/bin/python3 +# +# 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. + +""" +Generate Smali test files for test 964. +""" + +import os +import sys +from pathlib import Path + +BUILD_TOP = os.getenv("ANDROID_BUILD_TOP") +if BUILD_TOP is None: + print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr) + sys.exit(1) + +# Allow us to import utils and mixins. +sys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python")) + +from testgen.utils import get_copyright, subtree_sizes, gensym, filter_blanks +import testgen.mixins as mixins + +from functools import total_ordering +import itertools +import string + +# The max depth the tree can have. +MAX_IFACE_DEPTH = 3 + +class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin): + """ + A Main.smali file containing the Main class and the main function. It will run + all the test functions we have. + """ + + MAIN_CLASS_TEMPLATE = """{copyright} + +.class public LMain; +.super Ljava/lang/Object; + +# class Main {{ + +.method public constructor <init>()V + .registers 1 + invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V + return-void +.end method + +{test_groups} + +{main_func} + +# }} +""" + + MAIN_FUNCTION_TEMPLATE = """ +# public static void main(String[] args) {{ +.method public static main([Ljava/lang/String;)V + .locals 2 + + {test_group_invoke} + + return-void +.end method +# }} +""" + + TEST_GROUP_INVOKE_TEMPLATE = """ +# {test_name}(); + invoke-static {{}}, {test_name}()V +""" + + def __init__(self): + """ + Initialize this MainClass. We start out with no tests. + """ + self.tests = set() + + def add_test(self, ty): + """ + Add a test for the concrete type 'ty' + """ + self.tests.add(Func(ty)) + + def get_expected(self): + """ + Get the expected output of this test. + """ + all_tests = sorted(self.tests) + return filter_blanks("\n".join(a.get_expected() for a in all_tests)) + + def get_name(self): + """ + Gets the name of this class + """ + return "Main" + + def __str__(self): + """ + Print the smali code for this test. + """ + all_tests = sorted(self.tests) + test_invoke = "" + test_groups = "" + for t in all_tests: + test_groups += str(t) + for t in all_tests: + test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name()) + main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke) + + return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), + test_groups = test_groups, + main_func = main_func) + +class Func(mixins.Named, mixins.NameComparableMixin): + """ + A function that tests the functionality of a concrete type. Should only be + constructed by MainClass.add_test. + """ + + TEST_FUNCTION_TEMPLATE = """ +# public static void {fname}() {{ +# try {{ +# System.out.println("About to initialize {tree}"); +# {farg} v = new {farg}(); +# System.out.println("Initialized {tree}"); +# v.touchAll(); +# System.out.println("All of {tree} hierarchy initialized"); +# return; +# }} catch (Error e) {{ +# e.printStackTrace(System.out); +# return; +# }} +# }} +.method public static {fname}()V + .locals 7 + :call_{fname}_try_start + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + const-string v3, "About to initialize {tree}" + invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + new-instance v6, L{farg}; + invoke-direct {{v6}}, L{farg};-><init>()V + + const-string v3, "Initialized {tree}" + invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + invoke-virtual {{v6}}, L{farg};->touchAll()V + + const-string v3, "All of {tree} hierarchy initialized" + invoke-virtual {{v2, v3}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + + return-void + :call_{fname}_try_end + .catch Ljava/lang/Error; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start + :error_{fname}_start + move-exception v3 + sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {{v3,v2}}, Ljava/lang/Error;->printStackTrace(Ljava/io/PrintStream;)V + return-void +.end method +""" + + OUTPUT_FORMAT = """ +About to initialize {tree} +{initialize_output} +Initialized {tree} +{touch_output} +All of {tree} hierarchy initialized +""".strip() + + def __init__(self, farg): + """ + Initialize a test function for the given argument + """ + self.farg = farg + + def __str__(self): + """ + Print the smali code for this test function. + """ + return self.TEST_FUNCTION_TEMPLATE.format(fname=self.get_name(), + farg=self.farg.get_name(), + tree = self.farg.get_tree()) + + def get_name(self): + """ + Gets the name of this test function + """ + return "TEST_FUNC_{}".format(self.farg.get_name()) + + def get_expected(self): + """ + Get the expected output of this function. + """ + return self.OUTPUT_FORMAT.format( + tree = self.farg.get_tree(), + initialize_output = self.farg.get_initialize_output().strip(), + touch_output = self.farg.get_touch_output().strip()) + +class TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): + """ + A class that will be instantiated to test interface initialization order. + """ + + TEST_CLASS_TEMPLATE = """{copyright} + +.class public L{class_name}; +.super Ljava/lang/Object; +{implements_spec} + +# public class {class_name} implements {ifaces} {{ +# +# public {class_name}() {{ +# }} +.method public constructor <init>()V + .locals 2 + invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V + return-void +.end method + +# public void marker() {{ +# return; +# }} +.method public marker()V + .locals 0 + return-void +.end method + +# public void touchAll() {{ +.method public touchAll()V + .locals 2 + sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream; + {touch_calls} + return-void +.end method +# }} +# }} +""" + + IMPLEMENTS_TEMPLATE = """ +.implements L{iface_name}; +""" + + TOUCH_CALL_TEMPLATE = """ +# System.out.println("{class_name} touching {iface_name}"); +# {iface_name}.field.touch(); + const-string v1, "{class_name} touching {iface_name}" + invoke-virtual {{v0, v1}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + sget-object v1, L{iface_name};->field:LDisplayer; + invoke-virtual {{v1}}, LDisplayer;->touch()V +""" + + TOUCH_OUTPUT_TEMPLATE = """ +{class_name} touching {iface_name} +{touch_output} +""".strip() + + def __init__(self, ifaces): + """ + Initialize this test class which implements the given interfaces + """ + self.ifaces = ifaces + self.class_name = "CLASS_"+gensym() + + def get_name(self): + """ + Gets the name of this interface + """ + return self.class_name + + def get_tree(self): + """ + Print out a representation of the type tree of this class + """ + return "[{fname} {iftree}]".format(fname = self.get_name(), iftree = print_tree(self.ifaces)) + + def get_initialize_output(self): + return "\n".join(map(lambda i: i.get_initialize_output().strip(), dump_tree(self.ifaces))) + + def get_touch_output(self): + return "\n".join(map(lambda a: self.TOUCH_OUTPUT_TEMPLATE.format( + class_name = self.class_name, + iface_name = a.get_name(), + touch_output = a.get_touch_output()).strip(), + self.get_all_interfaces())) + + def get_all_interfaces(self): + """ + Returns a set of all interfaces this class transitively implements + """ + return sorted(set(dump_tree(self.ifaces))) + + def __str__(self): + """ + Print the smali code for this class. + """ + s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()), + self.ifaces)) + j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces)) + touches = '\n'.join(map(lambda a: self.TOUCH_CALL_TEMPLATE.format(class_name = self.class_name, + iface_name = a.get_name()), + self.get_all_interfaces())) + return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), + implements_spec = s_ifaces, + ifaces = j_ifaces, + class_name = self.class_name, + touch_calls = touches) + +class TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): + """ + An interface that will be used to test default method resolution order. + """ + + TEST_INTERFACE_TEMPLATE = """{copyright} +.class public abstract interface L{class_name}; +.super Ljava/lang/Object; +{implements_spec} + +# public interface {class_name} {extends} {ifaces} {{ +# public static final Displayer field = new Displayer("{tree}"); +.field public final static field:LDisplayer; + +.method public static constructor <clinit>()V + .locals 3 + const-string v2, "{tree}" + new-instance v1, LDisplayer; + invoke-direct {{v1, v2}}, LDisplayer;-><init>(Ljava/lang/String;)V + sput-object v1, L{class_name};->field:LDisplayer; + return-void +.end method + +# public void marker(); +.method public abstract marker()V +.end method + +{funcs} + +# }} +""" + + DEFAULT_FUNC_TEMPLATE = """ +# public default void {class_name}_DEFAULT_FUNC() {{ +# return; +# }} +.method public {class_name}_DEFAULT_FUNC()V + .locals 0 + return-void +.end method +""" + IMPLEMENTS_TEMPLATE = """ +.implements L{iface_name}; +""" + + OUTPUT_TEMPLATE = "initialization of {tree}" + + def __init__(self, ifaces, default): + """ + Initialize interface with the given super-interfaces + """ + self.ifaces = ifaces + self.default = default + end = "_DEFAULT" if default else "" + self.class_name = "INTERFACE_"+gensym()+end + self.cloned = False + self.initialized = False + + def clone(self): + """ + Clones this interface, returning a new one with the same structure but + different name. + """ + return TestInterface(tuple(map(lambda a: a.clone(), self.ifaces)), self.default) + + def get_name(self): + """ + Gets the name of this interface + """ + return self.class_name + + def __iter__(self): + """ + Performs depth-first traversal of the interface tree this interface is the + root of. Does not filter out repeats. + """ + for i in self.ifaces: + yield i + yield from i + + def get_tree(self): + """ + Print out a representation of the type tree of this class + """ + return "[{class_name} {iftree}]".format(class_name = self.get_name(), + iftree = print_tree(self.ifaces)) + + def get_initialize_output(self): + """ + Returns the expected output upon the class that implements this interface being initialized. + """ + if self.default and not self.initialized: + self.initialized = True + return self.OUTPUT_TEMPLATE.format(tree = self.get_tree()) + else: + return "" + + def get_touch_output(self): + """ + Returns the expected output upon this interface being touched. + """ + if not self.default and not self.initialized: + self.initialized = True + return self.OUTPUT_TEMPLATE.format(tree = self.get_tree()) + else: + return "" + + def __str__(self): + """ + Print the smali code for this interface. + """ + s_ifaces = '\n'.join(map(lambda a: self.IMPLEMENTS_TEMPLATE.format(iface_name = a.get_name()), + self.ifaces)) + j_ifaces = ', '.join(map(lambda a: a.get_name(), self.ifaces)) + if self.default: + funcs = self.DEFAULT_FUNC_TEMPLATE.format(class_name = self.class_name) + else: + funcs = "" + return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'), + implements_spec = s_ifaces, + extends = "extends" if len(self.ifaces) else "", + ifaces = j_ifaces, + funcs = funcs, + tree = self.get_tree(), + class_name = self.class_name) + +def dump_tree(ifaces): + """ + Yields all the interfaces transitively implemented by the set in + reverse-depth-first order + """ + for i in ifaces: + yield from dump_tree(i.ifaces) + yield i + +def print_tree(ifaces): + """ + Prints the tree for the given ifaces. + """ + return " ".join(i.get_tree() for i in ifaces) + +def clone_all(l): + return tuple(a.clone() for a in l) + +# Cached output of subtree_sizes for speed of access. +SUBTREES = [set(tuple(l) for l in subtree_sizes(i)) + for i in range(MAX_IFACE_DEPTH + 1)] + +def create_test_classes(): + """ + Yield all the test classes with the different interface trees + """ + for num in range(1, MAX_IFACE_DEPTH + 1): + for split in SUBTREES[num]: + ifaces = [] + for sub in split: + ifaces.append(list(create_interface_trees(sub))) + for supers in itertools.product(*ifaces): + yield TestClass(clone_all(supers)) + for i in range(len(set(dump_tree(supers)) - set(supers))): + ns = clone_all(supers) + selected = sorted(set(dump_tree(ns)) - set(ns))[i] + yield TestClass(tuple([selected] + list(ns))) + +def create_interface_trees(num): + """ + Yield all the interface trees up to 'num' depth. + """ + if num == 0: + yield TestInterface(tuple(), False) + yield TestInterface(tuple(), True) + return + for split in SUBTREES[num]: + ifaces = [] + for sub in split: + ifaces.append(list(create_interface_trees(sub))) + for supers in itertools.product(*ifaces): + yield TestInterface(clone_all(supers), False) + yield TestInterface(clone_all(supers), True) + # TODO Should add on some from higher up the tree. + +def create_all_test_files(): + """ + Creates all the objects representing the files in this test. They just need to + be dumped. + """ + mc = MainClass() + classes = {mc} + for clazz in create_test_classes(): + classes.add(clazz) + for i in dump_tree(clazz.ifaces): + classes.add(i) + mc.add_test(clazz) + return mc, classes + +def main(argv): + smali_dir = Path(argv[1]) + if not smali_dir.exists() or not smali_dir.is_dir(): + print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr) + sys.exit(1) + expected_txt = Path(argv[2]) + mainclass, all_files = create_all_test_files() + with expected_txt.open('w') as out: + print(mainclass.get_expected(), file=out) + for f in all_files: + f.dump(smali_dir) + +if __name__ == '__main__': + main(sys.argv) diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index db16b97ea6..e114a2e9f3 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -214,13 +214,29 @@ TEST_ART_TIMING_SENSITIVE_RUN_TESTS := \ 055-enum-performance \ 133-static-invoke-super - # disable timing sensitive tests on "dist" builds. +# disable timing sensitive tests on "dist" builds. ifdef dist_goal 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), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES)) endif +# Tests that require python3. +TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS := \ + 960-default-smali \ + 961-default-iface-resolution-generated \ + 964-default-iface-init-generated \ + +# Check if we have python3 to run our tests. +ifeq ($(wildcard /usr/bin/python3),) + $(warning "No python3 found. Disabling tests: $(TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS)") + + # Currently disable tests requiring python3 when it is not installed. + 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), $(TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS), $(ALL_ADDRESS_SIZES)) +endif + TEST_ART_TIMING_SENSITIVE_RUN_TESTS := # Note 116-nodex2oat is not broken per-se it just doesn't (and isn't meant to) work with --prebuild. @@ -313,13 +329,15 @@ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUIL $(PICTEST_TYPES),$(DEBUGGABLE_TYPES),130-hprof,$(ALL_ADDRESS_SIZES)) # 131 is an old test. The functionality has been implemented at an earlier stage and is checked -# in tests 138. -ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ +# in tests 138. Blacklisted for debug builds since these builds have duplicate classes checks which +# punt to interpreter. +ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),debug,$(PREBUILD_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), \ +# 138-duplicate-classes-check. Turned on for debug builds since debug builds have duplicate classes +# checks enabled, b/2133391. +ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),ndebug,$(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)) @@ -469,6 +487,8 @@ TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS := \ 530-checker-regression-reftype-final \ 532-checker-nonnull-arrayset \ 534-checker-bce-deoptimization \ + 536-checker-intrinsic-optimization \ + 537-checker-debuggable \ ifeq (mips,$(TARGET_ARCH)) ifneq (,$(filter optimizing,$(COMPILER_TYPES))) @@ -519,8 +539,10 @@ TEST_ART_BROKEN_OPTIMIZING_DEBUGGABLE_RUN_TESTS := # Tests that should fail in the read barrier configuration. # 137: Read barrier forces interpreter. Cannot run this with the interpreter. +# 141: Class unloading test is flaky with CC since CC seems to occasionally keep class loaders live. TEST_ART_BROKEN_READ_BARRIER_RUN_TESTS := \ - 137-cfi + 137-cfi \ + 141-class-unload ifeq ($(ART_USE_READ_BARRIER),true) ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ diff --git a/test/etc/default-build b/test/etc/default-build index c281bca3f5..c92402b529 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -26,6 +26,8 @@ while true; do option="$1" DX_FLAGS="${DX_FLAGS} $option" shift + elif [ "x$1" = "x--jvm" ]; then + shift elif expr "x$1" : "x--" >/dev/null 2>&1; then echo "unknown $0 option: $1" 1>&2 exit 1 diff --git a/test/run-all-tests b/test/run-all-tests index 13490c46e4..76283b7a8d 100755 --- a/test/run-all-tests +++ b/test/run-all-tests @@ -41,6 +41,9 @@ while true; do if [ "x$1" = "x--host" ]; then run_args="${run_args} --host" shift + elif [ "x$1" = "x--use-java-home" ]; then + run_args="${run_args} --use-java-home" + shift elif [ "x$1" = "x--jvm" ]; then run_args="${run_args} --jvm" shift @@ -133,7 +136,7 @@ if [ "$usage" = "yes" ]; then echo " --debug --dev --host --interpreter --jit --jvm --no-optimize" echo " --no-verify -O --update --valgrind --zygote --64 --relocate" echo " --prebuild --always-clean --gcstress --gcverify --trace" - echo " --no-patchoat --no-dex2oat" + echo " --no-patchoat --no-dex2oat --use-java-home" echo " Specific Runtime Options:" echo " --seq Run tests one-by-one, avoiding failures caused by busy CPU" ) 1>&2 diff --git a/test/run-test b/test/run-test index a5b6e92869..1b71f33209 100755 --- a/test/run-test +++ b/test/run-test @@ -40,7 +40,6 @@ else tmp_dir="${TMPDIR}/$USER/${test_dir}" fi checker="${progdir}/../tools/checker/checker.py" - export JAVA="java" export JAVAC="javac -g" export RUN="${progdir}/etc/run-test-jar" @@ -155,6 +154,15 @@ while true; do DEX_LOCATION=$tmp_dir run_args="${run_args} --host" shift + elif [ "x$1" = "x--use-java-home" ]; then + if [ -n "${JAVA_HOME}" ]; then + export JAVA="${JAVA_HOME}/bin/java" + export JAVAC="${JAVA_HOME}/bin/javac -g" + else + echo "Passed --use-java-home without JAVA_HOME variable set!" + usage="yes" + fi + shift elif [ "x$1" = "x--jvm" ]; then target_mode="no" runtime="jvm" @@ -162,6 +170,7 @@ while true; do NEED_DEX="false" USE_JACK="false" run_args="${run_args} --jvm" + build_args="${build_args} --jvm" shift elif [ "x$1" = "x-O" ]; then lib="libart.so" @@ -560,6 +569,9 @@ if [ "$usage" = "yes" ]; then echo " --invoke-with Pass --invoke-with option to runtime." echo " --dalvik Use Dalvik (off by default)." echo " --jvm Use a host-local RI virtual machine." + echo " --use-java-home Use the JAVA_HOME environment variable" + echo " to find the java compiler and runtime" + echo " (if applicable) to run the test with." echo " --output-path [path] Location where to store the build" \ "files." echo " --64 Run the test in 64-bit mode" @@ -637,18 +649,24 @@ if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]]; then # on a particular DEX output, keep building them with dx for now (b/19467889). USE_JACK="false" - if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$debuggable" = "no" ]; then + if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" ]; then # In no-prebuild mode, the compiler is only invoked if both dex2oat and # patchoat are available. Disable Checker otherwise (b/22552692). if [ "$prebuild_mode" = "yes" ] || [ "$have_patchoat" = "yes" -a "$have_dex2oat" = "yes" ]; then run_checker="yes" + if [ "$target_mode" = "no" ]; then cfg_output_dir="$tmp_dir" - checker_arch_option="--arch=${host_arch_name^^}" + checker_args="--arch=${host_arch_name^^}" else cfg_output_dir="$DEX_LOCATION" - checker_arch_option="--arch=${target_arch_name^^}" + checker_args="--arch=${target_arch_name^^}" + fi + + if [ "$debuggable" = "yes" ]; then + checker_args="$checker_args --debuggable" fi + run_args="${run_args} -Xcompiler-option --dump-cfg=$cfg_output_dir/$cfg_output \ -Xcompiler-option -j1" fi @@ -702,7 +720,7 @@ if [ "$dev_mode" = "yes" ]; then if [ "$target_mode" = "yes" ]; then adb pull $cfg_output_dir/$cfg_output &> /dev/null fi - "$checker" $checker_arch_option "$cfg_output" "$tmp_dir" 2>&1 + "$checker" $checker_args "$cfg_output" "$tmp_dir" 2>&1 checker_exit="$?" if [ "$checker_exit" = "0" ]; then good="yes" @@ -727,7 +745,7 @@ elif [ "$update_mode" = "yes" ]; then if [ "$target_mode" = "yes" ]; then adb pull $cfg_output_dir/$cfg_output &> /dev/null fi - "$checker" -q $checker_arch_option "$cfg_output" "$tmp_dir" >> "$output" 2>&1 + "$checker" -q $checker_args "$cfg_output" "$tmp_dir" >> "$output" 2>&1 fi sed -e 's/[[:cntrl:]]$//g' < "$output" >"${td_expected}" good="yes" @@ -768,7 +786,7 @@ else if [ "$target_mode" = "yes" ]; then adb pull $cfg_output_dir/$cfg_output &> /dev/null fi - "$checker" -q $checker_arch_option "$cfg_output" "$tmp_dir" >> "$output" 2>&1 + "$checker" -q $checker_args "$cfg_output" "$tmp_dir" >> "$output" 2>&1 checker_exit="$?" if [ "$checker_exit" != "0" ]; then echo "checker exit status: $checker_exit" 1>&2 diff --git a/test/utils/python/testgen/mixins.py b/test/utils/python/testgen/mixins.py new file mode 100644 index 0000000000..085e51def2 --- /dev/null +++ b/test/utils/python/testgen/mixins.py @@ -0,0 +1,135 @@ +#!/usr/bin/python3 +# +# 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. + +""" +Common mixins and abstract base classes (ABCs) useful for writing test generators in python +""" + +import abc +import collections.abc +import functools + +class Named(metaclass=abc.ABCMeta): + """ + An abc that defines a get_name method. + """ + + @abc.abstractmethod + def get_name(self): + """ + Returns a unique name to use as the identity for implementing comparisons. + """ + pass + +class FileLike(metaclass=abc.ABCMeta): + """ + An abc that defines get_file_name and get_file_extension methods. + """ + + @abc.abstractmethod + def get_file_name(self): + """Returns the filename this object represents""" + pass + + @abc.abstractmethod + def get_file_extension(self): + """Returns the file extension of the file this object represents""" + pass + +@functools.lru_cache(maxsize=None) +def get_file_extension_mixin(ext): + """ + Gets a mixin that defines get_file_name(self) in terms of get_name(self) with the + given file extension. + """ + + class FExt(object): + """ + A mixin defining get_file_name(self) in terms of get_name(self) + """ + + def get_file_name(self): + return self.get_name() + ext + + def get_file_extension(self): + return ext + + # Register the ABCs + Named.register(FExt) + FileLike.register(FExt) + + return FExt + +class SmaliFileMixin(get_file_extension_mixin(".smali")): + """ + A mixin that defines that the file this class belongs to is get_name() + ".smali". + """ + pass + +class NameComparableMixin(object): + """ + A mixin that defines the object comparison and related functionality in terms + of a get_name(self) function. + """ + + def __lt__(self, other): + return self.get_name() < other.get_name() + + def __gt__(self, other): + return self.get_name() > other.get_name() + + def __eq__(self, other): + return self.get_name() == other.get_name() + + def __le__(self, other): + return self.get_name() <= other.get_name() + + def __ge__(self, other): + return self.get_name() >= other.get_name() + + def __ne__(self, other): + return self.get_name() != other.get_name() + + def __hash__(self): + return hash(self.get_name()) + +Named.register(NameComparableMixin) +collections.abc.Hashable.register(NameComparableMixin) + +class DumpMixin(metaclass=abc.ABCMeta): + """ + A mixin to add support for dumping the string representation of an object to a + file. Requires the get_file_name(self) method be defined. + """ + + @abc.abstractmethod + def __str__(self): + """ + Returns the data to be printed to a file by dump. + """ + pass + + def dump(self, directory): + """ + Dump this object to a file in the given directory + """ + out_file = directory / self.get_file_name() + if out_file.exists(): + out_file.unlink() + with out_file.open('w') as out: + print(str(self), file=out) + +FileLike.register(DumpMixin) diff --git a/test/utils/python/testgen/utils.py b/test/utils/python/testgen/utils.py new file mode 100644 index 0000000000..769ad16ebe --- /dev/null +++ b/test/utils/python/testgen/utils.py @@ -0,0 +1,80 @@ +#!/usr/bin/python3 +# +# 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. + +""" +Common functions useful for writing test generators in python +""" + +import itertools +import os +import string +from pathlib import Path + +BUILD_TOP = os.getenv("ANDROID_BUILD_TOP") +if BUILD_TOP is None: + print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr) + sys.exit(1) + +# An iterator which yields strings made from lowercase letters. First yields +# all 1 length strings, then all 2 and so on. It does this alphabetically. +NAME_GEN = itertools.chain.from_iterable( + map(lambda n: itertools.product(string.ascii_lowercase, repeat=n), + itertools.count(1))) + +def gensym(): + """ + Returns a new, globally unique, identifier name that is a valid Java symbol + on each call. + """ + return ''.join(next(NAME_GEN)) + +def filter_blanks(s): + """ + Takes a string returns the same string sans empty lines + """ + return "\n".join(a for a in s.split("\n") if a.strip() != "") + +def get_copyright(filetype = "java"): + """ + Returns the standard copyright header for the given filetype + """ + if filetype == "smali": + return "\n".join(map(lambda a: "# " + a, get_copyright("java").split("\n"))) + else: + fname = filetype + ".txt" + with (Path(BUILD_TOP)/"development"/"docs"/"copyright-templates"/fname).open() as template: + return "".join(template.readlines()) + +def subtree_sizes(n): + """ + A generator that yields a tuple containing a possible arrangement of subtree + nodes for a tree with a total of 'n' leaf nodes. + """ + if n == 0: + return + elif n == 1: + yield (0,) + elif n == 2: + yield (1, 1) + else: + for prevt in subtree_sizes(n - 1): + prev = list(prevt) + yield tuple([1] + prev) + for i in range(len(prev)): + prev[i] += 1 + yield tuple(prev) + prev[i] -= 1 + |