auto import from //depot/cupcake/@135843
diff --git a/vm/reflect/Annotation.c b/vm/reflect/Annotation.c
new file mode 100644
index 0000000..c07c602
--- /dev/null
+++ b/vm/reflect/Annotation.c
@@ -0,0 +1,2179 @@
+/*
+ * 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;
+}
+