diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
| commit | f72d5de56a522ac3be03873bdde26f23a5eeeb3c (patch) | |
| tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /vm/reflect | |
| parent | 31e30105703263782efd450d356cd67ea01af3b7 (diff) | |
| download | android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.gz android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.bz2 android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.zip | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'vm/reflect')
| -rw-r--r-- | vm/reflect/Annotation.c | 2179 | ||||
| -rw-r--r-- | vm/reflect/Proxy.c | 1097 | ||||
| -rw-r--r-- | vm/reflect/Reflect.c | 1258 | ||||
| -rw-r--r-- | vm/reflect/Reflect.h | 239 |
4 files changed, 0 insertions, 4773 deletions
diff --git a/vm/reflect/Annotation.c b/vm/reflect/Annotation.c deleted file mode 100644 index c07c602ea..000000000 --- a/vm/reflect/Annotation.c +++ /dev/null @@ -1,2179 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Annotations. - * - * We're not expecting to make much use of runtime annotations, so speed vs. - * space choices are weighted heavily toward small size. - * - * It would have been nice to treat "system" annotations in the same way - * we do "real" annotations, but that doesn't work. The chief difficulty - * is that some of them have member types that are not legal in annotations, - * such as Method and Annotation. Another source of pain comes from the - * AnnotationDefault annotation, which by virtue of being an annotation - * could itself have default values, requiring some additional checks to - * prevent recursion. - * - * It's simpler, and more efficient, to handle the system annotations - * entirely inside the VM. There are empty classes defined for the system - * annotation types, but their only purpose is to allow the system - * annotations to share name space with standard annotations. - */ -#include "Dalvik.h" - -// fwd -static Object* processEncodedAnnotation(const ClassObject* clazz,\ - const u1** pPtr); -static bool skipEncodedAnnotation(const ClassObject* clazz, const u1** pPtr); - -/* - * System annotation descriptors. - */ -static const char* kDescrAnnotationDefault - = "Ldalvik/annotation/AnnotationDefault;"; -static const char* kDescrEnclosingClass - = "Ldalvik/annotation/EnclosingClass;"; -static const char* kDescrEnclosingMethod - = "Ldalvik/annotation/EnclosingMethod;"; -static const char* kDescrInnerClass = "Ldalvik/annotation/InnerClass;"; -static const char* kDescrMemberClasses - = "Ldalvik/annotation/MemberClasses;"; -static const char* kDescrSignature = "Ldalvik/annotation/Signature;"; -static const char* kDescrThrows = "Ldalvik/annotation/Throws;"; - - -/* - * Perform Annotation setup. - */ -bool dvmReflectAnnotationStartup(void) -{ - Method* meth; - - /* - * Find some standard Annotation classes. - */ - gDvm.classJavaLangAnnotationAnnotationArray = - dvmFindArrayClass("[Ljava/lang/annotation/Annotation;", NULL); - gDvm.classJavaLangAnnotationAnnotationArrayArray = - dvmFindArrayClass("[[Ljava/lang/annotation/Annotation;", NULL); - if (gDvm.classJavaLangAnnotationAnnotationArray == NULL || - gDvm.classJavaLangAnnotationAnnotationArrayArray == NULL) - { - LOGE("Could not find Annotation-array classes\n"); - return false; - } - - /* - * VM-specific annotation classes. - */ - gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory = - dvmFindSystemClassNoInit("Lorg/apache/harmony/lang/annotation/AnnotationFactory;"); - gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember = - dvmFindSystemClassNoInit("Lorg/apache/harmony/lang/annotation/AnnotationMember;"); - gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMemberArray = - dvmFindArrayClass("[Lorg/apache/harmony/lang/annotation/AnnotationMember;", NULL); - if (gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory == NULL || - gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember == NULL || - gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMemberArray == NULL) - { - LOGE("Could not find android.lang annotation classes\n"); - return false; - } - - meth = dvmFindDirectMethodByDescriptor(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory, - "createAnnotation", - "(Ljava/lang/Class;[Lorg/apache/harmony/lang/annotation/AnnotationMember;)Ljava/lang/annotation/Annotation;"); - if (meth == NULL) { - LOGE("Unable to find createAnnotation() in android AnnotationFactory\n"); - return false; - } - gDvm.methOrgApacheHarmonyLangAnnotationAnnotationFactory_createAnnotation = meth; - - meth = dvmFindDirectMethodByDescriptor(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember, - "<init>", - "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/reflect/Method;)V"); - if (meth == NULL) { - LOGE("Unable to find 4-arg constructor in android AnnotationMember\n"); - return false; - } - - gDvm.methOrgApacheHarmonyLangAnnotationAnnotationMember_init = meth; - - return true; -} - -/* - * Read an unsigned LEB128 value from a buffer. Advances "pBuf". - */ -static u4 readUleb128(const u1** pBuf) -{ - u4 result = 0; - int shift = 0; - const u1* buf = *pBuf; - u1 val; - - do { - /* - * Worst-case on bad data is we read too much data and return a bogus - * result. Safe to assume that we will encounter a byte with its - * high bit clear before the end of the mapped file. - */ - assert(shift < 32); - - val = *buf++; - result |= (val & 0x7f) << shift; - shift += 7; - } while ((val & 0x80) != 0); - - *pBuf = buf; - return result; -} - -/* - * Get the annotations directory item. - */ -static const DexAnnotationsDirectoryItem* getAnnoDirectory(DexFile* pDexFile, - const ClassObject* clazz) -{ - const DexClassDef* pClassDef; - - /* - * Find the class def in the DEX file. For better performance we should - * stash this in the ClassObject. - */ - pClassDef = dexFindClass(pDexFile, clazz->descriptor); - assert(pClassDef != NULL); - return dexGetAnnotationsDirectoryItem(pDexFile, pClassDef); -} - -/* - * Return a zero-length array of Annotation objects. - * - * TODO: this currently allocates a new array each time, but I think we - * can get away with returning a canonical copy. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -static ArrayObject* emptyAnnoArray(void) -{ - return dvmAllocArrayByClass( - gDvm.classJavaLangAnnotationAnnotationArray, 0, ALLOC_DEFAULT); -} - -/* - * Return an array of empty arrays of Annotation objects. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -static ArrayObject* emptyAnnoArrayArray(int numElements) -{ - Thread* self = dvmThreadSelf(); - ArrayObject* arr; - int i; - - arr = dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArrayArray, - numElements, ALLOC_DEFAULT); - if (arr != NULL) { - ArrayObject** elems = (ArrayObject**) arr->contents; - for (i = 0; i < numElements; i++) { - elems[i] = emptyAnnoArray(); - dvmReleaseTrackedAlloc((Object*)elems[i], self); - } - } - - return arr; -} - -/* - * Read a signed integer. "zwidth" is the zero-based byte count. - */ -static s4 readSignedInt(const u1* ptr, int zwidth) -{ - s4 val = 0; - int i; - - for (i = zwidth; i >= 0; --i) - val = ((u4)val >> 8) | (((s4)*ptr++) << 24); - val >>= (3 - zwidth) * 8; - - return val; -} - -/* - * Read an unsigned integer. "zwidth" is the zero-based byte count, - * "fillOnRight" indicates which side we want to zero-fill from. - */ -static u4 readUnsignedInt(const u1* ptr, int zwidth, bool fillOnRight) -{ - u4 val = 0; - int i; - - if (!fillOnRight) { - for (i = zwidth; i >= 0; --i) - val = (val >> 8) | (((u4)*ptr++) << 24); - val >>= (3 - zwidth) * 8; - } else { - for (i = zwidth; i >= 0; --i) - val = (val >> 8) | (((u4)*ptr++) << 24); - } - return val; -} - -/* - * Read a signed long. "zwidth" is the zero-based byte count. - */ -static s8 readSignedLong(const u1* ptr, int zwidth) -{ - s8 val = 0; - int i; - - for (i = zwidth; i >= 0; --i) - val = ((u8)val >> 8) | (((s8)*ptr++) << 56); - val >>= (7 - zwidth) * 8; - - return val; -} - -/* - * Read an unsigned long. "zwidth" is the zero-based byte count, - * "fillOnRight" indicates which side we want to zero-fill from. - */ -static u8 readUnsignedLong(const u1* ptr, int zwidth, bool fillOnRight) -{ - u8 val = 0; - int i; - - if (!fillOnRight) { - for (i = zwidth; i >= 0; --i) - val = (val >> 8) | (((u8)*ptr++) << 56); - val >>= (7 - zwidth) * 8; - } else { - for (i = zwidth; i >= 0; --i) - val = (val >> 8) | (((u8)*ptr++) << 56); - } - return val; -} - - -/* - * =========================================================================== - * Element extraction - * =========================================================================== - */ - -/* - * An annotation in "clazz" refers to a method by index. This just gives - * us the name of the class and the name and signature of the method. We - * need to find the method's class, and then find the method within that - * class. If the method has been resolved before, we can just use the - * results of the previous lookup. - * - * Normally we do this as part of method invocation in the interpreter, which - * provides us with a bit of context: is it virtual or direct, do we need - * to initialize the class because it's a static method, etc. We don't have - * that information here, so we have to do a bit of searching. - * - * Returns NULL if the method was not found (exception may be pending). - */ -static Method* resolveAmbiguousMethod(const ClassObject* referrer, u4 methodIdx) -{ - DexFile* pDexFile; - ClassObject* resClass; - Method* resMethod; - const DexMethodId* pMethodId; - const char* name; - const char* signature; - - /* if we've already resolved this method, return it */ - resMethod = dvmDexGetResolvedMethod(referrer->pDvmDex, methodIdx); - if (resMethod != NULL) - return resMethod; - - pDexFile = referrer->pDvmDex->pDexFile; - pMethodId = dexGetMethodId(pDexFile, methodIdx); - resClass = dvmResolveClass(referrer, pMethodId->classIdx, true); - if (resClass == NULL) { - /* note exception will be pending */ - LOGD("resolveAmbiguousMethod: unable to find class %d\n", methodIdx); - return NULL; - } - if (dvmIsInterfaceClass(resClass)) { - /* method is part of an interface -- not expecting that */ - LOGD("resolveAmbiguousMethod: method in interface?\n"); - return NULL; - } - - // TODO - consider a method access flag that indicates direct vs. virtual - name = dexStringById(pDexFile, pMethodId->nameIdx); - - DexProto proto; - dexProtoSetFromMethodId(&proto, pDexFile, pMethodId); - - if (name[0] == '<') { - /* - * Constructor or class initializer. Only need to examine the - * "direct" list, and don't need to look up the class hierarchy. - */ - resMethod = dvmFindDirectMethod(resClass, name, &proto); - } else { - /* - * Try both lists, and scan up the tree. - */ - resMethod = dvmFindVirtualMethodHier(resClass, name, &proto); - if (resMethod == NULL) - resMethod = dvmFindDirectMethodHier(resClass, name, &proto); - } - - return resMethod; -} - -/* - * constants for processAnnotationValue indicating what style of - * result is wanted - */ -typedef enum { - kAllObjects, /* return everything as an object */ - kAllRaw, /* return everything as a raw value or index */ - kPrimitivesOrObjects /* return primitives as-is but the rest as objects */ -} AnnotationResultStyle; - -/* - * Recursively process an annotation value. - * - * "clazz" is the class on which the annotations are defined. It may be - * NULL when "resultStyle" is "kAllRaw". - * - * If "resultStyle" is "kAllObjects", the result will always be an Object of an - * appropriate type (in pValue->value.l). For primitive types, the usual - * wrapper objects will be created. - * - * If "resultStyle" is "kAllRaw", numeric constants are stored directly into - * "pValue", and indexed values like String and Method are returned as - * indexes. Complex values like annotations and arrays are not handled. - * - * If "resultStyle" is "kPrimitivesOrObjects", numeric constants are stored - * directly into "pValue", and everything else is constructed as an Object - * of appropriate type (in pValue->value.l). - * - * The caller must call dvmReleaseTrackedAlloc on returned objects, when - * using "kAllObjects" or "kPrimitivesOrObjects". - * - * Returns "true" on success, "false" if the value could not be processed - * or an object could not be allocated. On allocation failure an exception - * will be raised. - */ -static bool processAnnotationValue(const ClassObject* clazz, - const u1** pPtr, AnnotationValue* pValue, - AnnotationResultStyle resultStyle) -{ - Thread* self = dvmThreadSelf(); - Object* elemObj = NULL; - bool setObject = false; - const u1* ptr = *pPtr; - u1 valueType, valueArg; - int width; - u4 idx; - - valueType = *ptr++; - valueArg = valueType >> kDexAnnotationValueArgShift; - width = valueArg + 1; /* assume, correct later */ - - LOGV("----- type is 0x%02x %d, ptr=%p [0x%06x]\n", - valueType & kDexAnnotationValueTypeMask, valueArg, ptr-1, - (ptr-1) - (u1*)clazz->pDvmDex->pDexFile->baseAddr); - - pValue->type = valueType & kDexAnnotationValueTypeMask; - - switch (valueType & kDexAnnotationValueTypeMask) { - case kDexAnnotationByte: - pValue->value.i = (s1) readSignedInt(ptr, valueArg); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('B')); - setObject = true; - } - break; - case kDexAnnotationShort: - pValue->value.i = (s2) readSignedInt(ptr, valueArg); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('S')); - setObject = true; - } - break; - case kDexAnnotationChar: - pValue->value.i = (u2) readUnsignedInt(ptr, valueArg, false); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('C')); - setObject = true; - } - break; - case kDexAnnotationInt: - pValue->value.i = readSignedInt(ptr, valueArg); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('I')); - setObject = true; - } - break; - case kDexAnnotationLong: - pValue->value.j = readSignedLong(ptr, valueArg); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('J')); - setObject = true; - } - break; - case kDexAnnotationFloat: - pValue->value.i = readUnsignedInt(ptr, valueArg, true); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('F')); - setObject = true; - } - break; - case kDexAnnotationDouble: - pValue->value.j = readUnsignedLong(ptr, valueArg, true); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('D')); - setObject = true; - } - break; - case kDexAnnotationBoolean: - pValue->value.i = (valueArg != 0); - if (resultStyle == kAllObjects) { - elemObj = (Object*) dvmWrapPrimitive(pValue->value, - dvmFindPrimitiveClass('Z')); - setObject = true; - } - width = 0; - break; - - case kDexAnnotationString: - idx = readUnsignedInt(ptr, valueArg, false); - if (resultStyle == kAllRaw) { - pValue->value.i = idx; - } else { - elemObj = (Object*) dvmResolveString(clazz, idx); - setObject = true; - if (elemObj == NULL) - return false; - dvmAddTrackedAlloc(elemObj, self); // balance the Release - } - break; - case kDexAnnotationType: - idx = readUnsignedInt(ptr, valueArg, false); - if (resultStyle == kAllRaw) { - pValue->value.i = idx; - } else { - elemObj = (Object*) dvmResolveClass(clazz, idx, true); - setObject = true; - if (elemObj == NULL) { - /* we're expected to throw a TypeNotPresentException here */ - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const char* desc = dexStringByTypeIdx(pDexFile, idx); - dvmClearException(self); - dvmThrowExceptionWithClassMessage( - "Ljava/lang/TypeNotPresentException;", desc); - return false; - } else { - dvmAddTrackedAlloc(elemObj, self); // balance the Release - } - } - break; - case kDexAnnotationMethod: - idx = readUnsignedInt(ptr, valueArg, false); - if (resultStyle == kAllRaw) { - pValue->value.i = idx; - } else { - Method* meth = resolveAmbiguousMethod(clazz, idx); - if (meth == NULL) - return false; - elemObj = dvmCreateReflectObjForMethod(clazz, meth); - setObject = true; - if (elemObj == NULL) - return false; - } - break; - case kDexAnnotationField: - idx = readUnsignedInt(ptr, valueArg, false); - assert(false); // TODO - break; - case kDexAnnotationEnum: - /* enum values are the contents of a static field */ - idx = readUnsignedInt(ptr, valueArg, false); - if (resultStyle == kAllRaw) { - pValue->value.i = idx; - } else { - StaticField* sfield; - - sfield = dvmResolveStaticField(clazz, idx); - if (sfield == NULL) { - return false; - } else { - assert(sfield->field.clazz->descriptor[0] == 'L'); - elemObj = sfield->value.l; - setObject = true; - dvmAddTrackedAlloc(elemObj, self); // balance the Release - } - } - break; - case kDexAnnotationArray: - /* - * encoded_array format, which is a size followed by a stream - * of annotation_value. - * - * We create an array of Object, populate it, and return it. - */ - if (resultStyle == kAllRaw) { - return false; - } else { - ArrayObject* newArray; - Object** pObj; - u4 size; - - size = readUleb128(&ptr); - LOGVV("--- annotation array, size is %u at %p\n", size, ptr); - newArray = dvmAllocArrayByClass(gDvm.classJavaLangObjectArray, - size, ALLOC_DEFAULT); - if (newArray == NULL) { - LOGE("annotation element array alloc failed (%d)\n", size); - return false; - } - pObj = (Object**)newArray->contents; - - AnnotationValue avalue; - while (size--) { - if (!processAnnotationValue(clazz, &ptr, &avalue, - kAllObjects)) { - dvmReleaseTrackedAlloc((Object*)newArray, self); - return false; - } - Object* obj = avalue.value.l; - dvmReleaseTrackedAlloc(obj, self); - *pObj++ = obj; - } - - elemObj = (Object*) newArray; - setObject = true; - } - width = 0; - break; - case kDexAnnotationAnnotation: - /* encoded_annotation format */ - if (resultStyle == kAllRaw) - return false; - elemObj = processEncodedAnnotation(clazz, &ptr); - setObject = true; - if (elemObj == NULL) - return false; - dvmAddTrackedAlloc(elemObj, self); // balance the Release - width = 0; - break; - case kDexAnnotationNull: - if (resultStyle == kAllRaw) { - pValue->value.i = 0; - } else { - assert(elemObj == NULL); - setObject = true; - } - width = 0; - break; - default: - LOGE("Bad annotation element value byte 0x%02x (0x%02x)\n", - valueType, valueType & kDexAnnotationValueTypeMask); - assert(false); - return false; - } - - ptr += width; - - *pPtr = ptr; - if (setObject) - pValue->value.l = elemObj; - return true; -} - - -/* - * For most object types, we have nothing to do here, and we just return - * "valueObj". - * - * For an array annotation, the type of the extracted object will always - * be java.lang.Object[], but we want it to match the type that the - * annotation member is expected to return. In theory we can just stomp - * the object's class to have the correct type, but this strikes me as a - * risky proposition (at the very least we would need to call instanceof() - * on every element). - * - * We allocate a second array with the correct type, then copy the data - * over. This releases the tracked allocation on "valueObj" and returns - * a new, tracked object. - * - * On failure, this releases the tracking on "valueObj" and returns NULL - * (allowing the call to say "foo = convertReturnType(foo, ..)"). - */ -static Object* convertReturnType(Object* valueObj, ClassObject* methodReturn) -{ - if (valueObj == NULL || - !dvmIsArray((ArrayObject*)valueObj) || !dvmIsArrayClass(methodReturn)) - { - return valueObj; - } - - Thread* self = dvmThreadSelf(); - ClassObject* srcElemClass; - ClassObject* dstElemClass; - - /* - * Strip off one '[' to get element class. Note this is not the - * same as clazz->elementClass. - */ - srcElemClass = dvmFindClass(valueObj->clazz->descriptor+1, - valueObj->clazz->classLoader); - dstElemClass = dvmFindClass(methodReturn->descriptor+1, - methodReturn->classLoader); - if (srcElemClass->primitiveType != PRIM_NOT || - dstElemClass->primitiveType != PRIM_NOT) - { - LOGE("ERROR: array of primitives not expected here\n"); - dvmAbort(); - } - LOGV("HEY: converting valueObj from [%s to [%s\n", - srcElemClass->descriptor, dstElemClass->descriptor); - - ArrayObject* srcArray = (ArrayObject*) valueObj; - u4 length = srcArray->length; - ArrayObject* newArray; - - newArray = dvmAllocArrayByClass(methodReturn, length, ALLOC_DEFAULT); - if (newArray == NULL) { - LOGE("Failed creating duplicate annotation class (%s %d)\n", - methodReturn->descriptor, length); - goto bail; - } - - if (!dvmCopyObjectArray(newArray, srcArray, dstElemClass)) { - LOGE("Annotation array copy failed\n"); - dvmReleaseTrackedAlloc((Object*)newArray, self); - newArray = NULL; - goto bail; - } - -bail: - /* replace old, return new */ - dvmReleaseTrackedAlloc(valueObj, self); - return (Object*) newArray; -} - -/* - * Create a new AnnotationMember. - * - * "clazz" is the class on which the annotations are defined. "pPtr" - * points to a pointer into the annotation data. "annoClass" is the - * annotation's class. - * - * We extract the annotation's value, create a new AnnotationMember object, - * and construct it. - * - * Returns NULL on failure; an exception may or may not be raised. - */ -static Object* createAnnotationMember(const ClassObject* clazz, - const ClassObject* annoClass, const u1** pPtr) -{ - Thread* self = dvmThreadSelf(); - const DexFile* pDexFile = clazz->pDvmDex->pDexFile; - StringObject* nameObj = NULL; - Object* valueObj = NULL; - Object* newMember = NULL; - Object* methodObj = NULL; - ClassObject* methodReturn = NULL; - u4 elementNameIdx; - const char* name; - AnnotationValue avalue; - JValue result; - bool failed = true; - - elementNameIdx = readUleb128(pPtr); - - if (!processAnnotationValue(clazz, pPtr, &avalue, kAllObjects)) { - LOGW("Failed processing annotation value\n"); - goto bail; - } - valueObj = avalue.value.l; - - /* new member to hold the element */ - newMember = - dvmAllocObject(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember, - ALLOC_DEFAULT); - name = dexStringById(pDexFile, elementNameIdx); - nameObj = dvmCreateStringFromCstr(name, ALLOC_DEFAULT); - - /* find the method in the annotation class, given only the name */ - if (name != NULL) { - Method* annoMeth = dvmFindVirtualMethodByName(annoClass, name); - if (annoMeth == NULL) { - LOGW("WARNING: could not find annotation member %s in %s\n", - name, annoClass->descriptor); - } else { - methodObj = dvmCreateReflectMethodObject(annoMeth); - methodReturn = dvmGetBoxedReturnType(annoMeth); - } - } - if (newMember == NULL || nameObj == NULL || methodObj == NULL || - methodReturn == NULL) - { - LOGE("Failed creating annotation element (m=%p n=%p a=%p r=%p)\n", - newMember, nameObj, methodObj, methodReturn); - goto bail; - } - - /* convert the return type, if necessary */ - valueObj = convertReturnType(valueObj, methodReturn); - if (valueObj == NULL) - goto bail; - - /* call 4-argument constructor */ - dvmCallMethod(self, gDvm.methOrgApacheHarmonyLangAnnotationAnnotationMember_init, - newMember, &result, nameObj, valueObj, methodReturn, methodObj); - if (dvmCheckException(self)) { - LOGD("Failed constructing annotation element\n"); - goto bail; - } - - failed = false; - -bail: - /* release tracked allocations */ - dvmReleaseTrackedAlloc(newMember, self); - dvmReleaseTrackedAlloc((Object*)nameObj, self); - dvmReleaseTrackedAlloc(valueObj, self); - dvmReleaseTrackedAlloc(methodObj, self); - if (failed) - return NULL; - else - return newMember; -} - -/* - * Create a new Annotation object from what we find in the annotation item. - * - * "clazz" is the class on which the annotations are defined. "pPtr" - * points to a pointer into the annotation data. - * - * We use the AnnotationFactory class to create the annotation for us. The - * method we call is: - * - * public static Annotation createAnnotation( - * Class<? extends Annotation> annotationType, - * AnnotationMember[] elements) - * - * Returns a new Annotation, which will NOT be in the local ref table and - * not referenced elsewhere, so store it away soon. On failure, returns NULL - * with an exception raised. - */ -static Object* processEncodedAnnotation(const ClassObject* clazz, - const u1** pPtr) -{ - Thread* self = dvmThreadSelf(); - const DexFile* pDexFile = clazz->pDvmDex->pDexFile; - Object* newAnno = NULL; - ArrayObject* elementArray = NULL; - const ClassObject* annoClass; - const u1* ptr; - u4 typeIdx, size; - - ptr = *pPtr; - typeIdx = readUleb128(&ptr); - size = readUleb128(&ptr); - - LOGVV("----- processEnc ptr=%p type=%d size=%d\n", ptr, typeIdx, size); - - annoClass = dvmDexGetResolvedClass(clazz->pDvmDex, typeIdx); - if (annoClass == NULL) { - annoClass = dvmResolveClass(clazz, typeIdx, true); - if (annoClass == NULL) { - LOGE("Unable to resolve %s annotation class %d\n", - clazz->descriptor, typeIdx); - assert(dvmCheckException(self)); - return NULL; - } - } - - LOGV("----- processEnc ptr=%p [0x%06x] typeIdx=%d size=%d class=%s\n", - *pPtr, *pPtr - (u1*) clazz->pDvmDex->pDexFile->baseAddr, - typeIdx, size, annoClass->descriptor); - - /* - * Elements are parsed out and stored in an array. The Harmony - * constructor wants an array with just the declared elements -- - * default values get merged in later. - */ - JValue result; - Object** pElement = NULL; - - if (size > 0) { - elementArray = dvmAllocArrayByClass( - gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMemberArray, - size, ALLOC_DEFAULT); - if (elementArray == NULL) { - LOGE("failed to allocate annotation member array (%d elements)\n", - size); - goto bail; - } - pElement = (Object**) elementArray->contents; - } - - /* - * "ptr" points to a byte stream with "size" occurrences of - * annotation_element. - */ - while (size--) { - Object* newMember = createAnnotationMember(clazz, annoClass, &ptr); - if (newMember == NULL) - goto bail; - - /* add it to the array */ - *pElement++ = newMember; - } - - dvmCallMethod(self, - gDvm.methOrgApacheHarmonyLangAnnotationAnnotationFactory_createAnnotation, - NULL, &result, annoClass, elementArray); - if (dvmCheckException(self)) { - LOGD("Failed creating an annotation\n"); - //dvmLogExceptionStackTrace(); - goto bail; - } - - newAnno = result.l; - -bail: - dvmReleaseTrackedAlloc((Object*) elementArray, NULL); - *pPtr = ptr; - if (newAnno == NULL && !dvmCheckException(self)) { - /* make sure an exception is raised */ - dvmThrowException("Ljava/lang/RuntimeException;", - "failure in processEncodedAnnotation"); - } - return newAnno; -} - -/* - * Run through an annotation set and convert each entry into an Annotation - * object. - * - * Returns an array of Annotation objects, or NULL with an exception raised - * on alloc failure. - */ -static ArrayObject* processAnnotationSet(const ClassObject* clazz, - const DexAnnotationSetItem* pAnnoSet, int visibility) -{ - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const DexAnnotationItem* pAnnoItem; - ArrayObject* annoArray; - Object** pContents; - int i, count; - - /* we need these later; make sure they're initialized */ - if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory)) - dvmInitClass(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationFactory); - if (!dvmIsClassInitialized(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember)) - dvmInitClass(gDvm.classOrgApacheHarmonyLangAnnotationAnnotationMember); - - /* count up the number of visible elements */ - for (i = count = 0; i < (int) pAnnoSet->size; i++) { - pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i); - if (pAnnoItem->visibility == visibility) - count++; - } - - annoArray =dvmAllocArrayByClass(gDvm.classJavaLangAnnotationAnnotationArray, - count, ALLOC_DEFAULT); - if (annoArray == NULL) - return NULL; - pContents = (Object**) annoArray->contents; - - /* - * Generate Annotation objects. We must put them into the array - * immediately (or add them to the tracked ref table). - */ - for (i = 0; i < (int) pAnnoSet->size; i++) { - pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i); - if (pAnnoItem->visibility != visibility) - continue; - const u1* ptr = pAnnoItem->annotation; - *pContents = processEncodedAnnotation(clazz, &ptr); - if (*pContents == NULL) { - dvmReleaseTrackedAlloc((Object*) annoArray, NULL); - return NULL; - } - pContents++; - } - - return annoArray; -} - - -/* - * =========================================================================== - * Skipping and scanning - * =========================================================================== - */ - -/* - * Skip past an annotation value. - * - * "clazz" is the class on which the annotations are defined. - * - * Returns "true" on success, "false" on parsing failure. - */ -static bool skipAnnotationValue(const ClassObject* clazz, const u1** pPtr) -{ - const u1* ptr = *pPtr; - u1 valueType, valueArg; - int width; - - valueType = *ptr++; - valueArg = valueType >> kDexAnnotationValueArgShift; - width = valueArg + 1; /* assume */ - - LOGV("----- type is 0x%02x %d, ptr=%p [0x%06x]\n", - valueType & kDexAnnotationValueTypeMask, valueArg, ptr-1, - (ptr-1) - (u1*)clazz->pDvmDex->pDexFile->baseAddr); - - switch (valueType & kDexAnnotationValueTypeMask) { - case kDexAnnotationByte: break; - case kDexAnnotationShort: break; - case kDexAnnotationChar: break; - case kDexAnnotationInt: break; - case kDexAnnotationLong: break; - case kDexAnnotationFloat: break; - case kDexAnnotationDouble: break; - case kDexAnnotationString: break; - case kDexAnnotationType: break; - case kDexAnnotationMethod: break; - case kDexAnnotationField: break; - case kDexAnnotationEnum: break; - - case kDexAnnotationArray: - /* encoded_array format */ - { - u4 size = readUleb128(&ptr); - while (size--) { - if (!skipAnnotationValue(clazz, &ptr)) - return false; - } - } - width = 0; - break; - case kDexAnnotationAnnotation: - /* encoded_annotation format */ - if (!skipEncodedAnnotation(clazz, &ptr)) - return false; - width = 0; - break; - case kDexAnnotationBoolean: - case kDexAnnotationNull: - width = 0; - break; - default: - LOGE("Bad annotation element value byte 0x%02x\n", valueType); - assert(false); - return false; - } - - ptr += width; - - *pPtr = ptr; - return true; -} - -/* - * Skip past an encoded annotation. Mainly useful for annotations embedded - * in other annotations. - */ -static bool skipEncodedAnnotation(const ClassObject* clazz, const u1** pPtr) -{ - const DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const u1* ptr; - u4 size; - - ptr = *pPtr; - (void) readUleb128(&ptr); - size = readUleb128(&ptr); - - /* - * "ptr" points to a byte stream with "size" occurrences of - * annotation_element. - */ - while (size--) { - (void) readUleb128(&ptr); - - if (!skipAnnotationValue(clazz, &ptr)) - return false; - } - - *pPtr = ptr; - return true; -} - - -/* - * Compare the name of the class in the DEX file to the supplied descriptor. - * Return value is equivalent to strcmp. - */ -static int compareClassDescriptor(DexFile* pDexFile, u4 typeIdx, - const char* descriptor) -{ - const char* str = dexStringByTypeIdx(pDexFile, typeIdx); - - return strcmp(str, descriptor); -} - -/* - * Search through the annotation set for an annotation with a matching - * descriptor. - * - * Comparing the string descriptor is slower than comparing an integer class - * index. If annotation lists are expected to be long, we could look up - * the class' index by name from the DEX file, rather than doing a class - * lookup and string compare on each entry. (Note the index will be - * different for each DEX file, so we can't cache annotation class indices - * globally.) - */ -static const DexAnnotationItem* searchAnnotationSet(const ClassObject* clazz, - const DexAnnotationSetItem* pAnnoSet, const char* descriptor, - int visibility) -{ - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const DexAnnotationItem* result = NULL; - u4 typeIdx; - int i; - - //printf("##### searchAnnotationSet %s %d\n", descriptor, visibility); - - for (i = 0; i < (int) pAnnoSet->size; i++) { - const DexAnnotationItem* pAnnoItem; - - pAnnoItem = dexGetAnnotationItem(pDexFile, pAnnoSet, i); - if (pAnnoItem->visibility != visibility) - continue; - const u1* ptr = pAnnoItem->annotation; - typeIdx = readUleb128(&ptr); - - if (compareClassDescriptor(pDexFile, typeIdx, descriptor) == 0) { - //printf("##### match on %x/%p at %d\n", typeIdx, pDexFile, i); - result = pAnnoItem; - break; - } - } - - return result; -} - -/* - * Find an annotation value in the annotation_item whose name matches "name". - * A pointer to the annotation_value is returned, or NULL if it's not found. - */ -static const u1* searchEncodedAnnotation(const ClassObject* clazz, - const u1* ptr, const char* name) -{ - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - u4 typeIdx, size; - - typeIdx = readUleb128(&ptr); - size = readUleb128(&ptr); - //printf("##### searching ptr=%p type=%u size=%u\n", ptr, typeIdx, size); - - while (size--) { - u4 elementNameIdx; - const char* elemName; - - elementNameIdx = readUleb128(&ptr); - elemName = dexStringById(pDexFile, elementNameIdx); - if (strcmp(name, elemName) == 0) { - //printf("##### item match on %s\n", name); - return ptr; /* points to start of value */ - } - - skipAnnotationValue(clazz, &ptr); - } - - //printf("##### no item match on %s\n", name); - return NULL; -} - -#define GAV_FAILED ((Object*) 0x10000001) - -/* - * Extract an encoded annotation value from the field specified by "annoName". - * - * "expectedType" is an annotation value type, e.g. kDexAnnotationString. - * "debugAnnoName" is only used in debug messages. - * - * Returns GAV_FAILED on failure. If an allocation failed, an exception - * will be raised. - */ -static Object* getAnnotationValue(const ClassObject* clazz, - const DexAnnotationItem* pAnnoItem, const char* annoName, - int expectedType, const char* debugAnnoName) -{ - const u1* ptr; - Object* obj; - AnnotationValue avalue; - - /* find the annotation */ - ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, annoName); - if (ptr == NULL) { - LOGW("%s annotation lacks '%s' member\n", debugAnnoName, annoName); - return GAV_FAILED; - } - - if (!processAnnotationValue(clazz, &ptr, &avalue, kAllObjects)) - return GAV_FAILED; - - /* make sure it has the expected format */ - if (avalue.type != expectedType) { - LOGW("%s %s has wrong type (0x%02x, expected 0x%02x)\n", - debugAnnoName, annoName, avalue.type, expectedType); - return GAV_FAILED; - } - - return avalue.value.l; -} - - -/* - * Find the Signature attribute and extract its value. (Signatures can - * be found in annotations on classes, constructors, methods, and fields.) - * - * Caller must call dvmReleaseTrackedAlloc(). - * - * Returns NULL if not found. On memory alloc failure, returns NULL with an - * exception raised. - */ -static ArrayObject* getSignatureValue(const ClassObject* clazz, - const DexAnnotationSetItem* pAnnoSet) -{ - const DexAnnotationItem* pAnnoItem; - Object* obj; - - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrSignature, - kDexVisibilitySystem); - if (pAnnoItem == NULL) - return NULL; - - /* - * The Signature annotation has one member, "String value". - */ - obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationArray, - "Signature"); - if (obj == GAV_FAILED) - return NULL; - assert(obj->clazz == gDvm.classJavaLangObjectArray); - - return (ArrayObject*)obj; -} - - -/* - * =========================================================================== - * Class - * =========================================================================== - */ - -/* - * Find the DexAnnotationSetItem for this class. - */ -static const DexAnnotationSetItem* findAnnotationSetForClass( - const ClassObject* clazz) -{ - DexFile* pDexFile; - const DexAnnotationsDirectoryItem* pAnnoDir; - - if (clazz->pDvmDex == NULL) /* generated class (Proxy, array) */ - return NULL; - - pDexFile = clazz->pDvmDex->pDexFile; - pAnnoDir = getAnnoDirectory(pDexFile, clazz); - if (pAnnoDir != NULL) - return dexGetClassAnnotationSet(pDexFile, pAnnoDir); - else - return NULL; -} - -/* - * Return an array of Annotation objects for the class. Returns an empty - * array if there are no annotations. - * - * Caller must call dvmReleaseTrackedAlloc(). - * - * On allocation failure, this returns NULL with an exception raised. - */ -ArrayObject* dvmGetClassAnnotations(const ClassObject* clazz) -{ - ArrayObject* annoArray; - const DexAnnotationSetItem* pAnnoSet = NULL; - - pAnnoSet = findAnnotationSetForClass(clazz); - if (pAnnoSet == NULL) { - /* no annotations for anything in class, or no class annotations */ - annoArray = emptyAnnoArray(); - } else { - annoArray = processAnnotationSet(clazz, pAnnoSet, - kDexVisibilityRuntime); - } - - return annoArray; -} - -/* - * Retrieve the Signature annotation, if any. Returns NULL if no signature - * exists. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -ArrayObject* dvmGetClassSignatureAnnotation(const ClassObject* clazz) -{ - ArrayObject* signature = NULL; - const DexAnnotationSetItem* pAnnoSet; - - pAnnoSet = findAnnotationSetForClass(clazz); - if (pAnnoSet != NULL) - signature = getSignatureValue(clazz, pAnnoSet); - - return signature; -} - -/* - * Get the EnclosingMethod attribute from an annotation. Returns a Method - * object, or NULL. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -Object* dvmGetEnclosingMethod(const ClassObject* clazz) -{ - const DexAnnotationItem* pAnnoItem; - const DexAnnotationSetItem* pAnnoSet; - Object* obj; - - pAnnoSet = findAnnotationSetForClass(clazz); - if (pAnnoSet == NULL) - return NULL; - - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingMethod, - kDexVisibilitySystem); - if (pAnnoItem == NULL) - return NULL; - - /* - * The EnclosingMethod annotation has one member, "Method value". - */ - obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationMethod, - "EnclosingMethod"); - if (obj == GAV_FAILED) - return NULL; - assert(obj->clazz == gDvm.classJavaLangReflectConstructor || - obj->clazz == gDvm.classJavaLangReflectMethod); - - return obj; -} - -/* - * Find a class' enclosing class. We return what we find in the - * EnclosingClass attribute. - * - * Returns a Class object, or NULL. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -ClassObject* dvmGetDeclaringClass(const ClassObject* clazz) -{ - const DexAnnotationItem* pAnnoItem; - const DexAnnotationSetItem* pAnnoSet; - Object* obj; - - pAnnoSet = findAnnotationSetForClass(clazz); - if (pAnnoSet == NULL) - return NULL; - - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingClass, - kDexVisibilitySystem); - if (pAnnoItem == NULL) - return NULL; - - /* - * The EnclosingClass annotation has one member, "Class value". - */ - obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationType, - "EnclosingClass"); - if (obj == GAV_FAILED) - return NULL; - - assert(obj->clazz == gDvm.classJavaLangClass); - return (ClassObject*)obj; -} - -/* - * Find a class' enclosing class. We first search for an EnclosingClass - * attribute, and if that's not found we look for an EnclosingMethod. - * - * Returns a Class object, or NULL. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -ClassObject* dvmGetEnclosingClass(const ClassObject* clazz) -{ - const DexAnnotationItem* pAnnoItem; - const DexAnnotationSetItem* pAnnoSet; - Object* obj; - - pAnnoSet = findAnnotationSetForClass(clazz); - if (pAnnoSet == NULL) - return NULL; - - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingClass, - kDexVisibilitySystem); - if (pAnnoItem != NULL) { - /* - * The EnclosingClass annotation has one member, "Class value". - */ - obj = getAnnotationValue(clazz, pAnnoItem, "value", kDexAnnotationType, - "EnclosingClass"); - if (obj != GAV_FAILED) { - assert(obj->clazz == gDvm.classJavaLangClass); - return (ClassObject*)obj; - } - } - - /* - * That didn't work. Look for an EnclosingMethod. - * - * We could create a java.lang.reflect.Method object and extract the - * declaringClass from it, but that's more work than we want to do. - * Instead, we find the "value" item and parse the index out ourselves. - */ - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrEnclosingMethod, - kDexVisibilitySystem); - if (pAnnoItem == NULL) - return NULL; - - /* find the value member */ - const u1* ptr; - ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "value"); - if (ptr == NULL) { - LOGW("EnclosingMethod annotation lacks 'value' member\n"); - return NULL; - } - - /* parse it, verify the type */ - AnnotationValue avalue; - if (!processAnnotationValue(clazz, &ptr, &avalue, kAllRaw)) { - LOGW("EnclosingMethod parse failed\n"); - return NULL; - } - if (avalue.type != kDexAnnotationMethod) { - LOGW("EnclosingMethod value has wrong type (0x%02x, expected 0x%02x)\n", - avalue.type, kDexAnnotationMethod); - return NULL; - } - - /* pull out the method index and resolve the method */ - Method* meth = resolveAmbiguousMethod(clazz, avalue.value.i); - if (meth == NULL) - return NULL; - - ClassObject* methClazz = meth->clazz; - dvmAddTrackedAlloc((Object*) methClazz, NULL); // balance the Release - return methClazz; -} - -/* - * Get the EnclosingClass attribute from an annotation. If found, returns - * "true". A String with the original name of the class and the original - * access flags are returned through the arguments. (The name will be NULL - * for an anonymous inner class.) - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -bool dvmGetInnerClass(const ClassObject* clazz, StringObject** pName, - int* pAccessFlags) -{ - const DexAnnotationItem* pAnnoItem; - const DexAnnotationSetItem* pAnnoSet; - - pAnnoSet = findAnnotationSetForClass(clazz); - if (pAnnoSet == NULL) - return false; - - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrInnerClass, - kDexVisibilitySystem); - if (pAnnoItem == NULL) - return false; - - /* - * The InnerClass annotation has two members, "String name" and - * "int accessFlags". We don't want to get the access flags as an - * Integer, so we process that as a simple value. - */ - const u1* ptr; - ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "name"); - if (ptr == NULL) { - LOGW("InnerClass annotation lacks 'name' member\n"); - return false; - } - - /* parse it into an Object */ - AnnotationValue avalue; - if (!processAnnotationValue(clazz, &ptr, &avalue, kAllObjects)) { - LOGD("processAnnotationValue failed on InnerClass member 'name'\n"); - return false; - } - - /* make sure it has the expected format */ - if (avalue.type != kDexAnnotationNull && - avalue.type != kDexAnnotationString) - { - LOGW("InnerClass name has bad type (0x%02x, expected STRING or NULL)\n", - avalue.type); - return false; - } - - *pName = (StringObject*) avalue.value.l; - assert(*pName == NULL || (*pName)->obj.clazz == gDvm.classJavaLangString); - - ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "accessFlags"); - if (ptr == NULL) { - LOGW("InnerClass annotation lacks 'accessFlags' member\n"); - return false; - } - - /* parse it, verify the type */ - if (!processAnnotationValue(clazz, &ptr, &avalue, kAllRaw)) { - LOGW("InnerClass accessFlags parse failed\n"); - return false; - } - if (avalue.type != kDexAnnotationInt) { - LOGW("InnerClass value has wrong type (0x%02x, expected 0x%02x)\n", - avalue.type, kDexAnnotationInt); - return false; - } - - *pAccessFlags = avalue.value.i; - - return true; -} - -/* - * Extract an array of Class objects from the MemberClasses annotation - * for this class. - * - * Caller must call dvmReleaseTrackedAlloc(). - * - * Returns NULL if we don't find any member classes. - */ -ArrayObject* dvmGetDeclaredClasses(const ClassObject* clazz) -{ - const DexAnnotationSetItem* pAnnoSet; - const DexAnnotationItem* pAnnoItem; - Object* obj; - - pAnnoSet = findAnnotationSetForClass(clazz); - if (pAnnoSet == NULL) - return NULL; - - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrMemberClasses, - kDexVisibilitySystem); - if (pAnnoItem == NULL) - return NULL; - - /* - * The MemberClasses annotation has one member, "Class[] value". - */ - obj = getAnnotationValue(clazz, pAnnoItem, "value", - kDexAnnotationArray, "MemberClasses"); - if (obj == GAV_FAILED) - return NULL; - assert(dvmIsArray((ArrayObject*)obj)); - obj = convertReturnType(obj, gDvm.classJavaLangClassArray); - return (ArrayObject*)obj; -} - - -/* - * =========================================================================== - * Method (and Constructor) - * =========================================================================== - */ - -/* - * Compare the attributes (class name, method name, method signature) of - * the specified method to "method". - */ -static int compareMethodStr(DexFile* pDexFile, u4 methodIdx, - const Method* method) -{ - const DexMethodId* pMethodId = dexGetMethodId(pDexFile, methodIdx); - const char* str = dexStringByTypeIdx(pDexFile, pMethodId->classIdx); - int result = strcmp(str, method->clazz->descriptor); - - if (result == 0) { - str = dexStringById(pDexFile, pMethodId->nameIdx); - result = strcmp(str, method->name); - if (result == 0) { - DexProto proto; - dexProtoSetFromMethodId(&proto, pDexFile, pMethodId); - result = dexProtoCompare(&proto, &method->prototype); - } - } - - return result; -} - -/* - * Given a method, determine the method's index. - * - * We could simply store this in the Method*, but that would cost 4 bytes - * per method. Instead we plow through the DEX data. - * - * We have two choices: look through the class method data, or look through - * the global method_ids table. The former is awkward because the method - * could have been defined in a superclass or interface. The latter works - * out reasonably well because it's in sorted order, though we're still left - * doing a fair number of string comparisons. - */ -static u4 getMethodIdx(const Method* method) -{ - DexFile* pDexFile = method->clazz->pDvmDex->pDexFile; - u4 hi = pDexFile->pHeader->methodIdsSize -1; - u4 lo = 0; - u4 cur; - - while (hi >= lo) { - int cmp; - cur = (lo + hi) / 2; - - cmp = compareMethodStr(pDexFile, cur, method); - if (cmp < 0) { - lo = cur + 1; - } else if (cmp > 0) { - hi = cur - 1; - } else { - break; - } - } - - if (hi < lo) { - /* this should be impossible -- the method came out of this DEX */ - char* desc = dexProtoCopyMethodDescriptor(&method->prototype); - LOGE("Unable to find method %s.%s %s in DEX file!\n", - method->clazz->descriptor, method->name, desc); - free(desc); - dvmAbort(); - } - - return cur; -} - -/* - * Find the DexAnnotationSetItem for this method. - * - * Returns NULL if none found. - */ -static const DexAnnotationSetItem* findAnnotationSetForMethod( - const Method* method) -{ - ClassObject* clazz = method->clazz; - DexFile* pDexFile; - const DexAnnotationsDirectoryItem* pAnnoDir; - const DexMethodAnnotationsItem* pMethodList; - const DexAnnotationSetItem* pAnnoSet = NULL; - - if (clazz->pDvmDex == NULL) /* generated class (Proxy, array) */ - return NULL; - pDexFile = clazz->pDvmDex->pDexFile; - - pAnnoDir = getAnnoDirectory(pDexFile, clazz); - if (pAnnoDir != NULL) { - pMethodList = dexGetMethodAnnotations(pDexFile, pAnnoDir); - if (pMethodList != NULL) { - /* - * Run through the list and find a matching method. We compare the - * method ref indices in the annotation list with the method's DEX - * method_idx value. - * - * TODO: use a binary search for long lists - * - * Alternate approach: for each entry in the annotations list, - * find the method definition in the DEX file and perform string - * comparisons on class name, method name, and signature. - */ - u4 methodIdx = getMethodIdx(method); - u4 count = dexGetMethodAnnotationsSize(pDexFile, pAnnoDir); - u4 idx; - - for (idx = 0; idx < count; idx++) { - if (pMethodList[idx].methodIdx == methodIdx) { - /* found! */ - pAnnoSet = dexGetMethodAnnotationSetItem(pDexFile, - &pMethodList[idx]); - break; - } - } - } - } - - return pAnnoSet; -} - -/* - * Return an array of Annotation objects for the method. Returns an empty - * array if there are no annotations. - * - * Caller must call dvmReleaseTrackedAlloc(). - * - * On allocation failure, this returns NULL with an exception raised. - */ -ArrayObject* dvmGetMethodAnnotations(const Method* method) -{ - ClassObject* clazz = method->clazz; - const DexAnnotationSetItem* pAnnoSet; - ArrayObject* annoArray = NULL; - - pAnnoSet = findAnnotationSetForMethod(method); - if (pAnnoSet == NULL) { - /* no matching annotations found */ - annoArray = emptyAnnoArray(); - } else { - annoArray = processAnnotationSet(clazz, pAnnoSet,kDexVisibilityRuntime); - } - - return annoArray; -} - -/* - * Retrieve the Signature annotation, if any. Returns NULL if no signature - * exists. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -ArrayObject* dvmGetMethodSignatureAnnotation(const Method* method) -{ - ClassObject* clazz = method->clazz; - const DexAnnotationSetItem* pAnnoSet; - ArrayObject* signature = NULL; - - pAnnoSet = findAnnotationSetForMethod(method); - if (pAnnoSet != NULL) - signature = getSignatureValue(clazz, pAnnoSet); - - return signature; -} - -/* - * Extract an array of exception classes from the "system" annotation list - * for this method. - * - * Caller must call dvmReleaseTrackedAlloc(). - * - * Returns NULL if we don't find any exceptions for this method. - */ -ArrayObject* dvmGetMethodThrows(const Method* method) -{ - ClassObject* clazz = method->clazz; - const DexAnnotationSetItem* pAnnoSet; - const DexAnnotationItem* pAnnoItem; - - /* find the set for this method */ - pAnnoSet = findAnnotationSetForMethod(method); - if (pAnnoSet == NULL) - return NULL; /* nothing for this method */ - - /* find the "Throws" annotation, if any */ - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrThrows, - kDexVisibilitySystem); - if (pAnnoItem == NULL) - return NULL; /* no Throws */ - - /* - * The Throws annotation has one member, "Class[] value". - */ - Object* obj = getAnnotationValue(clazz, pAnnoItem, "value", - kDexAnnotationArray, "Throws"); - if (obj == GAV_FAILED) - return NULL; - assert(dvmIsArray((ArrayObject*)obj)); - obj = convertReturnType(obj, gDvm.classJavaLangClassArray); - return (ArrayObject*)obj; -} - -/* - * Given an Annotation's method, find the default value, if any. - * - * If this is a CLASS annotation, and we can't find a match for the - * default class value, we need to throw a TypeNotPresentException. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -Object* dvmGetAnnotationDefaultValue(const Method* method) -{ - const ClassObject* clazz = method->clazz; - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const DexAnnotationsDirectoryItem* pAnnoDir; - const DexAnnotationSetItem* pAnnoSet = NULL; - - /* - * The method's declaring class (the annotation) will have an - * AnnotationDefault "system" annotation associated with it if any - * of its methods have default values. Start by finding the - * DexAnnotationItem associated with the class. - */ - pAnnoDir = getAnnoDirectory(pDexFile, clazz); - if (pAnnoDir != NULL) - pAnnoSet = dexGetClassAnnotationSet(pDexFile, pAnnoDir); - if (pAnnoSet == NULL) { - /* no annotations for anything in class, or no class annotations */ - return NULL; - } - - /* find the "AnnotationDefault" annotation, if any */ - const DexAnnotationItem* pAnnoItem; - pAnnoItem = searchAnnotationSet(clazz, pAnnoSet, kDescrAnnotationDefault, - kDexVisibilitySystem); - if (pAnnoItem == NULL) { - /* no default values for any member in this annotation */ - //printf("##### no default annotations for %s.%s\n", - // method->clazz->descriptor, method->name); - return NULL; - } - - /* - * The AnnotationDefault annotation has one member, "Annotation value". - * We need to pull that out. - */ - const u1* ptr; - ptr = searchEncodedAnnotation(clazz, pAnnoItem->annotation, "value"); - if (ptr == NULL) { - LOGW("AnnotationDefault annotation lacks 'value'\n"); - return NULL; - } - if ((*ptr & kDexAnnotationValueTypeMask) != kDexAnnotationAnnotation) { - LOGW("AnnotationDefault value has wrong type (0x%02x)\n", - *ptr & kDexAnnotationValueTypeMask); - return NULL; - } - - /* - * The value_type byte for VALUE_ANNOTATION is followed by - * encoded_annotation data. We want to scan through it to find an - * entry whose name matches our method name. - */ - ptr++; - ptr = searchEncodedAnnotation(clazz, ptr, method->name); - if (ptr == NULL) - return NULL; /* no default annotation for this method */ - - /* got it, pull it out */ - AnnotationValue avalue; - if (!processAnnotationValue(clazz, &ptr, &avalue, kAllObjects)) { - LOGD("processAnnotationValue failed on default for '%s'\n", - method->name); - return NULL; - } - - /* convert the return type, if necessary */ - ClassObject* methodReturn = dvmGetBoxedReturnType(method); - Object* obj = avalue.value.l; - obj = convertReturnType(obj, methodReturn); - - return obj; -} - - -/* - * =========================================================================== - * Field - * =========================================================================== - */ - -/* - * Compare the attributes (class name, field name, field signature) of - * the specified field to "field". - */ -static int compareFieldStr(DexFile* pDexFile, u4 idx, const Field* field) -{ - const DexFieldId* pFieldId = dexGetFieldId(pDexFile, idx); - const char* str = dexStringByTypeIdx(pDexFile, pFieldId->classIdx); - int result = strcmp(str, field->clazz->descriptor); - - if (result == 0) { - str = dexStringById(pDexFile, pFieldId->nameIdx); - result = strcmp(str, field->name); - if (result == 0) { - str = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx); - result = strcmp(str, field->signature); - } - } - - return result; -} - -/* - * Given a field, determine the field's index. - * - * This has the same tradeoffs as getMethodIdx. - */ -static u4 getFieldIdx(const Field* field) -{ - DexFile* pDexFile = field->clazz->pDvmDex->pDexFile; - u4 hi = pDexFile->pHeader->fieldIdsSize -1; - u4 lo = 0; - u4 cur; - - while (hi >= lo) { - int cmp; - cur = (lo + hi) / 2; - - cmp = compareFieldStr(pDexFile, cur, field); - if (cmp < 0) { - lo = cur + 1; - } else if (cmp > 0) { - hi = cur - 1; - } else { - break; - } - } - - if (hi < lo) { - /* this should be impossible -- the field came out of this DEX */ - LOGE("Unable to find field %s.%s %s in DEX file!\n", - field->clazz->descriptor, field->name, field->signature); - dvmAbort(); - } - - return cur; -} - -/* - * Find the DexAnnotationSetItem for this field. - * - * Returns NULL if none found. - */ -static const DexAnnotationSetItem* findAnnotationSetForField(const Field* field) -{ - ClassObject* clazz = field->clazz; - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const DexAnnotationsDirectoryItem* pAnnoDir; - const DexFieldAnnotationsItem* pFieldList; - const DexAnnotationSetItem* pAnnoSet = NULL; - - pAnnoDir = getAnnoDirectory(pDexFile, clazz); - if (pAnnoDir == NULL) - return NULL; - - pFieldList = dexGetFieldAnnotations(pDexFile, pAnnoDir); - if (pFieldList == NULL) - return NULL; - - /* - * Run through the list and find a matching field. We compare the - * field ref indices in the annotation list with the field's DEX - * field_idx value. - * - * TODO: use a binary search for long lists - * - * Alternate approach: for each entry in the annotations list, - * find the field definition in the DEX file and perform string - * comparisons on class name, field name, and signature. - */ - u4 fieldIdx = getFieldIdx(field); - u4 count = dexGetFieldAnnotationsSize(pDexFile, pAnnoDir); - u4 idx; - - for (idx = 0; idx < count; idx++) { - if (pFieldList[idx].fieldIdx == fieldIdx) { - /* found! */ - return dexGetFieldAnnotationSetItem(pDexFile, &pFieldList[idx]); - } - } - - return NULL; -} - -/* - * Return an array of Annotation objects for the field. Returns an empty - * array if there are no annotations. - * - * Caller must call dvmReleaseTrackedAlloc(). - * - * On allocation failure, this returns NULL with an exception raised. - */ -ArrayObject* dvmGetFieldAnnotations(const Field* field) -{ - ClassObject* clazz = field->clazz; - ArrayObject* annoArray = NULL; - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const DexAnnotationsDirectoryItem* pAnnoDir; - const DexAnnotationSetItem* pAnnoSet = NULL; - - pAnnoSet = findAnnotationSetForField(field); - if (pAnnoSet == NULL) { - /* no matching annotations found */ - annoArray = emptyAnnoArray(); - } else { - annoArray = processAnnotationSet(clazz, pAnnoSet, - kDexVisibilityRuntime); - } - - return annoArray; -} - -/* - * Retrieve the Signature annotation, if any. Returns NULL if no signature - * exists. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -ArrayObject* dvmGetFieldSignatureAnnotation(const Field* field) -{ - ClassObject* clazz = field->clazz; - const DexAnnotationSetItem* pAnnoSet; - ArrayObject* signature = NULL; - - pAnnoSet = findAnnotationSetForField(field); - if (pAnnoSet != NULL) - signature = getSignatureValue(clazz, pAnnoSet); - - return signature; -} - - -/* - * =========================================================================== - * Parameter - * =========================================================================== - */ - -/* - * We have an annotation_set_ref_list, which is essentially a list of - * entries that we pass to processAnnotationSet(). - * - * The returned object must be released with dvmReleaseTrackedAlloc. - */ -static ArrayObject* processAnnotationSetRefList(const ClassObject* clazz, - const DexAnnotationSetRefList* pAnnoSetList, u4 count) -{ - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - ArrayObject* annoArrayArray = NULL; - ArrayObject** pContents; - u4 idx; - - /* allocate an array of Annotation arrays to hold results */ - annoArrayArray = dvmAllocArrayByClass( - gDvm.classJavaLangAnnotationAnnotationArrayArray, count, ALLOC_DEFAULT); - if (annoArrayArray == NULL) { - LOGW("annotation set ref array alloc failed\n"); - goto bail; - } - - pContents = (ArrayObject**) annoArrayArray->contents; - - for (idx = 0; idx < count; idx++) { - Thread* self = dvmThreadSelf(); - const DexAnnotationSetRefItem* pItem; - const DexAnnotationSetItem* pAnnoSet; - - pItem = dexGetParameterAnnotationSetRef(pAnnoSetList, idx); - pAnnoSet = dexGetSetRefItemItem(pDexFile, pItem); - *pContents = processAnnotationSet(clazz, pAnnoSet, - kDexVisibilityRuntime); - if (*pContents == NULL) { - LOGW("processAnnotationSet failed\n"); - annoArrayArray = NULL; - goto bail; - } - dvmReleaseTrackedAlloc((Object*) *pContents, self); - pContents++; - } - -bail: - return annoArrayArray; -} - -/* - * Find the DexAnnotationSetItem for this parameter. - * - * Returns NULL if none found. - */ -static const DexParameterAnnotationsItem* findAnnotationsItemForMethod( - const Method* method) -{ - ClassObject* clazz = method->clazz; - DexFile* pDexFile; - const DexAnnotationsDirectoryItem* pAnnoDir; - const DexParameterAnnotationsItem* pParameterList; - - if (clazz->pDvmDex == NULL) /* generated class (Proxy, array) */ - return NULL; - - pDexFile = clazz->pDvmDex->pDexFile; - pAnnoDir = getAnnoDirectory(pDexFile, clazz); - if (pAnnoDir == NULL) - return NULL; - - pParameterList = dexGetParameterAnnotations(pDexFile, pAnnoDir); - if (pParameterList == NULL) - return NULL; - - /* - * Run through the list and find a matching method. We compare the - * method ref indices in the annotation list with the method's DEX - * method_idx value. - * - * TODO: use a binary search for long lists - * - * Alternate approach: for each entry in the annotations list, - * find the method definition in the DEX file and perform string - * comparisons on class name, method name, and signature. - */ - u4 methodIdx = getMethodIdx(method); - u4 count = dexGetParameterAnnotationsSize(pDexFile, pAnnoDir); - u4 idx; - - for (idx = 0; idx < count; idx++) { - if (pParameterList[idx].methodIdx == methodIdx) { - /* found! */ - return &pParameterList[idx]; - } - } - - return NULL; -} - - -/* - * Count up the number of arguments the method takes. The "this" pointer - * doesn't count. - */ -static int countMethodArguments(const Method* method) -{ - /* method->shorty[0] is the return type */ - return strlen(method->shorty + 1); -} - -/* - * Return an array of arrays of Annotation objects. The outer array has - * one entry per method parameter, the inner array has the list of annotations - * associated with that parameter. - * - * If the method has no parameters, we return an array of length zero. If - * the method has one or more parameters, we return an array whose length - * is equal to the number of parameters; if a given parameter does not have - * an annotation, the corresponding entry will be null. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -ArrayObject* dvmGetParameterAnnotations(const Method* method) -{ - ClassObject* clazz = method->clazz; - const DexParameterAnnotationsItem* pItem; - ArrayObject* annoArrayArray = NULL; - - pItem = findAnnotationsItemForMethod(method); - if (pItem != NULL) { - DexFile* pDexFile = clazz->pDvmDex->pDexFile; - const DexAnnotationSetRefList* pAnnoSetList; - u4 size; - - size = dexGetParameterAnnotationSetRefSize(pDexFile, pItem); - pAnnoSetList = dexGetParameterAnnotationSetRefList(pDexFile, pItem); - annoArrayArray = processAnnotationSetRefList(clazz, pAnnoSetList, size); - } else { - /* no matching annotations found */ - annoArrayArray = emptyAnnoArrayArray(countMethodArguments(method)); - } - - return annoArrayArray; -} - - -/* - * =========================================================================== - * DexEncodedArray interpretation - * =========================================================================== - */ - -/** - * Initializes an encoded array iterator. - * - * @param iterator iterator to initialize - * @param encodedArray encoded array to iterate over - * @param clazz class to use when resolving strings and types - */ -void dvmEncodedArrayIteratorInitialize(EncodedArrayIterator* iterator, - const DexEncodedArray* encodedArray, const ClassObject* clazz) { - iterator->encodedArray = encodedArray; - iterator->cursor = encodedArray->array; - iterator->size = readUleb128(&iterator->cursor); - iterator->elementsLeft = iterator->size; - iterator->clazz = clazz; -} - -/** - * Returns whether there are more elements to be read. - */ -bool dvmEncodedArrayIteratorHasNext(const EncodedArrayIterator* iterator) { - return (iterator->elementsLeft != 0); -} - -/** - * Returns the next decoded value from the iterator, advancing its - * cursor. This returns primitive values in their corresponding union - * slots, and returns everything else (including nulls) as object - * references in the "l" union slot. - * - * The caller must call dvmReleaseTrackedAlloc() on any returned reference. - * - * @param value pointer to store decoded value into - * @returns true if a value was decoded and the cursor advanced; false if - * the last value had already been decoded or if there was a problem decoding - */ -bool dvmEncodedArrayIteratorGetNext(EncodedArrayIterator* iterator, - AnnotationValue* value) { - bool processed; - - if (iterator->elementsLeft == 0) { - return false; - } - - processed = processAnnotationValue(iterator->clazz, &iterator->cursor, - value, kPrimitivesOrObjects); - - if (! processed) { - LOGE("Failed to process array element %d from %p", - iterator->size - iterator->elementsLeft, - iterator->encodedArray); - iterator->elementsLeft = 0; - return false; - } - - iterator->elementsLeft--; - return true; -} - diff --git a/vm/reflect/Proxy.c b/vm/reflect/Proxy.c deleted file mode 100644 index 31df708d8..000000000 --- a/vm/reflect/Proxy.c +++ /dev/null @@ -1,1097 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Implementation of java.lang.reflect.Proxy. - * - * Traditionally this is implemented entirely in interpreted code, - * generating bytecode that defines the proxy class. Dalvik doesn't - * currently support this approach, so we generate the class directly. If - * we add support for DefineClass with standard classfiles we can - * eliminate this. - */ -#include "Dalvik.h" - -#include <stdlib.h> - -// fwd -static bool returnTypesAreCompatible(Method* baseMethod, Method* subMethod); -static bool gatherMethods(ArrayObject* interfaces, Method*** pMethods,\ - ArrayObject** pThrows, int* pMethodCount); -static int copyWithoutDuplicates(Method** allMethods, int allCount, - Method** outMethods, ArrayObject* throws); -static bool createExceptionClassList(const Method* method, - PointerSet** pThrows); -static void updateExceptionClassList(const Method* method, PointerSet* throws); -static void createConstructor(ClassObject* clazz, Method* meth); -static void createHandlerMethod(ClassObject* clazz, Method* dstMeth, - const Method* srcMeth); -static void proxyConstructor(const u4* args, JValue* pResult, - const Method* method, Thread* self); -static void proxyInvoker(const u4* args, JValue* pResult, - const Method* method, Thread* self); -static bool mustWrapException(const Method* method, const Object* throwable); - -/* private static fields in the Proxy class */ -#define kThrowsField 0 - - -/* - * Perform Proxy setup. - */ -bool dvmReflectProxyStartup() -{ - /* - * Standard methods we must provide in our proxy. - */ - Method* methE; - Method* methH; - Method* methT; - Method* methF; - methE = dvmFindVirtualMethodByDescriptor(gDvm.classJavaLangObject, - "equals", "(Ljava/lang/Object;)Z"); - methH = dvmFindVirtualMethodByDescriptor(gDvm.classJavaLangObject, - "hashCode", "()I"); - methT = dvmFindVirtualMethodByDescriptor(gDvm.classJavaLangObject, - "toString", "()Ljava/lang/String;"); - methF = dvmFindVirtualMethodByDescriptor(gDvm.classJavaLangObject, - "finalize", "()V"); - if (methE == NULL || methH == NULL || methT == NULL || methF == NULL) { - LOGE("Could not find equals/hashCode/toString/finalize in Object\n"); - return false; - } - gDvm.voffJavaLangObject_equals = methE->methodIndex; - gDvm.voffJavaLangObject_hashCode = methH->methodIndex; - gDvm.voffJavaLangObject_toString = methT->methodIndex; - gDvm.voffJavaLangObject_finalize = methF->methodIndex; - - /* - * The prototype signature needs to be cloned from a method in a - * "real" DEX file. We declared this otherwise unused method just - * for this purpose. - */ - ClassObject* proxyClass; - Method* meth; - proxyClass = dvmFindSystemClassNoInit("Ljava/lang/reflect/Proxy;"); - if (proxyClass == NULL) { - LOGE("No java.lang.reflect.Proxy\n"); - return false; - } - meth = dvmFindDirectMethodByDescriptor(proxyClass, "constructorPrototype", - "(Ljava/lang/reflect/InvocationHandler;)V"); - if (meth == NULL) { - LOGE("Could not find java.lang.Proxy.constructorPrototype()\n"); - return false; - } - gDvm.methJavaLangReflectProxy_constructorPrototype = meth; - - /* - * Get the offset of the "h" field in Proxy. - */ - gDvm.offJavaLangReflectProxy_h = dvmFindFieldOffset(proxyClass, "h", - "Ljava/lang/reflect/InvocationHandler;"); - if (gDvm.offJavaLangReflectProxy_h < 0) { - LOGE("Unable to find 'h' field in java.lang.Proxy\n"); - return false; - } - - return true; -} - - -/* - * Generate a proxy class with the specified name, interfaces, and loader. - * "interfaces" is an array of class objects. - * - * The Proxy.getProxyClass() code has done the following: - * - Verified that "interfaces" contains only interfaces - * - Verified that no interface appears twice - * - Prepended the package name to the class name if one or more - * interfaces are non-public - * - Searched for an existing instance of an appropriate Proxy class - * - * On failure we leave a partially-created class object sitting around, - * but the garbage collector will take care of it. - */ -ClassObject* dvmGenerateProxyClass(StringObject* str, ArrayObject* interfaces, - Object* loader) -{ - int result = -1; - char* nameStr = NULL; - Method** methods = NULL; - ArrayObject* throws = NULL; - ClassObject* newClass = NULL; - int i; - - nameStr = dvmCreateCstrFromString(str); - if (nameStr == NULL) { - dvmThrowException("Ljava/lang/IllegalArgumentException;", - "missing name"); - goto bail; - } - - LOGV("+++ Generate proxy class '%s' %p from %d interface classes\n", - nameStr, loader, interfaces->length); - - - /* - * Characteristics of a Proxy class: - * - concrete class, public and final - * - superclass is java.lang.reflect.Proxy - * - implements all listed interfaces (req'd for instanceof) - * - has one method for each method in the interfaces (for duplicates, - * the method in the earliest interface wins) - * - has one constructor (takes an InvocationHandler arg) - * - has overrides for hashCode, equals, and toString (these come first) - * - has one field, a reference to the InvocationHandler object, inherited - * from Proxy - * - * TODO: set protection domain so it matches bootstrap classes. - * - * The idea here is to create a class object and fill in the details - * as we would in loadClassFromDex(), and then call dvmLinkClass() to do - * all the heavy lifting (notably populating the virtual and interface - * method tables). - */ - - /* - * Generate a temporary list of virtual methods. - */ - int methodCount = -1; - if (!gatherMethods(interfaces, &methods, &throws, &methodCount)) - goto bail; - - /* - * Allocate storage for the class object and set some basic fields. - */ - newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); - if (newClass == NULL) - goto bail; - DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass); - dvmSetClassSerialNumber(newClass); - newClass->descriptorAlloc = dvmNameToDescriptor(nameStr); - newClass->descriptor = newClass->descriptorAlloc; - newClass->accessFlags = ACC_PUBLIC | ACC_FINAL; - newClass->super = gDvm.classJavaLangReflectProxy; - newClass->primitiveType = PRIM_NOT; - newClass->classLoader = loader; -#if WITH_HPROF && WITH_HPROF_STACK - hprofFillInStackTrace(newClass); -#endif - - /* - * Add direct method definitions. We have one (the constructor). - */ - newClass->directMethodCount = 1; - newClass->directMethods = (Method*) dvmLinearAlloc(newClass->classLoader, - 1 * sizeof(Method)); - createConstructor(newClass, &newClass->directMethods[0]); - dvmLinearReadOnly(newClass->classLoader, newClass->directMethods); - - /* - * Add virtual method definitions. - */ - newClass->virtualMethodCount = methodCount; - newClass->virtualMethods = (Method*) dvmLinearAlloc(newClass->classLoader, - newClass->virtualMethodCount * sizeof(Method)); - for (i = 0; i < newClass->virtualMethodCount; i++) { - createHandlerMethod(newClass, &newClass->virtualMethods[i],methods[i]); - } - dvmLinearReadOnly(newClass->classLoader, newClass->virtualMethods); - - /* - * Add interface list. - */ - int interfaceCount = interfaces->length; - ClassObject** ifArray = (ClassObject**) interfaces->contents; - newClass->interfaceCount = interfaceCount; - newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader, - sizeof(ClassObject*) * interfaceCount); - for (i = 0; i < interfaceCount; i++) - newClass->interfaces[i] = ifArray[i]; - dvmLinearReadOnly(newClass->classLoader, newClass->interfaces); - - /* - * Static field list. We have one private field, for our list of - * exceptions declared for each method. - */ - newClass->sfieldCount = 1; - newClass->sfields = (StaticField*) calloc(1, sizeof(StaticField)); - StaticField* sfield = &newClass->sfields[kThrowsField]; - sfield->field.clazz = newClass; - sfield->field.name = "throws"; - sfield->field.signature = "[[Ljava/lang/Throwable;"; - sfield->field.accessFlags = ACC_STATIC | ACC_PRIVATE; - dvmSetStaticFieldObject(sfield, (Object*)throws); - - /* - * Everything is ready. See if the linker will lap it up. - */ - newClass->status = CLASS_LOADED; - if (!dvmLinkClass(newClass, true)) { - LOGD("Proxy class link failed\n"); - goto bail; - } - - /* - * All good. Add it to the hash table. We should NOT see a collision - * here; if we do, it means the caller has screwed up and provided us - * with a duplicate name. - */ - if (!dvmAddClassToHash(newClass)) { - LOGE("ERROR: attempted to generate %s more than once\n", - newClass->descriptor); - goto bail; - } - - result = 0; - -bail: - free(nameStr); - free(methods); - if (result != 0) { - /* must free innards explicitly if we didn't finish linking */ - dvmFreeClassInnards(newClass); - newClass = NULL; - if (!dvmCheckException(dvmThreadSelf())) { - /* throw something */ - dvmThrowException("Ljava/lang/RuntimeException;", NULL); - } - } - - /* allow the GC to free these when nothing else has a reference */ - dvmReleaseTrackedAlloc((Object*) throws, NULL); - dvmReleaseTrackedAlloc((Object*) newClass, NULL); - - return newClass; -} - - -/* - * Generate a list of methods. The Method pointers returned point to the - * abstract method definition from the appropriate interface, or to the - * virtual method definition in java.lang.Object. - * - * We also allocate an array of arrays of throwable classes, one for each - * method,so we can do some special handling of checked exceptions. The - * caller must call ReleaseTrackedAlloc() on *pThrows. - */ -static bool gatherMethods(ArrayObject* interfaces, Method*** pMethods, - ArrayObject** pThrows, int* pMethodCount) -{ - ClassObject** classes; - ArrayObject* throws = NULL; - Method** methods = NULL; - Method** allMethods = NULL; - int numInterfaces, maxCount, actualCount, allCount; - bool result = false; - int i; - - /* - * Get a maximum count so we can allocate storage. We need the - * methods declared by each interface and all of its superinterfaces. - */ - maxCount = 3; // 3 methods in java.lang.Object - numInterfaces = interfaces->length; - classes = (ClassObject**) interfaces->contents; - - for (i = 0; i < numInterfaces; i++, classes++) { - ClassObject* clazz = *classes; - - LOGVV("--- %s virtualMethodCount=%d\n", - clazz->descriptor, clazz->virtualMethodCount); - maxCount += clazz->virtualMethodCount; - - int j; - for (j = 0; j < clazz->iftableCount; j++) { - ClassObject* iclass = clazz->iftable[j].clazz; - - LOGVV("--- +%s %d\n", - iclass->descriptor, iclass->virtualMethodCount); - maxCount += iclass->virtualMethodCount; - } - } - - methods = (Method**) malloc(maxCount * sizeof(*methods)); - allMethods = (Method**) malloc(maxCount * sizeof(*methods)); - if (methods == NULL || allMethods == NULL) - goto bail; - - /* - * First three entries are the java.lang.Object methods. - */ - ClassObject* obj = gDvm.classJavaLangObject; - allMethods[0] = obj->vtable[gDvm.voffJavaLangObject_equals]; - allMethods[1] = obj->vtable[gDvm.voffJavaLangObject_hashCode]; - allMethods[2] = obj->vtable[gDvm.voffJavaLangObject_toString]; - allCount = 3; - - /* - * Add the methods from each interface, in order. - */ - classes = (ClassObject**) interfaces->contents; - for (i = 0; i < numInterfaces; i++, classes++) { - ClassObject* clazz = *classes; - int j; - - for (j = 0; j < clazz->virtualMethodCount; j++) { - allMethods[allCount++] = &clazz->virtualMethods[j]; - } - - for (j = 0; j < clazz->iftableCount; j++) { - ClassObject* iclass = clazz->iftable[j].clazz; - int k; - - for (k = 0; k < iclass->virtualMethodCount; k++) { - allMethods[allCount++] = &iclass->virtualMethods[k]; - } - } - } - assert(allCount == maxCount); - - /* - * Allocate some storage to hold the lists of throwables. We need - * one entry per unique method, but it's convenient to allocate it - * ahead of the duplicate processing. - */ - ClassObject* arrArrClass; - arrArrClass = dvmFindArrayClass("[[Ljava/lang/Throwable;", NULL); - if (arrArrClass == NULL) - goto bail; - throws = dvmAllocArrayByClass(arrArrClass, allCount, ALLOC_DEFAULT); - - /* - * Identify and remove duplicates. - */ - actualCount = copyWithoutDuplicates(allMethods, allCount, methods, throws); - if (actualCount < 0) - goto bail; - - //LOGI("gathered methods:\n"); - //for (i = 0; i < actualCount; i++) { - // LOGI(" %d: %s.%s\n", - // i, methods[i]->clazz->descriptor, methods[i]->name); - //} - - *pMethods = methods; - *pMethodCount = actualCount; - *pThrows = throws; - result = true; - -bail: - free(allMethods); - if (!result) { - free(methods); - dvmReleaseTrackedAlloc((Object*)throws, NULL); - } - return result; -} - -/* - * Identify and remove duplicates, where "duplicate" means it has the - * same name and arguments, but not necessarily the same return type. - * - * If duplicate methods have different return types, we want to use the - * first method whose return type is assignable from all other duplicate - * methods. That is, if we have: - * class base {...} - * class sub extends base {...} - * class subsub extends sub {...} - * Then we want to return the method that returns subsub, since callers - * to any form of the method will get a usable object back. - * - * All other duplicate methods are stripped out. - * - * This also populates the "throwLists" array with arrays of Class objects, - * one entry per method in "outMethods". Methods that don't declare any - * throwables (or have no common throwables with duplicate methods) will - * have NULL entries. - * - * Returns the number of methods copied into "methods", or -1 on failure. - */ -static int copyWithoutDuplicates(Method** allMethods, int allCount, - Method** outMethods, ArrayObject* throwLists) -{ - Method* best; - int outCount = 0; - int i, j; - - /* - * The plan is to run through all methods, checking all other methods - * for a duplicate. If we find a match, we see if the other methods' - * return type is compatible/assignable with ours. If the current - * method is assignable from all others, we copy it to the new list, - * and NULL out all other entries. If not, we keep looking for a - * better version. - * - * If there are no duplicates, we copy the method and NULL the entry. - * - * At the end of processing, if we have any non-NULL entries, then we - * have bad duplicates and must exit with an exception. - */ - for (i = 0; i < allCount; i++) { - bool best, dupe; - - if (allMethods[i] == NULL) - continue; - - /* - * Find all duplicates. If any of the return types is not - * assignable to our return type, then we're not the best. - * - * We start from 0, not i, because we need to compare assignability - * the other direction even if we've compared these before. - */ - dupe = false; - best = true; - for (j = 0; j < allCount; j++) { - if (i == j) - continue; - if (allMethods[j] == NULL) - continue; - - if (dvmCompareMethodNamesAndParameterProtos(allMethods[i], - allMethods[j]) == 0) - { - /* - * Duplicate method, check return type. If it's a primitive - * type or void, the types must match exactly, or we throw - * an exception now. - */ - LOGV("MATCH on %s.%s and %s.%s\n", - allMethods[i]->clazz->descriptor, allMethods[i]->name, - allMethods[j]->clazz->descriptor, allMethods[j]->name); - dupe = true; - if (!returnTypesAreCompatible(allMethods[i], allMethods[j])) - best = false; - } - } - - /* - * If this is the best of a set of duplicates, copy it over and - * nuke all duplicates. - * - * While we do this, we create the set of exceptions declared to - * be thrown by all occurrences of the method. - */ - if (dupe) { - if (best) { - LOGV("BEST %d %s.%s -> %d\n", i, - allMethods[i]->clazz->descriptor, allMethods[i]->name, - outCount); - - /* if we have exceptions, make a local copy */ - PointerSet* commonThrows = NULL; - if (!createExceptionClassList(allMethods[i], &commonThrows)) - return -1; - - /* - * Run through one more time, erasing the duplicates. (This - * would go faster if we had marked them somehow.) - */ - for (j = 0; j < allCount; j++) { - if (i == j) - continue; - if (allMethods[j] == NULL) - continue; - if (dvmCompareMethodNamesAndParameterProtos(allMethods[i], - allMethods[j]) == 0) - { - LOGV("DEL %d %s.%s\n", j, - allMethods[j]->clazz->descriptor, - allMethods[j]->name); - - /* - * Update set to hold the intersection of method[i]'s - * and method[j]'s throws. - */ - if (commonThrows != NULL) { - updateExceptionClassList(allMethods[j], - commonThrows); - } - - allMethods[j] = NULL; - } - } - - /* - * If the set of Throwable classes isn't empty, create an - * array of Class, copy them into it, and put the result - * into the "throwLists" array. - */ - if (commonThrows != NULL && - dvmPointerSetGetCount(commonThrows) > 0) - { - int commonCount = dvmPointerSetGetCount(commonThrows); - ArrayObject* throwArray; - Object** contents; - int ent; - - throwArray = dvmAllocArrayByClass( - gDvm.classJavaLangClassArray, commonCount, - ALLOC_DEFAULT); - if (throwArray == NULL) { - LOGE("common-throw array alloc failed\n"); - return -1; - } - - contents = (Object**) throwArray->contents; - for (ent = 0; ent < commonCount; ent++) { - contents[ent] = (Object*) - dvmPointerSetGetEntry(commonThrows, ent); - } - - /* add it to the array of arrays */ - contents = (Object**) throwLists->contents; - contents[outCount] = (Object*) throwArray; - dvmReleaseTrackedAlloc((Object*) throwArray, NULL); - } - - /* copy the winner and NULL it out */ - outMethods[outCount++] = allMethods[i]; - allMethods[i] = NULL; - - dvmPointerSetFree(commonThrows); - } else { - LOGV("BEST not %d\n", i); - } - } else { - /* - * Singleton. Copy the entry and NULL it out. - */ - LOGV("COPY singleton %d %s.%s -> %d\n", i, - allMethods[i]->clazz->descriptor, allMethods[i]->name, - outCount); - - /* keep track of our throwables */ - ArrayObject* exceptionArray = dvmGetMethodThrows(allMethods[i]); - if (exceptionArray != NULL) { - Object** contents; - - contents = (Object**) throwLists->contents; - contents[outCount] = (Object*) exceptionArray; - dvmReleaseTrackedAlloc((Object*) exceptionArray, NULL); - } - - outMethods[outCount++] = allMethods[i]; - allMethods[i] = NULL; - } - } - - /* - * Check for stragglers. If we find any, throw an exception. - */ - for (i = 0; i < allCount; i++) { - if (allMethods[i] != NULL) { - LOGV("BAD DUPE: %d %s.%s\n", i, - allMethods[i]->clazz->descriptor, allMethods[i]->name); - dvmThrowException("Ljava/lang/IllegalArgumentException;", - "incompatible return types in proxied interfaces"); - return -1; - } - } - - return outCount; -} - - -/* - * Classes can declare to throw multiple exceptions in a hierarchy, e.g. - * IOException and FileNotFoundException. Since we're only interested in - * knowing the set that can be thrown without requiring an extra wrapper, - * we can remove anything that is a subclass of something else in the list. - * - * The "mix" step we do next reduces things toward the most-derived class, - * so it's important that we start with the least-derived classes. - */ -static void reduceExceptionClassList(ArrayObject* exceptionArray) -{ - const ClassObject** classes = (const ClassObject**)exceptionArray->contents; - int len = exceptionArray->length; - int i, j; - - /* - * Consider all pairs of classes. If one is the subclass of the other, - * null out the subclass. - */ - for (i = 0; i < len-1; i++) { - if (classes[i] == NULL) - continue; - for (j = i + 1; j < len; j++) { - if (classes[j] == NULL) - continue; - - if (dvmInstanceof(classes[i], classes[j])) { - classes[i] = NULL; - break; /* no more comparisons against classes[i] */ - } else if (dvmInstanceof(classes[j], classes[i])) { - classes[j] = NULL; - } - } - } -} - -/* - * Create a local array with a copy of the throwable classes declared by - * "method". If no throws are declared, "*pSet" will be NULL. - * - * Returns "false" on allocation failure. - */ -static bool createExceptionClassList(const Method* method, PointerSet** pThrows) -{ - ArrayObject* exceptionArray = NULL; - bool result = false; - - exceptionArray = dvmGetMethodThrows(method); - if (exceptionArray != NULL && exceptionArray->length > 0) { - /* reduce list, nulling out redundant entries */ - reduceExceptionClassList(exceptionArray); - - *pThrows = dvmPointerSetAlloc(exceptionArray->length); - if (*pThrows == NULL) - goto bail; - - const ClassObject** contents; - int i; - - contents = (const ClassObject**) exceptionArray->contents; - for (i = 0; i < (int) exceptionArray->length; i++) { - if (contents[i] != NULL) - dvmPointerSetAddEntry(*pThrows, contents[i]); - } - } else { - *pThrows = NULL; - } - - result = true; - -bail: - dvmReleaseTrackedAlloc((Object*) exceptionArray, NULL); - return result; -} - -/* - * We need to compute the intersection of the arguments, i.e. remove - * anything from "throws" that isn't in the method's list of throws. - * - * If one class is a subclass of another, we want to keep just the subclass, - * moving toward the most-restrictive set. - * - * We assume these are all classes, and don't try to filter out interfaces. - */ -static void updateExceptionClassList(const Method* method, PointerSet* throws) -{ - int setSize = dvmPointerSetGetCount(throws); - if (setSize == 0) - return; - - ArrayObject* exceptionArray = dvmGetMethodThrows(method); - if (exceptionArray == NULL) { - /* nothing declared, so intersection is empty */ - dvmPointerSetClear(throws); - return; - } - - /* reduce list, nulling out redundant entries */ - reduceExceptionClassList(exceptionArray); - - int mixLen = dvmPointerSetGetCount(throws); - const ClassObject* mixSet[mixLen]; - - int declLen = exceptionArray->length; - const ClassObject** declSet = (const ClassObject**)exceptionArray->contents; - - int i, j; - - /* grab a local copy to work on */ - for (i = 0; i < mixLen; i++) { - mixSet[i] = dvmPointerSetGetEntry(throws, i); - } - - for (i = 0; i < mixLen; i++) { - for (j = 0; j < declLen; j++) { - if (declSet[j] == NULL) - continue; - - if (mixSet[i] == declSet[j]) { - /* match, keep this one */ - break; - } else if (dvmInstanceof(mixSet[i], declSet[j])) { - /* mix is a subclass of a declared throwable, keep it */ - break; - } else if (dvmInstanceof(declSet[j], mixSet[i])) { - /* mix is a superclass, replace it */ - mixSet[i] = declSet[j]; - break; - } - } - - if (j == declLen) { - /* no match, remove entry by nulling it out */ - mixSet[i] = NULL; - } - } - - /* copy results back out; this eliminates duplicates as we go */ - dvmPointerSetClear(throws); - for (i = 0; i < mixLen; i++) { - if (mixSet[i] != NULL) - dvmPointerSetAddEntry(throws, mixSet[i]); - } - - dvmReleaseTrackedAlloc((Object*) exceptionArray, NULL); -} - - -/* - * Check to see if the return types are compatible. - * - * If the return type is primitive or void, it must match exactly. - * - * If not, the type in "subMethod" must be assignable to the type in - * "baseMethod". - */ -static bool returnTypesAreCompatible(Method* subMethod, Method* baseMethod) -{ - const char* baseSig = dexProtoGetReturnType(&baseMethod->prototype); - const char* subSig = dexProtoGetReturnType(&subMethod->prototype); - ClassObject* baseClass; - ClassObject* subClass; - - if (baseSig[1] == '\0' || subSig[1] == '\0') { - /* at least one is primitive type */ - return (baseSig[0] == subSig[0] && baseSig[1] == subSig[1]); - } - - baseClass = dvmFindClass(baseSig, baseMethod->clazz->classLoader); - subClass = dvmFindClass(subSig, subMethod->clazz->classLoader); - bool result = dvmInstanceof(subClass, baseClass); - return result; -} - -/* - * Create a constructor for our Proxy class. The constructor takes one - * argument, a java.lang.reflect.InvocationHandler. - */ -static void createConstructor(ClassObject* clazz, Method* meth) -{ - meth->clazz = clazz; - meth->accessFlags = ACC_PUBLIC | ACC_NATIVE; - meth->name = "<init>"; - meth->prototype = - gDvm.methJavaLangReflectProxy_constructorPrototype->prototype; - meth->shorty = - gDvm.methJavaLangReflectProxy_constructorPrototype->shorty; - // no pDexCode or pDexMethod - - int argsSize = dvmComputeMethodArgsSize(meth) + 1; - meth->registersSize = meth->insSize = argsSize; - - meth->nativeFunc = proxyConstructor; -} - -/* - * Create a method in our Proxy class with the name and signature of - * the interface method it implements. - */ -static void createHandlerMethod(ClassObject* clazz, Method* dstMeth, - const Method* srcMeth) -{ - dstMeth->clazz = clazz; - dstMeth->insns = (u2*) srcMeth; - dstMeth->accessFlags = ACC_PUBLIC | ACC_NATIVE; - dstMeth->name = srcMeth->name; - dstMeth->prototype = srcMeth->prototype; - dstMeth->shorty = srcMeth->shorty; - // no pDexCode or pDexMethod - - int argsSize = dvmComputeMethodArgsSize(dstMeth) + 1; - dstMeth->registersSize = dstMeth->insSize = argsSize; - - dstMeth->nativeFunc = proxyInvoker; -} - -/* - * Return a new Object[] array with the contents of "args". We determine - * the number and types of values in "args" based on the method signature. - * Primitive types are boxed. - * - * Returns NULL if the method takes no arguments. - * - * The caller must call dvmReleaseTrackedAlloc() on the return value. - * - * On failure, returns with an appropriate exception raised. - */ -static ArrayObject* boxMethodArgs(const Method* method, const u4* args) -{ - const char* desc = &method->shorty[1]; // [0] is the return type. - ArrayObject* argArray = NULL; - int argCount; - Object** argObjects; - bool failed = true; - - /* count args */ - argCount = dexProtoGetParameterCount(&method->prototype); - - /* allocate storage */ - argArray = dvmAllocArray(gDvm.classJavaLangObjectArray, argCount, - kObjectArrayRefWidth, ALLOC_DEFAULT); - if (argArray == NULL) - goto bail; - argObjects = (Object**) argArray->contents; - - /* - * Fill in the array. - */ - - int srcIndex = 0; - - argCount = 0; - while (*desc != '\0') { - char descChar = *(desc++); - JValue value; - - switch (descChar) { - case 'Z': - case 'C': - case 'F': - case 'B': - case 'S': - case 'I': - value.i = args[srcIndex++]; - argObjects[argCount] = (Object*) dvmWrapPrimitive(value, - dvmFindPrimitiveClass(descChar)); - /* argObjects is tracked, don't need to hold this too */ - dvmReleaseTrackedAlloc(argObjects[argCount], NULL); - argCount++; - break; - case 'D': - case 'J': - value.j = dvmGetArgLong(args, srcIndex); - srcIndex += 2; - argObjects[argCount] = (Object*) dvmWrapPrimitive(value, - dvmFindPrimitiveClass(descChar)); - dvmReleaseTrackedAlloc(argObjects[argCount], NULL); - argCount++; - break; - case '[': - case 'L': - argObjects[argCount++] = (Object*) args[srcIndex++]; - break; - } - } - - failed = false; - -bail: - if (failed) { - dvmReleaseTrackedAlloc((Object*)argArray, NULL); - argArray = NULL; - } - return argArray; -} - -/* - * This is the constructor for a generated proxy object. All we need to - * do is stuff "handler" into "h". - */ -static void proxyConstructor(const u4* args, JValue* pResult, - const Method* method, Thread* self) -{ - Object* obj = (Object*) args[0]; - Object* handler = (Object*) args[1]; - - dvmSetFieldObject(obj, gDvm.offJavaLangReflectProxy_h, handler); -} - -/* - * This is the common message body for proxy methods. - * - * The method we're calling looks like: - * public Object invoke(Object proxy, Method method, Object[] args) - * - * This means we have to create a Method object, box our arguments into - * a new Object[] array, make the call, and unbox the return value if - * necessary. - */ -static void proxyInvoker(const u4* args, JValue* pResult, - const Method* method, Thread* self) -{ - Object* thisObj = (Object*) args[0]; - Object* methodObj = NULL; - ArrayObject* argArray = NULL; - Object* handler; - Method* invoke; - ClassObject* returnType; - int hOffset; - JValue invokeResult; - - /* - * Retrieve handler object for this proxy instance. The field is - * defined in the superclass (Proxy). - */ - handler = dvmGetFieldObject(thisObj, gDvm.offJavaLangReflectProxy_h); - - /* - * Find the invoke() method, looking in "this"s class. (Because we - * start here we don't have to convert it to a vtable index and then - * index into this' vtable.) - */ - invoke = dvmFindVirtualMethodHierByDescriptor(handler->clazz, "invoke", - "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); - if (invoke == NULL) { - LOGE("Unable to find invoke()\n"); - dvmAbort(); - } - - LOGV("invoke: %s.%s, this=%p, handler=%s\n", - method->clazz->descriptor, method->name, - thisObj, handler->clazz->descriptor); - - /* - * Create a java.lang.reflect.Method object for this method. - * - * We don't want to use "method", because that's the concrete - * implementation in the proxy class. We want the abstract Method - * from the declaring interface. We have a pointer to it tucked - * away in the "insns" field. - * - * TODO: this could be cached for performance. - */ - methodObj = dvmCreateReflectMethodObject((Method*) method->insns); - if (methodObj == NULL) { - assert(dvmCheckException(self)); - goto bail; - } - - /* - * Determine the return type from the signature. - * - * TODO: this could be cached for performance. - */ - returnType = dvmGetBoxedReturnType(method); - if (returnType == NULL) { - char* desc = dexProtoCopyMethodDescriptor(&method->prototype); - LOGE("Could not determine return type for '%s'\n", desc); - free(desc); - assert(dvmCheckException(self)); - goto bail; - } - LOGV(" return type will be %s\n", returnType->descriptor); - - /* - * Convert "args" array into Object[] array, using the method - * signature to determine types. If the method takes no arguments, - * we must pass null. - */ - argArray = boxMethodArgs(method, args+1); - if (dvmCheckException(self)) - goto bail; - - /* - * Call h.invoke(proxy, method, args). - * - * We don't need to repackage exceptions, so if one has been thrown - * just jump to the end. - */ - dvmCallMethod(self, invoke, handler, &invokeResult, - thisObj, methodObj, argArray); - if (dvmCheckException(self)) { - Object* excep = dvmGetException(self); - if (mustWrapException(method, excep)) { - /* wrap with UndeclaredThrowableException */ - dvmWrapException("Ljava/lang/reflect/UndeclaredThrowableException;"); - } - goto bail; - } - - /* - * Unbox the return value. If it's the wrong type, throw a - * ClassCastException. If it's a null pointer and we need a - * primitive type, throw a NullPointerException. - */ - if (returnType->primitiveType == PRIM_VOID) { - LOGVV("+++ ignoring return to void\n"); - } else if (invokeResult.l == NULL) { - if (dvmIsPrimitiveClass(returnType)) { - dvmThrowException("Ljava/lang/NullPointerException;", - "null result when primitive expected"); - goto bail; - } - pResult->l = NULL; - } else { - if (!dvmUnwrapPrimitive(invokeResult.l, returnType, pResult)) { - dvmThrowExceptionWithClassMessage("Ljava/lang/ClassCastException;", - ((Object*)invokeResult.l)->clazz->descriptor); - goto bail; - } - } - -bail: - dvmReleaseTrackedAlloc(methodObj, self); - dvmReleaseTrackedAlloc((Object*)argArray, self); -} - -/* - * Determine if it's okay for this method to throw this exception. If - * an unchecked exception was thrown we immediately return false. If - * checked, we have to ensure that this method and all of its duplicates - * have declared that they throw it. - */ -static bool mustWrapException(const Method* method, const Object* throwable) -{ - const ArrayObject* throws; - const ArrayObject* methodThrows; - const Object** contents; - const ClassObject** classes; - - if (!dvmIsCheckedException(throwable)) - return false; - - const StaticField* sfield = &method->clazz->sfields[kThrowsField]; - throws = (ArrayObject*) dvmGetStaticFieldObject(sfield); - - int methodIndex = method - method->clazz->virtualMethods; - assert(methodIndex >= 0 && methodIndex < method->clazz->virtualMethodCount); - - contents = (const Object**) throws->contents; - methodThrows = (ArrayObject*) contents[methodIndex]; - - if (methodThrows == NULL) { - /* no throws declared, must wrap all checked exceptions */ - //printf("+++ methodThrows[%d] is null, wrapping all\n", methodIndex); - return true; - } - - int throwCount = methodThrows->length; - classes = (const ClassObject**) methodThrows->contents; - int i; - - //printf("%s.%s list:\n", method->clazz->descriptor, method->name); - //for (i = 0; i < throwCount; i++) - // printf(" %d: %s\n", i, classes[i]->descriptor); - - for (i = 0; i < throwCount; i++) { - if (dvmInstanceof(throwable->clazz, classes[i])) { - /* this was declared, okay to throw */ - return false; - } - } - - /* no match in declared throws */ - return true; -} - diff --git a/vm/reflect/Reflect.c b/vm/reflect/Reflect.c deleted file mode 100644 index b7de934de..000000000 --- a/vm/reflect/Reflect.c +++ /dev/null @@ -1,1258 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Basic reflection calls and utility functions. - */ -#include "Dalvik.h" - -#include <stdlib.h> - -/* - * Cache some classes. - */ -bool dvmReflectStartup(void) -{ - gDvm.classJavaLangReflectAccessibleObject = - dvmFindSystemClassNoInit("Ljava/lang/reflect/AccessibleObject;"); - gDvm.classJavaLangReflectConstructor = - dvmFindSystemClassNoInit("Ljava/lang/reflect/Constructor;"); - gDvm.classJavaLangReflectConstructorArray = - dvmFindArrayClass("[Ljava/lang/reflect/Constructor;", NULL); - gDvm.classJavaLangReflectField = - dvmFindSystemClassNoInit("Ljava/lang/reflect/Field;"); - gDvm.classJavaLangReflectFieldArray = - dvmFindArrayClass("[Ljava/lang/reflect/Field;", NULL); - gDvm.classJavaLangReflectMethod = - dvmFindSystemClassNoInit("Ljava/lang/reflect/Method;"); - gDvm.classJavaLangReflectMethodArray = - dvmFindArrayClass("[Ljava/lang/reflect/Method;", NULL); - gDvm.classJavaLangReflectProxy = - dvmFindSystemClassNoInit("Ljava/lang/reflect/Proxy;"); - if (gDvm.classJavaLangReflectAccessibleObject == NULL || - gDvm.classJavaLangReflectConstructor == NULL || - gDvm.classJavaLangReflectConstructorArray == NULL || - gDvm.classJavaLangReflectField == NULL || - gDvm.classJavaLangReflectFieldArray == NULL || - gDvm.classJavaLangReflectMethod == NULL || - gDvm.classJavaLangReflectMethodArray == NULL || - gDvm.classJavaLangReflectProxy == NULL) - { - LOGE("Could not find one or more reflection classes\n"); - return false; - } - - gDvm.methJavaLangReflectConstructor_init = - dvmFindDirectMethodByDescriptor(gDvm.classJavaLangReflectConstructor, "<init>", - "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;I)V"); - gDvm.methJavaLangReflectField_init = - dvmFindDirectMethodByDescriptor(gDvm.classJavaLangReflectField, "<init>", - "(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;I)V"); - gDvm.methJavaLangReflectMethod_init = - dvmFindDirectMethodByDescriptor(gDvm.classJavaLangReflectMethod, "<init>", - "(Ljava/lang/Class;[Ljava/lang/Class;[Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;I)V"); - if (gDvm.methJavaLangReflectConstructor_init == NULL || - gDvm.methJavaLangReflectField_init == NULL || - gDvm.methJavaLangReflectMethod_init == NULL) - { - LOGE("Could not find reflection constructors\n"); - return false; - } - - gDvm.classJavaLangClassArray = - dvmFindArrayClass("[Ljava/lang/Class;", NULL); - gDvm.classJavaLangObjectArray = - dvmFindArrayClass("[Ljava/lang/Object;", NULL); - if (gDvm.classJavaLangClassArray == NULL || - gDvm.classJavaLangObjectArray == NULL) - { - LOGE("Could not find class-array or object-array class\n"); - return false; - } - - gDvm.offJavaLangReflectAccessibleObject_flag = - dvmFindFieldOffset(gDvm.classJavaLangReflectAccessibleObject, "flag", - "Z"); - - gDvm.offJavaLangReflectConstructor_slot = - dvmFindFieldOffset(gDvm.classJavaLangReflectConstructor, "slot", "I"); - gDvm.offJavaLangReflectConstructor_declClass = - dvmFindFieldOffset(gDvm.classJavaLangReflectConstructor, - "declaringClass", "Ljava/lang/Class;"); - - gDvm.offJavaLangReflectField_slot = - dvmFindFieldOffset(gDvm.classJavaLangReflectField, "slot", "I"); - gDvm.offJavaLangReflectField_declClass = - dvmFindFieldOffset(gDvm.classJavaLangReflectField, - "declaringClass", "Ljava/lang/Class;"); - - gDvm.offJavaLangReflectMethod_slot = - dvmFindFieldOffset(gDvm.classJavaLangReflectMethod, "slot", "I"); - gDvm.offJavaLangReflectMethod_declClass = - dvmFindFieldOffset(gDvm.classJavaLangReflectMethod, - "declaringClass", "Ljava/lang/Class;"); - - if (gDvm.offJavaLangReflectAccessibleObject_flag < 0 || - gDvm.offJavaLangReflectConstructor_slot < 0 || - gDvm.offJavaLangReflectConstructor_declClass < 0 || - gDvm.offJavaLangReflectField_slot < 0 || - gDvm.offJavaLangReflectField_declClass < 0 || - gDvm.offJavaLangReflectMethod_slot < 0 || - gDvm.offJavaLangReflectMethod_declClass < 0) - { - LOGE("Could not find reflection fields\n"); - return false; - } - - if (!dvmReflectProxyStartup()) - return false; - if (!dvmReflectAnnotationStartup()) - return false; - - return true; -} - -/* - * Clean up. - */ -void dvmReflectShutdown(void) -{ - // nothing to do -} - -/* - * For some of the reflection stuff we need to un-box primitives, e.g. - * convert a java/lang/Integer to int or even a float. We assume that - * the first instance field holds the value. - * - * To verify this, we either need to ensure that the class has only one - * instance field, or we need to look up the field by name and verify - * that it comes first. The former is simpler, and should work. - */ -bool dvmValidateBoxClasses() -{ - static const char* classes[] = { - "Ljava/lang/Boolean;", - "Ljava/lang/Character;", - "Ljava/lang/Float;", - "Ljava/lang/Double;", - "Ljava/lang/Byte;", - "Ljava/lang/Short;", - "Ljava/lang/Integer;", - "Ljava/lang/Long;", - NULL - }; - const char** ccp; - - for (ccp = classes; *ccp != NULL; ccp++) { - ClassObject* clazz; - - clazz = dvmFindClassNoInit(*ccp, NULL); - if (clazz == NULL) { - LOGE("Couldn't find '%s'\n", *ccp); - return false; - } - - if (clazz->ifieldCount != 1) { - LOGE("Found %d instance fields in '%s'\n", - clazz->ifieldCount, *ccp); - return false; - } - } - - return true; -} - - -/* - * Find the named class object. We have to trim "*pSignature" down to just - * the first token, do the lookup, and then restore anything important - * that we've stomped on. - * - * "pSig" will be advanced to the start of the next token. - */ -static ClassObject* convertSignaturePartToClass(char** pSignature, - const ClassObject* defClass) -{ - ClassObject* clazz = NULL; - char* signature = *pSignature; - - if (*signature == '[') { - /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */ - char savedChar; - - while (*++signature == '[') - ; - if (*signature == 'L') { - while (*++signature != ';') - ; - } - - /* advance past ';', and stomp on whatever comes next */ - savedChar = *++signature; - *signature = '\0'; - clazz = dvmFindArrayClass(*pSignature, defClass->classLoader); - *signature = savedChar; - } else if (*signature == 'L') { - /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */ - char savedChar; - while (*++signature != ';') - ; - savedChar = *++signature; - *signature = '\0'; - clazz = dvmFindClass(*pSignature, defClass->classLoader); - *signature = savedChar; - } else { - clazz = dvmFindPrimitiveClass(*signature++); - } - - if (clazz == NULL) { - LOGW("Unable to match class for part: '%s'\n", *pSignature); - dvmClearException(dvmThreadSelf()); - dvmThrowException("Ljava/lang/NoSuchMethodException;", NULL); - } - *pSignature = signature; - return clazz; -} - -/* - * Convert the method signature to an array of classes. - * - * The tokenization process may mangle "*pSignature". On return, it will - * be pointing at the closing ')'. - * - * "defClass" is the method's class, which is needed to make class loaders - * happy. - */ -static ArrayObject* convertSignatureToClassArray(char** pSignature, - ClassObject* defClass) -{ - ArrayObject* classArray; - ClassObject** classes; - char* signature = *pSignature; - char* cp; - int i, count; - - assert(*signature == '('); - signature++; - - /* count up the number of parameters */ - count = 0; - cp = signature; - while (*cp != ')') { - count++; - - if (*cp == '[') { - while (*++cp == '[') - ; - } - if (*cp == 'L') { - while (*++cp != ';') - ; - } - cp++; - } - LOGVV("REFLECT found %d parameters in '%s'\n", count, *pSignature); - - /* create an array to hold them */ - classArray = dvmAllocArray(gDvm.classJavaLangClassArray, count, - kObjectArrayRefWidth, ALLOC_DEFAULT); - if (classArray == NULL) - return NULL; - - /* fill it in */ - classes = (ClassObject**) classArray->contents; - cp = signature; - for (i = 0; i < count; i++) { - ClassObject* clazz; - - clazz = convertSignaturePartToClass(&cp, defClass); - if (clazz == NULL) { - assert(dvmCheckException(dvmThreadSelf())); - return NULL; - } - LOGVV("REFLECT %d: '%s'\n", i, clazz->descriptor); - - *classes++ = clazz; - } - - *pSignature = cp; - - /* caller must call dvmReleaseTrackedAlloc */ - return classArray; -} - - -/* - * Convert a field pointer to a slot number. - * - * We use positive values starting from 0 for instance fields, negative - * values starting from -1 for static fields. - */ -static int fieldToSlot(const Field* field, const ClassObject* clazz) -{ - int slot; - - if (dvmIsStaticField(field)) { - slot = (StaticField*)field - clazz->sfields; - assert(slot >= 0 && slot < clazz->sfieldCount); - slot = -(slot+1); - } else { - slot = (InstField*)field - clazz->ifields; - assert(slot >= 0 && slot < clazz->ifieldCount); - } - - return slot; -} - -/* - * Convert a slot number to a field pointer. - */ -Field* dvmSlotToField(ClassObject* clazz, int slot) -{ - if (slot < 0) { - slot = -(slot+1); - assert(slot < clazz->sfieldCount); - return (Field*) &clazz->sfields[slot]; - } else { - assert(slot < clazz->ifieldCount); - return (Field*) &clazz->ifields[slot]; - } -} - -/* - * Create a new java.lang.reflect.Field object from "field". - * - * The Field spec doesn't specify the constructor. We're going to use the - * one from our existing class libs: - * - * private Field(Class declaringClass, Class type, String name, int slot) - */ -static Object* createFieldObject(Field* field, const ClassObject* clazz) -{ - Object* result = NULL; - Object* fieldObj = NULL; - StringObject* nameObj = NULL; - ClassObject* type; - char* mangle; - char* cp; - int slot; - - assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField)); - - fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT); - if (fieldObj == NULL) - goto bail; - - cp = mangle = strdup(field->signature); - type = convertSignaturePartToClass(&cp, clazz); - free(mangle); - if (type == NULL) - goto bail; - - nameObj = dvmCreateStringFromCstr(field->name, ALLOC_DEFAULT); - if (nameObj == NULL) - goto bail; - - slot = fieldToSlot(field, clazz); - - JValue unused; - dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init, - fieldObj, &unused, clazz, type, nameObj, slot); - if (dvmCheckException(dvmThreadSelf())) { - LOGD("Field class init threw exception\n"); - goto bail; - } - - result = fieldObj; - -bail: - dvmReleaseTrackedAlloc((Object*) nameObj, NULL); - if (result == NULL) - dvmReleaseTrackedAlloc((Object*) fieldObj, NULL); - /* caller must dvmReleaseTrackedAlloc(result) */ - return result; -} - -/* - * - * Get an array with all fields declared by a class. - * - * This includes both static and instance fields. - */ -ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly) -{ - ArrayObject* fieldArray = NULL; - Object** fields; - int i, count; - - if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) - dvmInitClass(gDvm.classJavaLangReflectField); - - /* count #of fields */ - if (!publicOnly) - count = clazz->sfieldCount + clazz->ifieldCount; - else { - count = 0; - for (i = 0; i < clazz->sfieldCount; i++) { - if ((clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0) - count++; - } - for (i = 0; i < clazz->ifieldCount; i++) { - if ((clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0) - count++; - } - } - - /* create the Field[] array */ - fieldArray = dvmAllocArray(gDvm.classJavaLangReflectFieldArray, count, - kObjectArrayRefWidth, ALLOC_DEFAULT); - if (fieldArray == NULL) - return NULL; - fields = (Object**) fieldArray->contents; - - /* populate */ - for (i = 0; i < clazz->sfieldCount; i++) { - if (!publicOnly || - (clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0) - { - *fields = createFieldObject(&clazz->sfields[i].field, clazz); - if (*fields == NULL) - goto fail; - dvmReleaseTrackedAlloc(*fields, NULL); - fields++; - count--; - } - } - for (i = 0; i < clazz->ifieldCount; i++) { - if (!publicOnly || - (clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0) - { - *fields = createFieldObject(&clazz->ifields[i].field, clazz); - if (*fields == NULL) - goto fail; - dvmReleaseTrackedAlloc(*fields, NULL); - fields++; - count--; - } - } - - /* caller must call dvmReleaseTrackedAlloc */ - return fieldArray; - -fail: - dvmReleaseTrackedAlloc((Object*) fieldArray, NULL); - return NULL; -} - - -/* - * Convert a method pointer to a slot number. - * - * We use positive values starting from 0 for virtual methods, negative - * values starting from -1 for static methods. - */ -static int methodToSlot(const Method* meth) -{ - ClassObject* clazz = meth->clazz; - int slot; - - if (dvmIsDirectMethod(meth)) { - slot = meth - clazz->directMethods; - assert(slot >= 0 && slot < clazz->directMethodCount); - slot = -(slot+1); - } else { - slot = meth - clazz->virtualMethods; - assert(slot >= 0 && slot < clazz->virtualMethodCount); - } - - return slot; -} - -/* - * Convert a slot number to a method pointer. - */ -Method* dvmSlotToMethod(ClassObject* clazz, int slot) -{ - if (slot < 0) { - slot = -(slot+1); - assert(slot < clazz->directMethodCount); - return &clazz->directMethods[slot]; - } else { - assert(slot < clazz->virtualMethodCount); - return &clazz->virtualMethods[slot]; - } -} - -/* - * Create a new java/lang/reflect/Constructor object, using the contents of - * "meth" to construct it. - * - * The spec doesn't specify the constructor. We're going to use the - * one from our existing class libs: - * - * private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes, - * int slot) - */ -static Object* createConstructorObject(Method* meth) -{ - Object* result = NULL; - ArrayObject* params = NULL; - ArrayObject* exceptions = NULL; - Object* consObj; - DexStringCache mangle; - char* cp; - int slot; - - dexStringCacheInit(&mangle); - - /* parent should guarantee init so we don't have to check on every call */ - assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)); - - consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor, - ALLOC_DEFAULT); - if (consObj == NULL) - goto bail; - - /* - * Convert the signature string into an array of classes representing - * the arguments. - */ - cp = dvmCopyDescriptorStringFromMethod(meth, &mangle); - params = convertSignatureToClassArray(&cp, meth->clazz); - if (params == NULL) - goto bail; - assert(*cp == ')'); - assert(*(cp+1) == 'V'); - - /* - * Create an array with one entry for every exception that the class - * is declared to throw. - */ - exceptions = dvmGetMethodThrows(meth); - if (dvmCheckException(dvmThreadSelf())) - goto bail; - - slot = methodToSlot(meth); - - JValue unused; - dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init, - consObj, &unused, meth->clazz, params, exceptions, slot); - if (dvmCheckException(dvmThreadSelf())) { - LOGD("Constructor class init threw exception\n"); - goto bail; - } - - result = consObj; - -bail: - dexStringCacheRelease(&mangle); - dvmReleaseTrackedAlloc((Object*) params, NULL); - dvmReleaseTrackedAlloc((Object*) exceptions, NULL); - if (result == NULL) { - assert(dvmCheckException(dvmThreadSelf())); - dvmReleaseTrackedAlloc(consObj, NULL); - } - /* caller must dvmReleaseTrackedAlloc(result) */ - return result; -} - -/* - * Get an array with all constructors declared by a class. - */ -ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly) -{ - ArrayObject* consArray; - Object** consObjPtr; - Method* meth; - int i, count; - - if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) - dvmInitClass(gDvm.classJavaLangReflectConstructor); - - /* - * Ordinarily we init the class the first time we resolve a method. - * We're bypassing the normal resolution mechanism, so we init it here. - */ - if (!dvmIsClassInitialized(clazz)) - dvmInitClass(clazz); - - /* - * Count up the #of relevant methods. - */ - count = 0; - meth = clazz->directMethods; - for (i = 0; i < clazz->directMethodCount; i++, meth++) { - if ((!publicOnly || dvmIsPublicMethod(meth)) && - dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) - { - count++; - } - } - - /* - * Create an array of Constructor objects. - */ - consArray = dvmAllocArray(gDvm.classJavaLangReflectConstructorArray, count, - kObjectArrayRefWidth, ALLOC_DEFAULT); - if (consArray == NULL) - return NULL; - - consObjPtr = (Object**) consArray->contents; - - /* - * Fill out the array. - */ - meth = clazz->directMethods; - for (i = 0; i < clazz->directMethodCount; i++, meth++) { - if ((!publicOnly || dvmIsPublicMethod(meth)) && - dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth)) - { - Object* consObj = createConstructorObject(meth); - if (consObj == NULL) - goto fail; - *consObjPtr++ = consObj; - dvmReleaseTrackedAlloc(consObj, NULL); - } - } - - assert(consObjPtr - (Object**) consArray->contents == count); - - /* caller must call dvmReleaseTrackedAlloc */ - return consArray; - -fail: - dvmReleaseTrackedAlloc((Object*) consArray, NULL); - return NULL; -} - -/* - * Create a new java/lang/reflect/Method object, using the contents of - * "meth" to construct it. - * - * The spec doesn't specify the constructor. We're going to use the - * one from our existing class libs: - * - * private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes, - * Class returnType, String name, int slot) - * - * The caller must call dvmReleaseTrackedAlloc() on the result. - */ -Object* dvmCreateReflectMethodObject(const Method* meth) -{ - Object* result = NULL; - ArrayObject* params = NULL; - ArrayObject* exceptions = NULL; - StringObject* nameObj = NULL; - Object* methObj; - ClassObject* returnType; - DexStringCache mangle; - char* cp; - int slot; - - if (dvmCheckException(dvmThreadSelf())) { - LOGW("WARNING: dvmCreateReflectMethodObject called with " - "exception pending\n"); - return NULL; - } - - dexStringCacheInit(&mangle); - - /* parent should guarantee init so we don't have to check on every call */ - assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)); - - methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT); - if (methObj == NULL) - goto bail; - - /* - * Convert the signature string into an array of classes representing - * the arguments, and a class for the return type. - */ - cp = dvmCopyDescriptorStringFromMethod(meth, &mangle); - params = convertSignatureToClassArray(&cp, meth->clazz); - if (params == NULL) - goto bail; - assert(*cp == ')'); - cp++; - returnType = convertSignaturePartToClass(&cp, meth->clazz); - if (returnType == NULL) - goto bail; - - /* - * Create an array with one entry for every exception that the class - * is declared to throw. - */ - exceptions = dvmGetMethodThrows(meth); - if (dvmCheckException(dvmThreadSelf())) - goto bail; - - /* method name */ - nameObj = dvmCreateStringFromCstr(meth->name, ALLOC_DEFAULT); - if (nameObj == NULL) - goto bail; - - slot = methodToSlot(meth); - - JValue unused; - dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init, - methObj, &unused, meth->clazz, params, exceptions, returnType, - nameObj, slot); - if (dvmCheckException(dvmThreadSelf())) { - LOGD("Method class init threw exception\n"); - goto bail; - } - - result = methObj; - -bail: - dexStringCacheRelease(&mangle); - if (result == NULL) { - assert(dvmCheckException(dvmThreadSelf())); - } - dvmReleaseTrackedAlloc((Object*) nameObj, NULL); - dvmReleaseTrackedAlloc((Object*) params, NULL); - dvmReleaseTrackedAlloc((Object*) exceptions, NULL); - if (result == NULL) - dvmReleaseTrackedAlloc(methObj, NULL); - return result; -} - -/* - * Get an array with all methods declared by a class. - * - * This includes both static and virtual methods, and can include private - * members if "publicOnly" is false. It does not include Miranda methods, - * since those weren't declared in the class, or constructors. - */ -ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly) -{ - ArrayObject* methodArray; - Object** methObjPtr; - Method* meth; - int i, count; - - if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) - dvmInitClass(gDvm.classJavaLangReflectMethod); - - /* - * Count up the #of relevant methods. - * - * Ignore virtual Miranda methods and direct class/object constructors. - */ - count = 0; - meth = clazz->virtualMethods; - for (i = 0; i < clazz->virtualMethodCount; i++, meth++) { - if ((!publicOnly || dvmIsPublicMethod(meth)) && - !dvmIsMirandaMethod(meth)) - { - count++; - } - } - meth = clazz->directMethods; - for (i = 0; i < clazz->directMethodCount; i++, meth++) { - if ((!publicOnly || dvmIsPublicMethod(meth)) && - meth->name[0] != '<') - { - count++; - } - } - - /* - * Create an array of Method objects. - */ - methodArray = dvmAllocArray(gDvm.classJavaLangReflectMethodArray, count, - kObjectArrayRefWidth, ALLOC_DEFAULT); - if (methodArray == NULL) - return NULL; - - methObjPtr = (Object**) methodArray->contents; - - /* - * Fill out the array. - */ - meth = clazz->virtualMethods; - for (i = 0; i < clazz->virtualMethodCount; i++, meth++) { - if ((!publicOnly || dvmIsPublicMethod(meth)) && - !dvmIsMirandaMethod(meth)) - { - Object* methObj = dvmCreateReflectMethodObject(meth); - if (methObj == NULL) - goto fail; - *methObjPtr++ = methObj; - dvmReleaseTrackedAlloc(methObj, NULL); - } - } - meth = clazz->directMethods; - for (i = 0; i < clazz->directMethodCount; i++, meth++) { - if ((!publicOnly || dvmIsPublicMethod(meth)) && - meth->name[0] != '<') - { - Object* methObj = dvmCreateReflectMethodObject(meth); - if (methObj == NULL) - goto fail; - *methObjPtr++ = methObj; - dvmReleaseTrackedAlloc(methObj, NULL); - } - } - - assert(methObjPtr - (Object**) methodArray->contents == count); - - /* caller must call dvmReleaseTrackedAlloc */ - return methodArray; - -fail: - dvmReleaseTrackedAlloc((Object*) methodArray, NULL); - return NULL; -} - -/* - * Get all interfaces a class implements. If this is unable to allocate - * the result array, this raises an OutOfMemoryError and returns NULL. - */ -ArrayObject* dvmGetInterfaces(ClassObject* clazz) -{ - ArrayObject* interfaceArray; - - if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) - dvmInitClass(gDvm.classJavaLangReflectMethod); - - /* - * Create an array of Class objects. - */ - int count = clazz->interfaceCount; - interfaceArray = dvmAllocArray(gDvm.classJavaLangClassArray, count, - kObjectArrayRefWidth, ALLOC_DEFAULT); - if (interfaceArray == NULL) - return NULL; - - /* - * Fill out the array. - */ - Object** interfaceObjPtr = (Object**) interfaceArray->contents; - int i; - for (i = 0; i < count; i++) { - *interfaceObjPtr++ = (Object*) clazz->interfaces[i]; - } - - /* caller must call dvmReleaseTrackedAlloc */ - return interfaceArray; -} - -/* - * Given a boxed primitive type, such as java/lang/Integer, return the - * primitive type index. - * - * Returns PRIM_NOT for void, since we never "box" that. - */ -static PrimitiveType getBoxedType(DataObject* arg) -{ - static const int kJavaLangLen = 11; // strlen("Ljava/lang/") - const char* name; - - if (arg == NULL) - return PRIM_NOT; - - name = arg->obj.clazz->descriptor; - - if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0) - return PRIM_NOT; - - if (strcmp(name + kJavaLangLen, "Boolean;") == 0) - return PRIM_BOOLEAN; - if (strcmp(name + kJavaLangLen, "Character;") == 0) - return PRIM_CHAR; - if (strcmp(name + kJavaLangLen, "Float;") == 0) - return PRIM_FLOAT; - if (strcmp(name + kJavaLangLen, "Double;") == 0) - return PRIM_DOUBLE; - if (strcmp(name + kJavaLangLen, "Byte;") == 0) - return PRIM_BYTE; - if (strcmp(name + kJavaLangLen, "Short;") == 0) - return PRIM_SHORT; - if (strcmp(name + kJavaLangLen, "Integer;") == 0) - return PRIM_INT; - if (strcmp(name + kJavaLangLen, "Long;") == 0) - return PRIM_LONG; - return PRIM_NOT; -} - -/* - * Convert primitive, boxed data from "srcPtr" to "dstPtr". - * - * Section v2 2.6 lists the various conversions and promotions. We - * allow the "widening" and "identity" conversions, but don't allow the - * "narrowing" conversions. - * - * Allowed: - * byte to short, int, long, float, double - * short to int, long, float double - * char to int, long, float, double - * int to long, float, double - * long to float, double - * float to double - * Values of types byte, char, and short are "internally" widened to int. - * - * Returns the width in bytes of the destination primitive, or -1 if the - * conversion is not allowed. - * - * TODO? use JValue rather than u4 pointers - */ -int dvmConvertPrimitiveValue(PrimitiveType srcType, - PrimitiveType dstType, const s4* srcPtr, s4* dstPtr) -{ - enum { - OK4, OK8, ItoJ, - ItoD, JtoD, FtoD, - ItoF, JtoF, - bad, kMax - }; - /* [src][dst] */ - static const int kConvMode[kMax][kMax] = { - /*FROM *TO: bool char float double byte short int long */ - /*bool */ { OK4, bad, bad, bad, bad, bad, bad, bad }, - /*char */ { bad, OK4, ItoF, ItoD, bad, bad, OK4, ItoJ }, - /*float*/ { bad, bad, OK4, FtoD, bad, bad, bad, bad }, - /*doubl*/ { bad, bad, bad, OK8, bad, bad, bad, bad }, - /*byte */ { bad, bad, ItoF, ItoD, OK4, OK4, OK4, ItoJ }, - /*short*/ { bad, bad, ItoF, ItoD, bad, OK4, OK4, ItoJ }, - /*int */ { bad, bad, ItoF, ItoD, bad, bad, OK4, ItoJ }, - /*long */ { bad, bad, JtoF, JtoD, bad, bad, bad, OK8 }, - }; - int result; - - assert(srcType != PRIM_NOT && dstType != PRIM_NOT && - srcType != PRIM_VOID && dstType != PRIM_VOID); - result = kConvMode[srcType][dstType]; - - //LOGV("+++ convprim: src=%d dst=%d result=%d\n", srcType, dstType, result); - - switch (result) { - case OK4: - *dstPtr = *srcPtr; - return 1; - case OK8: - *(s8*)dstPtr = *(s8*)srcPtr; - return 2; - case ItoJ: - *(s8*)dstPtr = (s8) (*(s4*) srcPtr); - return 2; - case ItoD: - *(double*)dstPtr = (double) (*(s4*) srcPtr); - return 2; - case JtoD: - *(double*)dstPtr = (double) (*(long long*) srcPtr); - return 2; - case FtoD: - *(double*)dstPtr = (double) (*(float*) srcPtr); - return 2; - case ItoF: - *(float*)dstPtr = (float) (*(int*) srcPtr); - return 1; - case JtoF: - *(float*)dstPtr = (float) (*(long long*) srcPtr); - return 1; - case bad: - LOGV("convert primitive: prim %d to %d not allowed\n", - srcType, dstType); - return -1; - default: - assert(false); - return -1; - } -} - -/* - * Convert types and widen primitives. Puts the value of "arg" into - * "destPtr". - * - * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error. - */ -int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr) -{ - int retVal; - - if (dvmIsPrimitiveClass(type)) { - /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */ - PrimitiveType srcType; - s4* valuePtr; - - srcType = getBoxedType(arg); - if (srcType < 0) { // didn't pass a boxed primitive in - LOGVV("conv arg: type '%s' not boxed primitive\n", - arg->obj.clazz->descriptor); - return -1; - } - - /* assumes value is stored in first instance field */ - valuePtr = (s4*) arg->instanceData; - - retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType, - valuePtr, destPtr); - } else { - /* verify object is compatible */ - if ((arg == NULL) || dvmInstanceof(arg->obj.clazz, type)) { - *destPtr = (s4) arg; - retVal = 1; - } else { - LOGVV("Arg %p (%s) not compatible with %s\n", - arg, arg->obj.clazz->descriptor, type->descriptor); - retVal = -1; - } - } - - return retVal; -} - -/* - * Create a wrapper object for a primitive data type. If "returnType" is - * not primitive, this just casts "value" to an object and returns it. - * - * We could invoke the "toValue" method on the box types to take - * advantage of pre-created values, but running that through the - * interpreter is probably less efficient than just allocating storage here. - * - * The caller must call dvmReleaseTrackedAlloc on the result. - */ -DataObject* dvmWrapPrimitive(JValue value, ClassObject* returnType) -{ - static const char* boxTypes[] = { // order from enum PrimitiveType - "Ljava/lang/Boolean;", - "Ljava/lang/Character;", - "Ljava/lang/Float;", - "Ljava/lang/Double;", - "Ljava/lang/Byte;", - "Ljava/lang/Short;", - "Ljava/lang/Integer;", - "Ljava/lang/Long;" - }; - ClassObject* wrapperClass; - DataObject* wrapperObj; - s4* dataPtr; - PrimitiveType typeIndex = returnType->primitiveType; - const char* classDescriptor; - - if (typeIndex == PRIM_NOT) { - /* add to tracking table so return value is always in table */ - if (value.l != NULL) - dvmAddTrackedAlloc(value.l, NULL); - return (DataObject*) value.l; - } - - assert(typeIndex >= 0 && typeIndex < PRIM_MAX); - if (typeIndex == PRIM_VOID) - return NULL; - - classDescriptor = boxTypes[typeIndex]; - - wrapperClass = dvmFindSystemClass(classDescriptor); - if (wrapperClass == NULL) { - LOGW("Unable to find '%s'\n", classDescriptor); - assert(dvmCheckException(dvmThreadSelf())); - return NULL; - } - - wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT); - if (wrapperObj == NULL) - return NULL; - dataPtr = (s4*) wrapperObj->instanceData; - - /* assumes value is stored in first instance field */ - /* (see dvmValidateBoxClasses) */ - if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE) - *(s8*)dataPtr = value.j; - else - *dataPtr = value.i; - - return wrapperObj; -} - -/* - * Unwrap a primitive data type, if necessary. - * - * If "returnType" is not primitive, we just tuck "value" into JValue and - * return it after verifying that it's the right type of object. - * - * Fails if the field is primitive and "value" is either not a boxed - * primitive or is of a type that cannot be converted. - * - * Returns "true" on success, "false" on failure. - */ -bool dvmUnwrapPrimitive(Object* value, ClassObject* returnType, - JValue* pResult) -{ - JValue result; - PrimitiveType typeIndex = returnType->primitiveType; - PrimitiveType valueIndex; - //const u4* dataPtr; - - if (typeIndex == PRIM_NOT) { - if (value != NULL && !dvmInstanceof(value->clazz, returnType)) { - LOGD("wrong object type: %s %s\n", - value->clazz->descriptor, returnType->descriptor); - return false; - } - pResult->l = value; - return true; - } else if (typeIndex == PRIM_VOID) { - /* can't put anything into a void */ - return false; - } - - valueIndex = getBoxedType((DataObject*)value); - if (valueIndex == PRIM_NOT) - return false; - - /* assumes value is stored in first instance field of "value" */ - /* (see dvmValidateBoxClasses) */ - if (dvmConvertPrimitiveValue(valueIndex, typeIndex, - (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0) - { - LOGV("Prim conversion failed\n"); - return false; - } - - return true; -} - - -/* - * Find the return type in the signature, and convert it to a class - * object. For primitive types we use a boxed class, for reference types - * we do a name lookup. - * - * On failure, we return NULL with an exception raised. - */ -ClassObject* dvmGetBoxedReturnType(const Method* meth) -{ - const char* sig = dexProtoGetReturnType(&meth->prototype); - - switch (*sig) { - case 'Z': - case 'C': - case 'F': - case 'D': - case 'B': - case 'S': - case 'I': - case 'J': - case 'V': - return dvmFindPrimitiveClass(*sig); - case '[': - case 'L': - return dvmFindClass(sig, meth->clazz->classLoader); - default: { - /* should not have passed verification */ - char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); - LOGE("Bad return type in signature '%s'\n", desc); - free(desc); - dvmThrowException("Ljava/lang/InternalError;", NULL); - return NULL; - } - } -} - - -/* - * JNI reflection support: convert reflection object to Field ptr. - */ -Field* dvmGetFieldFromReflectObj(Object* obj) -{ - ClassObject* clazz; - int slot; - - assert(obj->clazz == gDvm.classJavaLangReflectField); - clazz = (ClassObject*)dvmGetFieldObject(obj, - gDvm.offJavaLangReflectField_declClass); - slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot); - - /* must initialize the class before returning a field ID */ - if (!dvmInitClass(clazz)) - return NULL; - - return dvmSlotToField(clazz, slot); -} - -/* - * JNI reflection support: convert reflection object to Method ptr. - */ -Method* dvmGetMethodFromReflectObj(Object* obj) -{ - ClassObject* clazz; - int slot; - - if (obj->clazz == gDvm.classJavaLangReflectConstructor) { - clazz = (ClassObject*)dvmGetFieldObject(obj, - gDvm.offJavaLangReflectConstructor_declClass); - slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot); - } else if (obj->clazz == gDvm.classJavaLangReflectMethod) { - clazz = (ClassObject*)dvmGetFieldObject(obj, - gDvm.offJavaLangReflectMethod_declClass); - slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot); - } else { - assert(false); - return NULL; - } - - /* must initialize the class before returning a method ID */ - if (!dvmInitClass(clazz)) - return NULL; - - return dvmSlotToMethod(clazz, slot); -} - -/* - * JNI reflection support: convert Field to reflection object. - * - * The return value is a java.lang.reflect.Field. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field) -{ - if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField)) - dvmInitClass(gDvm.classJavaLangReflectField); - - /* caller must dvmReleaseTrackedAlloc(result) */ - return createFieldObject(field, clazz); -} - -/* - * JNI reflection support: convert Method to reflection object. - * - * The returned object will be either a java.lang.reflect.Method or - * .Constructor, depending on whether "method" is a constructor. - * - * This is also used for certain "system" annotations. - * - * Caller must call dvmReleaseTrackedAlloc(). - */ -Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method) -{ - UNUSED_PARAMETER(clazz); - - if (strcmp(method->name, "<init>") == 0) { - if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor)) - dvmInitClass(gDvm.classJavaLangReflectConstructor); - - return createConstructorObject(method); - } else { - if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) - dvmInitClass(gDvm.classJavaLangReflectMethod); - - return dvmCreateReflectMethodObject(method); - } -} - diff --git a/vm/reflect/Reflect.h b/vm/reflect/Reflect.h deleted file mode 100644 index cd8e76c4e..000000000 --- a/vm/reflect/Reflect.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - * Basic reflection calls and utility functions. - */ -#ifndef _DALVIK_REFLECT_REFLECT -#define _DALVIK_REFLECT_REFLECT - -bool dvmReflectStartup(void); -bool dvmReflectProxyStartup(void); -bool dvmReflectAnnotationStartup(void); -void dvmReflectShutdown(void); - -/* - * During startup, validate the "box" classes, e.g. java/lang/Integer. - */ -bool dvmValidateBoxClasses(); - -/* - * Get all fields declared by a class. - * - * Includes both class and instance fields. - */ -ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly); - -/* - * Get all constructors declared by a class. - */ -ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly); - -/* - * Get all methods declared by a class. - * - * This includes both static and virtual methods, and can include private - * members if "publicOnly" is false. It does not include Miranda methods, - * since those weren't declared in the class, or constructors. - */ -ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly); - -/* - * Get all interfaces a class implements. If this is unable to allocate - * the result array, this raises an OutOfMemoryError and returns NULL. - */ -ArrayObject* dvmGetInterfaces(ClassObject* clazz); - -/* - * Convert slot numbers back to objects. - */ -Field* dvmSlotToField(ClassObject* clazz, int slot); -Method* dvmSlotToMethod(ClassObject* clazz, int slot); - -/* - * Convert a primitive value, performing a widening conversion if necessary. - */ -int dvmConvertPrimitiveValue(PrimitiveType srcType, - PrimitiveType dstType, const s4* srcPtr, s4* dstPtr); - -/* - * Convert the argument to the specified type. - * - * Returns the width of the argument (1 for most types, 2 for J/D, -1 on - * error). - */ -int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* ins); - -/* - * Create a wrapper object for a primitive data type. If "returnType" is - * not primitive, this just returns "value" cast to an object. - */ -DataObject* dvmWrapPrimitive(JValue value, ClassObject* returnType); - -/* - * Unwrap a boxed primitive. If "returnType" is not primitive, this just - * returns "value" cast into a JValue. - */ -bool dvmUnwrapPrimitive(Object* value, ClassObject* returnType, - JValue* pResult); - -/* - * Return the class object that matches the method's signature. For - * primitive types, returns the box class. - */ -ClassObject* dvmGetBoxedReturnType(const Method* meth); - -/* - * JNI reflection support. - */ -Field* dvmGetFieldFromReflectObj(Object* obj); -Method* dvmGetMethodFromReflectObj(Object* obj); -Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field); -Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method); - -/* - * Quick test to determine if the method in question is a reflection call. - * Used for some stack parsing. Currently defined as "the method's declaring - * class is java.lang.reflect.Method". - */ -INLINE bool dvmIsReflectionMethod(const Method* method) -{ - return (method->clazz == gDvm.classJavaLangReflectMethod); -} - -/* - * Proxy class generation. - */ -ClassObject* dvmGenerateProxyClass(StringObject* str, ArrayObject* interfaces, - Object* loader); - -/* - * Create a new java.lang.reflect.Method object based on "meth". - */ -Object* dvmCreateReflectMethodObject(const Method* meth); - -/* - * Return an array of Annotation objects for the specified piece. For method - * parameters this is an array of arrays of Annotation objects. - * - * Method also applies to Constructor. - */ -ArrayObject* dvmGetClassAnnotations(const ClassObject* clazz); -ArrayObject* dvmGetMethodAnnotations(const Method* method); -ArrayObject* dvmGetFieldAnnotations(const Field* field); -ArrayObject* dvmGetParameterAnnotations(const Method* method); - -/* - * Find the default value for an annotation member. - */ -Object* dvmGetAnnotationDefaultValue(const Method* method); - -/* - * Get the list of thrown exceptions for a method. Returns NULL if there - * are no exceptions listed. - */ -ArrayObject* dvmGetMethodThrows(const Method* method); - -/* - * Get the Signature annotation. - */ -ArrayObject* dvmGetClassSignatureAnnotation(const ClassObject* clazz); -ArrayObject* dvmGetMethodSignatureAnnotation(const Method* method); -ArrayObject* dvmGetFieldSignatureAnnotation(const Field* field); - -/* - * Get the EnclosingMethod attribute from an annotation. Returns a Method - * object, or NULL. - */ -Object* dvmGetEnclosingMethod(const ClassObject* clazz); - -/* - * Return clazz's declaring class, or NULL if there isn't one. - */ -ClassObject* dvmGetDeclaringClass(const ClassObject* clazz); - -/* - * Return clazz's enclosing class, or NULL if there isn't one. - */ -ClassObject* dvmGetEnclosingClass(const ClassObject* clazz); - -/* - * Get the EnclosingClass attribute from an annotation. If found, returns - * "true". A String with the original name of the class and the original - * access flags are returned through the arguments. (The name will be NULL - * for an anonymous inner class.) - */ -bool dvmGetInnerClass(const ClassObject* clazz, StringObject** pName, - int* pAccessFlags); - -/* - * Get an array of class objects from the MemberClasses annotation. Returns - * NULL if none found. - */ -ArrayObject* dvmGetDeclaredClasses(const ClassObject* clazz); - -/* - * Used to pass values out of annotation (and encoded array) processing - * functions. - */ -typedef struct AnnotationValue { - JValue value; - u1 type; -} AnnotationValue; - - -/** - * Iterator structure for iterating over DexEncodedArray instances. The - * structure should be treated as opaque. - */ -typedef struct { - const u1* cursor; /* current cursor */ - u4 elementsLeft; /* number of elements left to read */ - const DexEncodedArray* encodedArray; /* instance being iterated over */ - u4 size; /* number of elements in instance */ - const ClassObject* clazz; /* class to resolve with respect to */ -} EncodedArrayIterator; - -/** - * Initializes an encoded array iterator. - * - * @param iterator iterator to initialize - * @param encodedArray encoded array to iterate over - * @param clazz class to use when resolving strings and types - */ -void dvmEncodedArrayIteratorInitialize(EncodedArrayIterator* iterator, - const DexEncodedArray* encodedArray, const ClassObject* clazz); - -/** - * Returns whether there are more elements to be read. - */ -bool dvmEncodedArrayIteratorHasNext(const EncodedArrayIterator* iterator); - -/** - * Returns the next decoded value from the iterator, advancing its - * cursor. This returns primitive values in their corresponding union - * slots, and returns everything else (including nulls) as object - * references in the "l" union slot. - * - * The caller must call dvmReleaseTrackedAlloc() on any returned reference. - * - * @param value pointer to store decoded value into - * @returns true if a value was decoded and the cursor advanced; false if - * the last value had already been decoded or if there was a problem decoding - */ -bool dvmEncodedArrayIteratorGetNext(EncodedArrayIterator* iterator, - AnnotationValue* value); - -#endif /*_DALVIK_REFLECT_REFLECT*/ |
