Search for miranda methods in virtual methods instead of interface.

Also added tests that get miranda methods via reflection and jni.
Miranda methods can't be found via reflection, and have the interface
class as their declaring class when found via jni.

Bug: 11736932
Change-Id: I92b4fdf31be64269898ed2686a28dfb6008b213a
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 4dcce1e..3a28974 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -248,7 +248,7 @@
   if (method->IsDirect()) {
     return method;
   }
-  if (method->GetDeclaringClass()->IsInterface()) {
+  if (method->GetDeclaringClass()->IsInterface() && !method->IsMiranda()) {
     return FindVirtualMethodForInterface(method);
   }
   return FindVirtualMethodForVirtual(method);
diff --git a/test/040-miranda/expected.txt b/test/040-miranda/expected.txt
index e22bbd9..011be2a 100644
--- a/test/040-miranda/expected.txt
+++ b/test/040-miranda/expected.txt
@@ -10,3 +10,5 @@
   inInterface:  true
   inInterface2: 28
   inAbstract:   true
+Test getting miranda method via reflection:
+  caught expected NoSuchMethodException
diff --git a/test/040-miranda/src/Main.java b/test/040-miranda/src/Main.java
index 1fd8287..ff5eba0 100644
--- a/test/040-miranda/src/Main.java
+++ b/test/040-miranda/src/Main.java
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.Method;
+
 /**
  * Miranda testing.
  */
@@ -37,5 +39,16 @@
         System.out.println("  inInterface:  " + mira2.inInterface());
         System.out.println("  inInterface2: " + mira2.inInterface2());
         System.out.println("  inAbstract:   " + mira2.inAbstract());
+
+        System.out.println("Test getting miranda method via reflection:");
+        try {
+          Class mirandaClass = Class.forName("MirandaAbstract");
+          Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface", (Class[]) null);
+          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/JniTest/JniTest.java b/test/JniTest/JniTest.java
index 7014ef9..a1b1f0c 100644
--- a/test/JniTest/JniTest.java
+++ b/test/JniTest/JniTest.java
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+import java.lang.reflect.Method;
+
 class JniTest {
     public static void main(String[] args) {
         System.loadLibrary("arttest");
         testFindClassOnAttachedNativeThread();
         testCallStaticVoidMethodOnSubClass();
+        testGetMirandaMethod();
     }
 
     private static native void testFindClassOnAttachedNativeThread();
@@ -42,4 +45,23 @@
     private static class testCallStaticVoidMethodOnSubClass_SubClass
         extends testCallStaticVoidMethodOnSubClass_SuperClass {
     }
+
+    private static native Method testGetMirandaMethodNative();
+
+    private static void testGetMirandaMethod() {
+        Method m = testGetMirandaMethodNative();
+        if (m.getDeclaringClass() != testGetMirandaMethod_MirandaInterface.class) {
+            throw new AssertionError();
+        }
+    }
+
+    private static abstract class testGetMirandaMethod_MirandaAbstract implements testGetMirandaMethod_MirandaInterface {
+        public boolean inAbstract() {
+            return true;
+        }
+    }
+
+    private static interface testGetMirandaMethod_MirandaInterface {
+        public boolean inInterface();
+    }
 }
diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc
index 72a3309..cfcbb64 100644
--- a/test/JniTest/jni_test.cc
+++ b/test/JniTest/jni_test.cc
@@ -81,3 +81,11 @@
 
   env->CallStaticVoidMethod(sub_class, execute);
 }
+
+extern "C" JNIEXPORT jobject JNICALL Java_JniTest_testGetMirandaMethodNative(JNIEnv* env, jclass) {
+  jclass abstract_class = env->FindClass("JniTest$testGetMirandaMethod_MirandaAbstract");
+  assert(abstract_class != NULL);
+  jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z");
+  assert(miranda_method != NULL);
+  return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE);
+}
diff --git a/test/run-test b/test/run-test
index f706110..c3943e7 100755
--- a/test/run-test
+++ b/test/run-test
@@ -65,7 +65,7 @@
 dev_mode="no"
 update_mode="no"
 debug_mode="no"
-dalvik_mode="no"
+runtime="art"
 usage="no"
 build_only="no"
 
@@ -77,6 +77,7 @@
         shift
     elif [ "x$1" = "x--jvm" ]; then
         target_mode="no"
+        runtime="jvm"
         RUN="${progdir}/etc/reference-run-test-classes"
         NEED_DEX="false"
         shift
@@ -85,7 +86,7 @@
         shift
     elif [ "x$1" = "x--dalvik" ]; then
         lib="libdvm.so"
-        dalvik_mode="yes"
+        runtime="dalvik"
         shift
     elif [ "x$1" = "x--image" ]; then
         shift
@@ -155,15 +156,11 @@
     fi
 done
 
-run_args="${run_args} --lib $lib"
+if [ ! "$runtime" = "jvm" ]; then
+  run_args="${run_args} --lib $lib"
+fi
 
-if [ "$dalvik_mode" = "no" ]; then
-    if [ "$target_mode" = "no" ]; then
-        run_args="${run_args} --boot -Ximage:${ANDROID_HOST_OUT}/framework/core.art"
-    else
-        run_args="${run_args} --boot -Ximage:/data/art-test/core.art"
-    fi
-else
+if [ "$runtime" = "dalvik" ]; then
     if [ "$target_mode" = "no" ]; then
         framework="${OUT}/system/framework"
         bpath="${framework}/core.jar:${framework}/conscrypt.jar:${framework}/okhttp.jar:${framework}/core-junit.jar:${framework}/bouncycastle.jar:${framework}/ext.jar"
@@ -171,6 +168,12 @@
     else
         true # defaults to using target BOOTCLASSPATH
     fi
+elif [ "$runtime" = "art" ]; then
+    if [ "$target_mode" = "no" ]; then
+        run_args="${run_args} --boot -Ximage:${ANDROID_HOST_OUT}/framework/core.art"
+    else
+        run_args="${run_args} --boot -Ximage:/data/art-test/core.art"
+    fi
 fi
 
 if [ "$dev_mode" = "yes" -a "$update_mode" = "yes" ]; then