OSDN Git Service

ART: Add miranda checking
authorAndreas Gampe <agampe@google.com>
Sat, 1 Nov 2014 01:12:30 +0000 (18:12 -0700)
committerAndreas Gampe <agampe@google.com>
Mon, 3 Nov 2014 22:44:14 +0000 (14:44 -0800)
Add a test for resolution of miranda methods across dex-files. See
CL 112688 and b/18193682 for the code change.

Fix the test script to support no-verify again.

Weaken the dex cache check to a check whether the found method is a
miranda method. This will penalize miranda methods, as they will
always have to be resolved by name, but does not require the multi-step
load of the method's dex cache.

Bug: 18193682

(cherry picked from commit 2b0fa5ba4a8f07ee243452003bf93418d30e9448)

Change-Id: I1dae2a9ec0985dc8625acd7dd5686a5d3cdc8888

18 files changed:
runtime/mirror/class.cc
test/040-miranda/src/Main.java
test/040-miranda/src/MirandaAbstract.java
test/040-miranda/src/MirandaClass.java
test/040-miranda/src/MirandaClass2.java
test/126-miranda-multidex/build [new file with mode: 0644]
test/126-miranda-multidex/expected.txt [new file with mode: 0644]
test/126-miranda-multidex/info.txt [new file with mode: 0644]
test/126-miranda-multidex/run [new file with mode: 0755]
test/126-miranda-multidex/src/Main.java [new file with mode: 0644]
test/126-miranda-multidex/src/MirandaAbstract.java [new file with mode: 0644]
test/126-miranda-multidex/src/MirandaClass.java [new file with mode: 0644]
test/126-miranda-multidex/src/MirandaClass2.java [new file with mode: 0644]
test/126-miranda-multidex/src/MirandaInterface.java [new file with mode: 0644]
test/126-miranda-multidex/src/MirandaInterface2.java [new file with mode: 0644]
test/etc/host-run-test-jar
test/etc/push-and-run-prebuilt-test-jar
test/etc/push-and-run-test-jar

index df43e98..4ef6ea0 100644 (file)
@@ -500,8 +500,9 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t
     for (size_t i = 0; i < NumVirtualMethods(); ++i) {
       ArtMethod* method = GetVirtualMethod(i);
       if (method->GetDexMethodIndex() == dex_method_idx &&
-          // A miranda method may have a different DexCache.
-          method->GetDexCache() == dex_cache) {
+          // A miranda method may have a different DexCache and is always created by linking,
+          // never *declared* in the class.
+          !method->IsMiranda()) {
         return method;
       }
     }
