summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2011-02-22 20:20:36 -0800
committerJesse Wilson <jessewilson@google.com>2011-02-23 13:30:36 -0800
commit3c6f4c012e0a314dc9f9f540b9374dbf530d03b0 (patch)
treea8b909adb787ca7847a1d181a9996a0bbf00c868
parent6c360b86f5774376140636ff60ad4af3814fef21 (diff)
downloadandroid_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.c2
-rw-r--r--libdex/DexProto.h6
-rw-r--r--vm/native/java_lang_Class.c21
-rw-r--r--vm/oo/Object.h3
-rw-r--r--vm/reflect/Reflect.c100
-rw-r--r--vm/reflect/Reflect.h6
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.
*/