OSDN Git Service

Optimize Class.getMethod() by loading only one method.
authorJesse Wilson <jessewilson@google.com>
Wed, 23 Feb 2011 04:20:36 +0000 (20:20 -0800)
committerJesse Wilson <jessewilson@google.com>
Wed, 23 Feb 2011 21:30:36 +0000 (13:30 -0800)
Change-Id: Ia2cd776c0a14914264e8d94e978d55854ed75623
http://b/3431686

libdex/DexProto.c
libdex/DexProto.h
vm/native/java_lang_Class.c
vm/oo/Object.h
vm/reflect/Reflect.c
vm/reflect/Reflect.h

index b5574dc..66d3e64 100644 (file)
@@ -33,7 +33,7 @@
  * Make sure that the given cache can hold a string of the given length,
  * including the final '\0' byte.
  */
-static void dexStringCacheAlloc(DexStringCache* pCache, size_t length) {
+void dexStringCacheAlloc(DexStringCache* pCache, size_t length) {
     if (pCache->allocatedSize != 0) {
         if (pCache->allocatedSize >= length) {
             return;
index 1ef577b..6e31648 100644 (file)
@@ -37,6 +37,12 @@ typedef struct DexStringCache {
 } DexStringCache;
 
 /*
+ * Make sure that the given cache can hold a string of the given length,
+ * including the final '\0' byte.
+ */
+void dexStringCacheAlloc(DexStringCache* pCache, size_t length);
+
+/*
  * Initialize the given DexStringCache. Use this function before passing
  * one into any other function.
  */
index 3bb6885..1cd31df 100644 (file)
@@ -275,6 +275,25 @@ static void Dalvik_java_lang_Class_getDeclaredMethods(const u4* args,
 }
 
 /*
+ * static native Member getDeclaredConstructorOrMethod(
+ *     Class clazz, String name, Class[] args);
+ */
+static void Dalvik_java_lang_Class_getDeclaredConstructorOrMethod(
+    const u4* args, JValue* pResult)
+{
+    ClassObject* clazz = (ClassObject*) args[0];
+    StringObject* nameObj = (StringObject*) args[1];
+    ArrayObject* methodArgs = (ArrayObject*) args[2];
+
+    Object* methodObj;
+
+    methodObj = dvmGetDeclaredConstructorOrMethod(clazz, nameObj, methodArgs);
+    dvmReleaseTrackedAlloc(methodObj, NULL);
+
+    RETURN_PTR(methodObj);
+}
+
+/*
  * Class[] getInterfaces()
  */
 static void Dalvik_java_lang_Class_getInterfaces(const u4* args,
@@ -741,6 +760,8 @@ const DalvikNativeMethod dvm_java_lang_Class[] = {
         Dalvik_java_lang_Class_getDeclaredFields },
     { "getDeclaredMethods",     "(Ljava/lang/Class;Z)[Ljava/lang/reflect/Method;",
         Dalvik_java_lang_Class_getDeclaredMethods },
+    { "getDeclaredConstructorOrMethod", "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;",
+        Dalvik_java_lang_Class_getDeclaredConstructorOrMethod },
     { "getInterfaces",          "()[Ljava/lang/Class;",
         Dalvik_java_lang_Class_getInterfaces },
     { "getModifiers",           "(Ljava/lang/Class;Z)I",
index 4fc0e5c..fd37da0 100644 (file)
@@ -710,6 +710,9 @@ INLINE bool dvmIsNativeMethod(const Method* method) {
 INLINE bool dvmIsAbstractMethod(const Method* method) {
     return (method->accessFlags & ACC_ABSTRACT) != 0;
 }
+INLINE bool dvmIsSyntheticMethod(const Method* method) {
+    return (method->accessFlags & ACC_SYNTHETIC) != 0;
+}
 INLINE bool dvmIsMirandaMethod(const Method* method) {
     return (method->accessFlags & ACC_MIRANDA) != 0;
 }
index 2a7c740..a881a92 100644 (file)
@@ -817,6 +817,106 @@ fail:
 }
 
 /*
+ * Fills targetDescriptorCache with the descriptors of the classes in args.
+ * This is the concatenation of the descriptors with no other adornment,
+ * consistent with dexProtoGetParameterDescriptors.
+ */
+static void createTargetDescriptor(ArrayObject* args,
+    DexStringCache* targetDescriptorCache)
+{
+    size_t i;
+    ClassObject** argsArray = NULL;
+    size_t length;
+    char* at;
+    const char* descriptor;
+
+    argsArray = (ClassObject**) args->contents;
+
+    length = 1; /* +1 for the terminating '\0' */
+    for (i = 0; i < args->length; ++i) {
+        length += strlen(argsArray[i]->descriptor);
+    }
+
+    dexStringCacheAlloc(targetDescriptorCache, length);
+
+    at = (char*) targetDescriptorCache->value;
+    for (i = 0; i < args->length; ++i) {
+        descriptor = argsArray[i]->descriptor;
+        strcpy(at, descriptor);
+        at += strlen(descriptor);
+    }
+}
+
+static Object* findConstructorOrMethodInArray(int methodsCount, Method* methods,
+    const char* name, const char* parameterDescriptors,
+    DexStringCache* stringCache)
+{
+    Method* method = NULL;
+    Method* result = NULL;
+    int i;
+
+    for (i = 0; i < methodsCount; ++i) {
+        method = &methods[i];
+        if (strcmp(name, method->name) != 0
+            || dvmIsMirandaMethod(method)
+            || strcmp(parameterDescriptors, dexProtoGetParameterDescriptors(
+                &method->prototype, stringCache)) != 0) {
+            continue;
+        }
+
+        result = method;
+
+        /*
+         * Covariant return types permit the class to define multiple
+         * methods with the same name and parameter types. Prefer to return
+         * a non-synthetic method in such situations. We may still return
+         * a synthetic method to handle situations like escalated visibility.
+         */
+        if (!dvmIsSyntheticMethod(method)) {
+            break;
+        }
+    }
+
+    if (result != NULL) {
+        return dvmCreateReflectObjForMethod(result->clazz, result);
+    }
+
+    return NULL;
+}
+
+/*
+ * Get the named method.
+ */
+Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
+    StringObject* nameObj, ArrayObject* args)
+{
+    Object* result = NULL;
+    DexStringCache stringCache;
+    DexStringCache targetDescriptorCache;
+    char* name;
+    const char* targetDescriptor;
+
+    dexStringCacheInit(&stringCache);
+    dexStringCacheInit(&targetDescriptorCache);
+
+    name = dvmCreateCstrFromString(nameObj);
+    createTargetDescriptor(args, &targetDescriptorCache);
+    targetDescriptor = targetDescriptorCache.value;
+
+    result = findConstructorOrMethodInArray(clazz->directMethodCount,
+        clazz->directMethods, name, targetDescriptor, &stringCache);
+    if (result == NULL) {
+        result = findConstructorOrMethodInArray(clazz->virtualMethodCount,
+            clazz->virtualMethods, name, targetDescriptor, &stringCache);
+    }
+
+    free(name);
+    dexStringCacheRelease(&stringCache);
+    dexStringCacheRelease(&targetDescriptorCache);
+    return result;
+}
+
+/*
  * Get all interfaces a class implements. If this is unable to allocate
  * the result array, this raises an OutOfMemoryError and returns NULL.
  */
index c9a9a22..42b18c0 100644 (file)
@@ -51,6 +51,12 @@ ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly);
 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly);
 
 /*
+ * Get the named method.
+ */
+Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
+    StringObject* nameObj, ArrayObject* args);
+
+/*
  * Get all interfaces a class implements. If this is unable to allocate
  * the result array, this raises an OutOfMemoryError and returns NULL.
  */