index ff5eba0..65f4fb4 100644 (file)
@@ -42,8 +42,8 @@ public class Main {
 
         System.out.println("Test getting miranda method via reflection:");
         try {
-          Class mirandaClass = Class.forName("MirandaAbstract");
-          Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface", (Class[]) null);
+          Class<?> mirandaClass = Class.forName("MirandaAbstract");
+          Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface");
           System.out.println("  did not expect to find miranda method");
         } catch (NoSuchMethodException nsme) {
           System.out.println("  caught expected NoSuchMethodException");
index 309ecca..c8cfa34 100644 (file)
@@ -21,6 +21,8 @@ public abstract class MirandaAbstract implements MirandaInterface, MirandaInterf
 {
     protected MirandaAbstract() { }
 
+    // These will be miranda methods, as the interfaces define them, but they are not
+    // implemented in this abstract class:
     //public abstract boolean inInterface();
     //public abstract int inInterface2();
 
index 0d942f0..4160992 100644 (file)
@@ -22,17 +22,14 @@ public class MirandaClass extends MirandaAbstract {
     public MirandaClass() {}
 
     public boolean inInterface() {
-        //System.out.println("    MirandaClass inInterface");
         return true;
     }
 
     public int inInterface2() {
-        //System.out.println("    MirandaClass inInterface2");
         return 27;
     }
 
     public boolean inAbstract() {
-        //System.out.println("    MirandaClass inAbstract");
         return false;
     }
 }
index e9bdf2b..143eb37 100644 (file)
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2006 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 MirandaClass2 extends MirandaAbstract {
     public boolean inInterface() {
         return true;
diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build
new file mode 100644 (file)
index 0000000..4c30f3f
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+
+# All except Main
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/MirandaInterface.class
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+# Only Main
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/Main.class classes/MirandaAbstract.class classes/MirandaClass*.class classes/MirandaInterface2*.class
+${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+
+zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/126-miranda-multidex/expected.txt b/test/126-miranda-multidex/expected.txt
new file mode 100644 (file)
index 0000000..dbe3717
--- /dev/null
@@ -0,0 +1,32 @@
+MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+MirandaAbstract / MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+true 27
+MirandaAbstract / MirandaClass2:
+  inInterface:  true
+  inInterface2: 28
+  inAbstract:   true
+true 28
+Test getting miranda method via reflection:
+  caught expected NoSuchMethodException
+MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+MirandaAbstract / MirandaClass:
+  inInterface:  true
+  inInterface2: 27
+  inAbstract:   false
+true 27
+MirandaAbstract / MirandaClass2:
+  inInterface:  true
+  inInterface2: 28
+  inAbstract:   true
+true 28
+Test getting miranda method via reflection:
+  caught expected NoSuchMethodException
diff --git a/test/126-miranda-multidex/info.txt b/test/126-miranda-multidex/info.txt
new file mode 100644 (file)
index 0000000..ac50e2e
--- /dev/null
@@ -0,0 +1,2 @@
+This test ensures that cross-dex-file Miranda methods are correctly resolved.
+See b/18193682 for details.
diff --git a/test/126-miranda-multidex/run b/test/126-miranda-multidex/run
new file mode 100755 (executable)
index 0000000..23c9935
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 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.
+
+${RUN} $@
+
+# The problem was first exposed in a no-verify setting, as that changes the resolution path
+# taken. Make sure we also test in that environment.
+${RUN} --no-verify ${@}
diff --git a/test/126-miranda-multidex/src/Main.java b/test/126-miranda-multidex/src/Main.java
new file mode 100644 (file)
index 0000000..8624378
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+
+/**
+ * Miranda testing.
+ */
+public class Main {
+    public static void main(String[] args) {
+        MirandaClass mir = new MirandaClass();
+        System.out.println("MirandaClass:");
+        System.out.println("  inInterface:  " + mir.inInterface());
+        System.out.println("  inInterface2: " + mir.inInterface2());
+        System.out.println("  inAbstract:   " + mir.inAbstract());
+
+        /* try again through abstract class; results should be identical */
+        MirandaAbstract mira = mir;
+        System.out.println("MirandaAbstract / MirandaClass:");
+        System.out.println("  inInterface:  " + mira.inInterface());
+        System.out.println("  inInterface2: " + mira.inInterface2());
+        System.out.println("  inAbstract:   " + mira.inAbstract());
+        mira.callMiranda();
+
+        MirandaAbstract mira2 = new MirandaClass2();
+        System.out.println("MirandaAbstract / MirandaClass2:");
+        System.out.println("  inInterface:  " + mira2.inInterface());
+        System.out.println("  inInterface2: " + mira2.inInterface2());
+        System.out.println("  inAbstract:   " + mira2.inAbstract());
+        mira2.callMiranda();
+
+        System.out.println("Test getting miranda method via reflection:");
+        try {
+          Class<?> mirandaClass = Class.forName("MirandaAbstract");
+          Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface");
+          System.out.println("  did not expect to find miranda method");
+        } catch (NoSuchMethodException nsme) {
+          System.out.println("  caught expected NoSuchMethodException");
+        } catch (Exception e) {
+          System.out.println("  caught unexpected exception " + e);
+        }
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaAbstract.java b/test/126-miranda-multidex/src/MirandaAbstract.java
new file mode 100644 (file)
index 0000000..c09a61f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public abstract class MirandaAbstract implements MirandaInterface, MirandaInterface2
+{
+    protected MirandaAbstract() { }
+
+    // These will be miranda methods, as the interfaces define them, but they are not
+    // implemented in this abstract class:
+    //public abstract boolean inInterface();
+    //public abstract int inInterface2();
+
+    public boolean inAbstract() {
+        return true;
+    }
+
+    public void callMiranda() {
+        System.out.println(inInterface() + " " + inInterface2());
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaClass.java b/test/126-miranda-multidex/src/MirandaClass.java
new file mode 100644 (file)
index 0000000..7bb37e7
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public class MirandaClass extends MirandaAbstract {
+
+    public MirandaClass() {}
+
+    public boolean inInterface() {
+        return true;
+    }
+
+    public int inInterface2() {
+        return 27;
+    }
+
+    public boolean inAbstract() {
+        return false;
+    }
+
+    // Better not hit any of these...
+    public void inInterfaceDummy1() {
+        System.out.println("inInterfaceDummy1");
+    }
+    public void inInterfaceDummy2() {
+        System.out.println("inInterfaceDummy2");
+    }
+    public void inInterfaceDummy3() {
+        System.out.println("inInterfaceDummy3");
+    }
+    public void inInterfaceDummy4() {
+        System.out.println("inInterfaceDummy4");
+    }
+    public void inInterfaceDummy5() {
+        System.out.println("inInterfaceDummy5");
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaClass2.java b/test/126-miranda-multidex/src/MirandaClass2.java
new file mode 100644 (file)
index 0000000..797ead2
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 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 MirandaClass2 extends MirandaAbstract {
+    public boolean inInterface() {
+        return true;
+    }
+
+    public int inInterface2() {
+        return 28;
+    }
+
+    // Better not hit any of these...
+    public void inInterfaceDummy1() {
+        System.out.println("inInterfaceDummy1");
+    }
+    public void inInterfaceDummy2() {
+        System.out.println("inInterfaceDummy2");
+    }
+    public void inInterfaceDummy3() {
+        System.out.println("inInterfaceDummy3");
+    }
+    public void inInterfaceDummy4() {
+        System.out.println("inInterfaceDummy4");
+    }
+    public void inInterfaceDummy5() {
+        System.out.println("inInterfaceDummy5");
+    }
+}
diff --git a/test/126-miranda-multidex/src/MirandaInterface.java b/test/126-miranda-multidex/src/MirandaInterface.java
new file mode 100644 (file)
index 0000000..df12fcc
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public interface MirandaInterface {
+
+    public boolean inInterface();
+
+    // A couple of dummy methods to fill the method table.
+    public void inInterfaceDummy1();
+    public void inInterfaceDummy2();
+    public void inInterfaceDummy3();
+    public void inInterfaceDummy4();
+    public void inInterfaceDummy5();
+
+}
diff --git a/test/126-miranda-multidex/src/MirandaInterface2.java b/test/126-miranda-multidex/src/MirandaInterface2.java
new file mode 100644 (file)
index 0000000..7c93fd0
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+/**
+ * Miranda testing.
+ */
+public interface MirandaInterface2 {
+
+    public boolean inInterface();
+
+    public int inInterface2();
+
+}
index 41af077..37c579d 100755 (executable)
@@ -26,6 +26,7 @@ BUILD_BOOT_OPT=""
 SECONDARY_DEX=""
 exe="${ANDROID_HOST_OUT}/bin/dalvikvm32"
 main="Main"
+DEX_VERIFY=""
 
 while true; do
     if [ "x$1" = "x--quiet" ]; then
@@ -158,7 +159,12 @@ fi
 
 if [ "$INTERPRETER" = "y" ]; then
     INT_OPTS="-Xint"
-    COMPILER_FLAGS="${COMPILER_FLAGS} --compiler-filter=interpret-only"
+    if [ "$VERIFY" = "y" ] ; then
+      COMPILER_FLAGS="${COMPILER_FLAGS} --compiler-filter=interpret-only"
+    else
+      COMPILER_FLAGS="${COMPILER_FLAGS} --compiler-filter=verify-none"
+      DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
+    fi
 fi
 
 if [ "$RELOCATE" = "y" ]; then
@@ -184,7 +190,7 @@ else
 fi
 
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
-cmdline="$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $JNI_OPTS $FLAGS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX $main"
+cmdline="$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $DEX_VERIFY $JNI_OPTS $FLAGS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX $main"
 if [ "$DEV_MODE" = "y" ]; then
   if [ "$PREBUILD" = "y" ]; then
     echo "$mkdir_cmd && $prebuild_cmd && $cmdline"
index 42b6972..7353544 100755 (executable)
@@ -27,6 +27,7 @@ TARGET_SUFFIX="32"
 GDB_TARGET_SUFFIX=""
 COMPILE_FLAGS=""
 SECONDARY_DEX=""
+DEX_VERIFY=""
 
 while true; do
     if [ "x$1" = "x--quiet" ]; then
@@ -130,7 +131,6 @@ if [ "$ZYGOTE" = "" ]; then
     fi
 
     if [ "$VERIFY" = "y" ]; then
-        DEX_VERIFY=""
         msg "Performing verification"
     else
         DEX_VERIFY="-Xverify:none"
@@ -177,7 +177,12 @@ fi
 
 if [ "$INTERPRETER" = "y" ]; then
     INT_OPTS="-Xint"
-    COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
+    if [ "$VERIFY" = "y" ] ; then
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
+    else
+      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
+      DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
+    fi
 fi
 
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
index 7b3db5f..a6a4e78 100755 (executable)
@@ -23,6 +23,7 @@ FLAGS=""
 TARGET_SUFFIX="32"
 GDB_TARGET_SUFFIX=""
 SECONDARY_DEX=""
+DEX_VERIFY=""
 
 while true; do
     if [ "x$1" = "x--quiet" ]; then
@@ -123,7 +124,6 @@ if [ "$ZYGOTE" = "" ]; then
     fi
 
     if [ "$VERIFY" = "y" ]; then
-        DEX_VERIFY=""
         msg "Performing verification"
     else
         DEX_VERIFY="-Xverify:none"
@@ -164,6 +164,12 @@ fi
 
 if [ "$INTERPRETER" = "y" ]; then
     INT_OPTS="-Xint"
+    if [ "$VERIFY" = "y" ] ; then
+      COMPILER_FLAGS="${COMPILER_FLAGS} --compiler-filter=interpret-only"
+    else
+      COMPILER_FLAGS="${COMPILER_FLAGS} --compiler-filter=verify-none"
+      DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
+    fi
 fi
 
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
@@ -176,7 +182,7 @@ else
 fi
 
 cmdline="cd $DEX_LOCATION && export ANDROID_DATA=$DEX_LOCATION && export DEX_LOCATION=$DEX_LOCATION && \
-    $INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX $FLAGS $gdbargs -XXlib:$LIB $ZYGOTE $JNI_OPTS $RELOCATE_OPT $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX Main"
+    $INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX $FLAGS $DEX_VERIFY $gdbargs -XXlib:$LIB $ZYGOTE $JNI_OPTS $RELOCATE_OPT $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX Main"
 if [ "$DEV_MODE" = "y" ]; then
   echo $cmdline "$@"
 fi