diff options
author | Jesse Wilson <jessewilson@google.com> | 2011-02-22 20:20:36 -0800 |
---|---|---|
committer | Jesse Wilson <jessewilson@google.com> | 2011-02-23 13:30:36 -0800 |
commit | 3c6f4c012e0a314dc9f9f540b9374dbf530d03b0 (patch) | |
tree | a8b909adb787ca7847a1d181a9996a0bbf00c868 | |
parent | 6c360b86f5774376140636ff60ad4af3814fef21 (diff) | |
download | android_dalvik-3c6f4c012e0a314dc9f9f540b9374dbf530d03b0.tar.gz android_dalvik-3c6f4c012e0a314dc9f9f540b9374dbf530d03b0.tar.bz2 android_dalvik-3c6f4c012e0a314dc9f9f540b9374dbf530d03b0.zip |
Optimize Class.getMethod() by loading only one method.
Change-Id: Ia2cd776c0a14914264e8d94e978d55854ed75623
http://b/3431686
-rw-r--r-- | libdex/DexProto.c | 2 | ||||
-rw-r--r-- | libdex/DexProto.h | 6 | ||||
-rw-r--r-- | vm/native/java_lang_Class.c | 21 | ||||
-rw-r--r-- | vm/oo/Object.h | 3 | ||||
-rw-r--r-- | vm/reflect/Reflect.c | 100 | ||||
-rw-r--r-- | vm/reflect/Reflect.h | 6 |
6 files changed, 137 insertions, 1 deletions
diff --git a/libdex/DexProto.c b/libdex/DexProto.c index b5574dc0f..66d3e6413 100644 --- a/libdex/DexProto.c +++ b/libdex/DexProto.c @@ -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; diff --git a/libdex/DexProto.h b/libdex/DexProto.h index 1ef577b5b..6e3164803 100644 --- a/libdex/DexProto.h +++ b/libdex/DexProto.h @@ -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. */ diff --git a/vm/native/java_lang_Class.c b/vm/native/java_lang_Class.c index 3bb688531..1cd31dfe9 100644 --- a/vm/native/java_lang_Class.c +++ b/vm/native/java_lang_Class.c @@ -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", diff --git a/vm/oo/Object.h b/vm/oo/Object.h index 4fc0e5ca5..fd37da0ae 100644 --- a/vm/oo/Object.h +++ b/vm/oo/Object.h @@ -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; } diff --git a/vm/reflect/Reflect.c b/vm/reflect/Reflect.c index 2a7c74061..a881a92b3 100644 --- a/vm/reflect/Reflect.c +++ b/vm/reflect/Reflect.c @@ -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. */ diff --git a/vm/reflect/Reflect.h b/vm/reflect/Reflect.h index c9a9a22ca..42b18c01b 100644 --- a/vm/reflect/Reflect.h +++ b/vm/reflect/Reflect.h @@ -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. */ |