summaryrefslogtreecommitdiffstats
path: root/vm/reflect
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:14 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:14 -0800
commitf72d5de56a522ac3be03873bdde26f23a5eeeb3c (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /vm/reflect
parent31e30105703263782efd450d356cd67ea01af3b7 (diff)
downloadandroid_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.c2179
-rw-r--r--vm/reflect/Proxy.c1097
-rw-r--r--vm/reflect/Reflect.c1258
-rw-r--r--vm/reflect/Reflect.h239
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*/