OSDN Git Service

Fix JNI GetMethodID on interfaces
authorAndy McFadden <fadden@android.com>
Fri, 7 Jan 2011 01:04:05 +0000 (17:04 -0800)
committerAndy McFadden <fadden@android.com>
Fri, 7 Jan 2011 18:47:28 +0000 (10:47 -0800)
The GetMethodID call was only searching through methods declared by
classes and superclasses.  If you passed it an interface class and
asked for a method declared in a superinterface, the call would fail.
We now have separate code for handling lookups on interfaces.

This also refactors some similar code in the interface method resolver.

Bug 3329492

Change-Id: I4db505231501ef089cd1c406b4654e897bd77d48

vm/Jni.c
vm/analysis/Optimize.c
vm/oo/Object.c
vm/oo/Object.h
vm/oo/Resolve.c

index ac6ae70..41e547d 100644 (file)
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -2333,6 +2333,11 @@ static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz)
 /*
  * Get a method ID for an instance method.
  *
+ * While Dalvik bytecode has distinct instructions for virtual, super,
+ * static, direct, and interface method invocation, JNI only provides
+ * two functions for acquiring a method ID.  This call handles everything
+ * but static methods.
+ *
  * JNI defines <init> as an instance method, but Dalvik considers it a
  * "direct" method, so we have to special-case it here.
  *
@@ -2349,10 +2354,16 @@ static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,
 
     if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
         assert(dvmCheckException(_self));
+    } else if (dvmIsInterfaceClass(clazz)) {
+        Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
+        if (meth == NULL) {
+            dvmThrowExceptionFmt("Ljava/lang/NoSuchMethodError;",
+                "no method with name='%s' signature='%s' in interface %s",
+                name, sig, clazz->descriptor);
+        }
+        id = (jmethodID) meth;
     } else {
-        Method* meth;
-
-        meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
+        Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
         if (meth == NULL) {
             /* search private methods and constructors; non-hierarchical */
             meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
index f37dd75..69990a4 100644 (file)
@@ -922,7 +922,6 @@ Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
 {
     DvmDex* pDvmDex = referrer->pDvmDex;
     Method* resMethod;
-    int i;
 
     LOGVV("--- resolving interface method %d (referrer=%s)\n",
         methodIdx, referrer->descriptor);
@@ -953,24 +952,10 @@ Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx)
 
         LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
             methodName, methodSig, resClass->descriptor);
-        resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
+        resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
         if (resMethod == NULL) {
-            /* scan superinterfaces and superclass interfaces */
-            LOGVV("+++ did not resolve immediately\n");
-            for (i = 0; i < resClass->iftableCount; i++) {
-                resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
-                                methodName, &proto);
-                if (resMethod != NULL)
-                    break;
-            }
-
-            if (resMethod == NULL) {
-                LOGVV("+++ unable to resolve method %s\n", methodName);
-                return NULL;
-            }
-        } else {
-            LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
-                resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
+            dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName);
+            return NULL;
         }
 
         /* we're expecting this to be abstract */
index 32ed679..e99f690 100644 (file)
@@ -517,7 +517,7 @@ Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName,
 
 /*
  * Find a "virtual" method in a class.  If we don't find it, try the
- * superclass.
+ * superclass.  Does not examine interfaces.
  *
  * Returns NULL if the method can't be found.  (Does not throw an exception.)
  */
@@ -530,7 +530,7 @@ Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
 
 /*
  * Find a "virtual" method in a class.  If we don't find it, try the
- * superclass.
+ * superclass.  Does not examine interfaces.
  *
  * Returns NULL if the method can't be found.  (Does not throw an exception.)
  */
@@ -542,6 +542,51 @@ Method* dvmFindVirtualMethodHier(const ClassObject* clazz,
 }
 
 /*
+ * Find a method in an interface.  Searches superinterfaces.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindInterfaceMethodHierByDescriptor(const ClassObject* iface,
+    const char* methodName, const char* descriptor)
+{
+    Method* resMethod = dvmFindVirtualMethodByDescriptor(iface,
+        methodName, descriptor);
+    if (resMethod == NULL) {
+        /* scan superinterfaces and superclass interfaces */
+        int i;
+        for (i = 0; i < iface->iftableCount; i++) {
+            resMethod = dvmFindVirtualMethodByDescriptor(iface->iftable[i].clazz,
+                methodName, descriptor);
+            if (resMethod != NULL)
+                break;
+        }
+    }
+    return resMethod;
+}
+
+/*
+ * Find a method in an interface.  Searches superinterfaces.
+ *
+ * Returns NULL if the method can't be found.  (Does not throw an exception.)
+ */
+Method* dvmFindInterfaceMethodHier(const ClassObject* iface,
+    const char* methodName, const DexProto* proto)
+{
+    Method* resMethod = dvmFindVirtualMethod(iface, methodName, proto);
+    if (resMethod == NULL) {
+        /* scan superinterfaces and superclass interfaces */
+        int i;
+        for (i = 0; i < iface->iftableCount; i++) {
+            resMethod = dvmFindVirtualMethod(iface->iftable[i].clazz,
+                methodName, proto);
+            if (resMethod != NULL)
+                break;
+        }
+    }
+    return resMethod;
+}
+
+/*
  * Find a "direct" method (static, private, or "<*init>").
  *
  * Returns NULL if the method can't be found.  (Does not throw an exception.)
index 903450f..4fc0e5c 100644 (file)
@@ -629,6 +629,14 @@ Method* dvmFindMethodHier(const ClassObject* clazz, const char* methodName,
     const DexProto* proto);
 
 /*
+ * Find a method in an interface hierarchy.
+ */
+Method* dvmFindInterfaceMethodHierByDescriptor(const ClassObject* iface,
+    const char* methodName, const char* descriptor);
+Method* dvmFindInterfaceMethodHier(const ClassObject* iface,
+    const char* methodName, const DexProto* proto);
+
+/*
  * Find the implementation of "meth" in "clazz".
  *
  * Returns NULL and throws an exception if not found.
index c4bda8b..b277576 100644 (file)
@@ -287,7 +287,6 @@ Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx)
     ClassObject* resClass;
     const DexMethodId* pMethodId;
     Method* resMethod;
-    int i;
 
     LOGVV("--- resolving interface method %d (referrer=%s)\n",
         methodIdx, referrer->descriptor);
@@ -338,23 +337,10 @@ Method* dvmResolveInterfaceMethod(const ClassObject* referrer, u4 methodIdx)
 
     LOGVV("+++ looking for '%s' '%s' in resClass='%s'\n",
         methodName, methodSig, resClass->descriptor);
-    resMethod = dvmFindVirtualMethod(resClass, methodName, &proto);
+    resMethod = dvmFindInterfaceMethodHier(resClass, methodName, &proto);
     if (resMethod == NULL) {
-        LOGVV("+++ did not resolve immediately\n");
-        for (i = 0; i < resClass->iftableCount; i++) {
-            resMethod = dvmFindVirtualMethod(resClass->iftable[i].clazz,
-                            methodName, &proto);
-            if (resMethod != NULL)
-                break;
-        }
-
-        if (resMethod == NULL) {
-            dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName);
-            return NULL;
-        }
-    } else {
-        LOGVV("+++ resolved immediately: %s (%s %d)\n", resMethod->name,
-            resMethod->clazz->descriptor, (u4) resMethod->methodIndex);
+        dvmThrowException("Ljava/lang/NoSuchMethodError;", methodName);
+        return NULL;
     }
 
     LOGVV("--- found interface method %d (%s.%s)\n",