Home | History | Annotate | Download | only in reflect
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /*
     17  * Basic reflection calls and utility functions.
     18  */
     19 #include "Dalvik.h"
     20 
     21 #include <stdlib.h>
     22 
     23 /*
     24  * For some of the reflection stuff we need to un-box primitives, e.g.
     25  * convert a java/lang/Integer to int or even a float.  We assume that
     26  * the first instance field holds the value.
     27  *
     28  * To verify this, we either need to ensure that the class has only one
     29  * instance field, or we need to look up the field by name and verify
     30  * that it comes first.  The former is simpler, and should work.
     31  */
     32 bool dvmValidateBoxClasses()
     33 {
     34     static const char* classes[] = {
     35         "Ljava/lang/Boolean;",
     36         "Ljava/lang/Character;",
     37         "Ljava/lang/Float;",
     38         "Ljava/lang/Double;",
     39         "Ljava/lang/Byte;",
     40         "Ljava/lang/Short;",
     41         "Ljava/lang/Integer;",
     42         "Ljava/lang/Long;",
     43         NULL
     44     };
     45     const char** ccp;
     46 
     47     for (ccp = classes; *ccp != NULL; ccp++) {
     48         ClassObject* clazz;
     49 
     50         clazz = dvmFindClassNoInit(*ccp, NULL);
     51         if (clazz == NULL) {
     52             ALOGE("Couldn't find '%s'", *ccp);
     53             return false;
     54         }
     55 
     56         if (clazz->ifieldCount != 1) {
     57             ALOGE("Found %d instance fields in '%s'",
     58                 clazz->ifieldCount, *ccp);
     59             return false;
     60         }
     61     }
     62 
     63     return true;
     64 }
     65 
     66 
     67 /*
     68  * Find the named class object.  We have to trim "*pSignature" down to just
     69  * the first token, do the lookup, and then restore anything important
     70  * that we've stomped on.
     71  *
     72  * "pSig" will be advanced to the start of the next token.
     73  */
     74 static ClassObject* convertSignaturePartToClass(char** pSignature,
     75     const ClassObject* defClass)
     76 {
     77     ClassObject* clazz = NULL;
     78     char* signature = *pSignature;
     79 
     80     if (*signature == '[') {
     81         /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */
     82         char savedChar;
     83 
     84         while (*++signature == '[')
     85             ;
     86         if (*signature == 'L') {
     87             while (*++signature != ';')
     88                 ;
     89         }
     90 
     91         /* advance past ';', and stomp on whatever comes next */
     92         savedChar = *++signature;
     93         *signature = '\0';
     94         clazz = dvmFindArrayClass(*pSignature, defClass->classLoader);
     95         *signature = savedChar;
     96     } else if (*signature == 'L') {
     97         /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */
     98         char savedChar;
     99         while (*++signature != ';')
    100             ;
    101         savedChar = *++signature;
    102         *signature = '\0';
    103         clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader);
    104         *signature = savedChar;
    105     } else {
    106         clazz = dvmFindPrimitiveClass(*signature++);
    107     }
    108 
    109     if (clazz == NULL) {
    110         ALOGW("Unable to match class for part: '%s'", *pSignature);
    111     }
    112     *pSignature = signature;
    113     return clazz;
    114 }
    115 
    116 /*
    117  * Convert the method signature to an array of classes.
    118  *
    119  * The tokenization process may mangle "*pSignature".  On return, it will
    120  * be pointing at the closing ')'.
    121  *
    122  * "defClass" is the method's class, which is needed to make class loaders
    123  * happy.
    124  */
    125 static ArrayObject* convertSignatureToClassArray(char** pSignature,
    126     ClassObject* defClass)
    127 {
    128     char* signature = *pSignature;
    129 
    130     assert(*signature == '(');
    131     signature++;
    132 
    133     /* count up the number of parameters */
    134     size_t count = 0;
    135     char* cp = signature;
    136     while (*cp != ')') {
    137         count++;
    138 
    139         if (*cp == '[') {
    140             while (*++cp == '[')
    141                 ;
    142         }
    143         if (*cp == 'L') {
    144             while (*++cp != ';')
    145                 ;
    146         }
    147         cp++;
    148     }
    149     LOGVV("REFLECT found %d parameters in '%s'", count, *pSignature);
    150 
    151     /* create an array to hold them */
    152     ArrayObject* classArray = dvmAllocArrayByClass(gDvm.classJavaLangClassArray,
    153                      count, ALLOC_DEFAULT);
    154     if (classArray == NULL)
    155         return NULL;
    156 
    157     /* fill it in */
    158     cp = signature;
    159     for (size_t i = 0; i < count; i++) {
    160         ClassObject* clazz = convertSignaturePartToClass(&cp, defClass);
    161         if (clazz == NULL) {
    162             assert(dvmCheckException(dvmThreadSelf()));
    163             return NULL;
    164         }
    165         LOGVV("REFLECT  %d: '%s'", i, clazz->descriptor);
    166         dvmSetObjectArrayElement(classArray, i, (Object *)clazz);
    167     }
    168 
    169     *pSignature = cp;
    170 
    171     /* caller must call dvmReleaseTrackedAlloc */
    172     return classArray;
    173 }
    174 
    175 
    176 /*
    177  * Convert a field pointer to a slot number.
    178  *
    179  * We use positive values starting from 0 for instance fields, negative
    180  * values starting from -1 for static fields.
    181  */
    182 static int fieldToSlot(const Field* field, const ClassObject* clazz)
    183 {
    184     int slot;
    185 
    186     if (dvmIsStaticField(field)) {
    187         slot = (StaticField*)field - &clazz->sfields[0];
    188         assert(slot >= 0 && slot < clazz->sfieldCount);
    189         slot = -(slot+1);
    190     } else {
    191         slot = (InstField*)field - clazz->ifields;
    192         assert(slot >= 0 && slot < clazz->ifieldCount);
    193     }
    194 
    195     return slot;
    196 }
    197 
    198 /*
    199  * Convert a slot number to a field pointer.
    200  */
    201 Field* dvmSlotToField(ClassObject* clazz, int slot)
    202 {
    203     if (slot < 0) {
    204         slot = -(slot+1);
    205         assert(slot < clazz->sfieldCount);
    206         return (Field*)(void*)&clazz->sfields[slot];
    207     } else {
    208         assert(slot < clazz->ifieldCount);
    209         return (Field*)(void*)&clazz->ifields[slot];
    210     }
    211 }
    212 
    213 /*
    214  * Create a new java.lang.reflect.Field object from "field".
    215  *
    216  * The Field spec doesn't specify the constructor.  We're going to use the
    217  * one from our existing class libs:
    218  *
    219  *  private Field(Class declaringClass, Class type, String name, int slot)
    220  */
    221 static Object* createFieldObject(Field* field, const ClassObject* clazz)
    222 {
    223     Object* result = NULL;
    224     Object* fieldObj = NULL;
    225     StringObject* nameObj = NULL;
    226     ClassObject* type;
    227     char* mangle;
    228     char* cp;
    229     int slot, field_idx;
    230 
    231     assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField));
    232 
    233     fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT);
    234     if (fieldObj == NULL)
    235         goto bail;
    236 
    237     cp = mangle = strdup(field->signature);
    238     type = convertSignaturePartToClass(&cp, clazz);
    239     free(mangle);
    240     if (type == NULL)
    241         goto bail;
    242 
    243     nameObj = dvmCreateStringFromCstr(field->name);
    244     if (nameObj == NULL)
    245         goto bail;
    246 
    247     slot = fieldToSlot(field, clazz);
    248     field_idx = dvmGetFieldIdx(field);
    249 
    250     JValue unused;
    251     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init,
    252         fieldObj, &unused, clazz, type, nameObj, slot, field_idx);
    253     if (dvmCheckException(dvmThreadSelf())) {
    254         ALOGD("Field class init threw exception");
    255         goto bail;
    256     }
    257 
    258     result = fieldObj;
    259 
    260 bail:
    261     dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
    262     if (result == NULL)
    263         dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
    264     /* caller must dvmReleaseTrackedAlloc(result) */
    265     return result;
    266 }
    267 
    268 /*
    269  *
    270  * Get an array with all fields declared by a class.
    271  *
    272  * This includes both static and instance fields.
    273  */
    274 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
    275 {
    276     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
    277         dvmInitClass(gDvm.classJavaLangReflectField);
    278 
    279     /* count #of fields */
    280     size_t count;
    281     if (!publicOnly)
    282         count = clazz->sfieldCount + clazz->ifieldCount;
    283     else {
    284         count = 0;
    285         for (int i = 0; i < clazz->sfieldCount; i++) {
    286             if ((clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
    287                 count++;
    288         }
    289         for (int i = 0; i < clazz->ifieldCount; i++) {
    290             if ((clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
    291                 count++;
    292         }
    293     }
    294 
    295     /* create the Field[] array */
    296     ArrayObject* fieldArray =
    297         dvmAllocArrayByClass(gDvm.classJavaLangReflectFieldArray, count, ALLOC_DEFAULT);
    298     if (fieldArray == NULL)
    299         return NULL;
    300 
    301     /* populate */
    302     size_t fieldCount = 0;
    303     for (int i = 0; i < clazz->sfieldCount; i++) {
    304         if (!publicOnly ||
    305             (clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
    306         {
    307             Object* field = createFieldObject(&clazz->sfields[i], clazz);
    308             if (field == NULL) {
    309                 goto fail;
    310             }
    311             dvmSetObjectArrayElement(fieldArray, fieldCount, field);
    312             dvmReleaseTrackedAlloc(field, NULL);
    313             ++fieldCount;
    314         }
    315     }
    316     for (int i = 0; i < clazz->ifieldCount; i++) {
    317         if (!publicOnly ||
    318             (clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
    319         {
    320             Object* field = createFieldObject(&clazz->ifields[i], clazz);
    321             if (field == NULL) {
    322                 goto fail;
    323             }
    324             dvmSetObjectArrayElement(fieldArray, fieldCount, field);
    325             dvmReleaseTrackedAlloc(field, NULL);
    326             ++fieldCount;
    327         }
    328     }
    329 
    330     assert(fieldCount == fieldArray->length);
    331 
    332     /* caller must call dvmReleaseTrackedAlloc */
    333     return fieldArray;
    334 
    335 fail:
    336     dvmReleaseTrackedAlloc((Object*) fieldArray, NULL);
    337     return NULL;
    338 }
    339 
    340 
    341 /*
    342  * Convert a method pointer to a slot number.
    343  *
    344  * We use positive values starting from 0 for virtual methods, negative
    345  * values starting from -1 for static methods.
    346  */
    347 static int methodToSlot(const Method* meth)
    348 {
    349     ClassObject* clazz = meth->clazz;
    350     int slot;
    351 
    352     if (dvmIsDirectMethod(meth)) {
    353         slot = meth - clazz->directMethods;
    354         assert(slot >= 0 && slot < clazz->directMethodCount);
    355         slot = -(slot+1);
    356     } else {
    357         slot = meth - clazz->virtualMethods;
    358         assert(slot >= 0 && slot < clazz->virtualMethodCount);
    359     }
    360 
    361     return slot;
    362 }
    363 
    364 /*
    365  * Convert a slot number to a method pointer.
    366  */
    367 Method* dvmSlotToMethod(ClassObject* clazz, int slot)
    368 {
    369     if (slot < 0) {
    370         slot = -(slot+1);
    371         assert(slot < clazz->directMethodCount);
    372         return &clazz->directMethods[slot];
    373     } else {
    374         assert(slot < clazz->virtualMethodCount);
    375         return &clazz->virtualMethods[slot];
    376     }
    377 }
    378 
    379 /*
    380  * Create a new java/lang/reflect/Constructor object, using the contents of
    381  * "meth" to construct it.
    382  *
    383  * The spec doesn't specify the constructor.  We're going to use the
    384  * one from our existing class libs:
    385  *
    386  *  private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes,
    387  *      int slot)
    388  */
    389 static Object* createConstructorObject(Method* meth)
    390 {
    391     Object* result = NULL;
    392     ArrayObject* params = NULL;
    393     ArrayObject* exceptions = NULL;
    394     Object* consObj;
    395     DexStringCache mangle;
    396     char* cp;
    397     int slot, method_idx;
    398 
    399     dexStringCacheInit(&mangle);
    400 
    401     /* parent should guarantee init so we don't have to check on every call */
    402     assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor));
    403 
    404     consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor,
    405                 ALLOC_DEFAULT);
    406     if (consObj == NULL)
    407         goto bail;
    408 
    409     /*
    410      * Convert the signature string into an array of classes representing
    411      * the arguments.
    412      */
    413     cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
    414     params = convertSignatureToClassArray(&cp, meth->clazz);
    415     if (params == NULL)
    416         goto bail;
    417     assert(*cp == ')');
    418     assert(*(cp+1) == 'V');
    419 
    420     /*
    421      * Create an array with one entry for every exception that the class
    422      * is declared to throw.
    423      */
    424     exceptions = dvmGetMethodThrows(meth);
    425     if (dvmCheckException(dvmThreadSelf()))
    426         goto bail;
    427 
    428     slot = methodToSlot(meth);
    429     method_idx = dvmGetMethodIdx(meth);
    430 
    431     JValue unused;
    432     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init,
    433         consObj, &unused, meth->clazz, params, exceptions, slot, method_idx);
    434     if (dvmCheckException(dvmThreadSelf())) {
    435         ALOGD("Constructor class init threw exception");
    436         goto bail;
    437     }
    438 
    439     result = consObj;
    440 
    441 bail:
    442     dexStringCacheRelease(&mangle);
    443     dvmReleaseTrackedAlloc((Object*) params, NULL);
    444     dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
    445     if (result == NULL) {
    446         assert(dvmCheckException(dvmThreadSelf()));
    447         dvmReleaseTrackedAlloc(consObj, NULL);
    448     }
    449     /* caller must dvmReleaseTrackedAlloc(result) */
    450     return result;
    451 }
    452 
    453 /*
    454  * Get an array with all constructors declared by a class.
    455  */
    456 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
    457 {
    458     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
    459         dvmInitClass(gDvm.classJavaLangReflectConstructor);
    460 
    461     /*
    462      * Ordinarily we init the class the first time we resolve a method.
    463      * We're bypassing the normal resolution mechanism, so we init it here.
    464      */
    465     if (!dvmIsClassInitialized(clazz))
    466         dvmInitClass(clazz);
    467 
    468     /*
    469      * Count up the #of relevant methods.
    470      */
    471     size_t count = 0;
    472     for (int i = 0; i < clazz->directMethodCount; ++i) {
    473         Method* meth = &clazz->directMethods[i];
    474         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    475             dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
    476         {
    477             count++;
    478         }
    479     }
    480 
    481     /*
    482      * Create an array of Constructor objects.
    483      */
    484     ClassObject* arrayClass = gDvm.classJavaLangReflectConstructorArray;
    485     ArrayObject* ctorArray = dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
    486     if (ctorArray == NULL)
    487         return NULL;
    488 
    489     /*
    490      * Fill out the array.
    491      */
    492     size_t ctorObjCount = 0;
    493     for (int i = 0; i < clazz->directMethodCount; ++i) {
    494         Method* meth = &clazz->directMethods[i];
    495         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    496             dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
    497         {
    498             Object* ctorObj = createConstructorObject(meth);
    499             if (ctorObj == NULL) {
    500               dvmReleaseTrackedAlloc((Object*) ctorArray, NULL);
    501               return NULL;
    502             }
    503             dvmSetObjectArrayElement(ctorArray, ctorObjCount, ctorObj);
    504             ++ctorObjCount;
    505             dvmReleaseTrackedAlloc(ctorObj, NULL);
    506         }
    507     }
    508 
    509     assert(ctorObjCount == ctorArray->length);
    510 
    511     /* caller must call dvmReleaseTrackedAlloc */
    512     return ctorArray;
    513 }
    514 
    515 /*
    516  * Create a new java/lang/reflect/Method object, using the contents of
    517  * "meth" to construct it.
    518  *
    519  * The spec doesn't specify the constructor.  We're going to use the
    520  * one from our existing class libs:
    521  *
    522  *  private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes,
    523  *      Class returnType, String name, int slot)
    524  *
    525  * The caller must call dvmReleaseTrackedAlloc() on the result.
    526  */
    527 Object* dvmCreateReflectMethodObject(const Method* meth)
    528 {
    529     Object* result = NULL;
    530     ArrayObject* params = NULL;
    531     ArrayObject* exceptions = NULL;
    532     StringObject* nameObj = NULL;
    533     Object* methObj;
    534     ClassObject* returnType;
    535     DexStringCache mangle;
    536     char* cp;
    537     int slot, method_idx;
    538 
    539     if (dvmCheckException(dvmThreadSelf())) {
    540         ALOGW("WARNING: dvmCreateReflectMethodObject called with "
    541              "exception pending");
    542         return NULL;
    543     }
    544 
    545     dexStringCacheInit(&mangle);
    546 
    547     /* parent should guarantee init so we don't have to check on every call */
    548     assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod));
    549 
    550     methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT);
    551     if (methObj == NULL)
    552         goto bail;
    553 
    554     /*
    555      * Convert the signature string into an array of classes representing
    556      * the arguments, and a class for the return type.
    557      */
    558     cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
    559     params = convertSignatureToClassArray(&cp, meth->clazz);
    560     if (params == NULL)
    561         goto bail;
    562     assert(*cp == ')');
    563     cp++;
    564     returnType = convertSignaturePartToClass(&cp, meth->clazz);
    565     if (returnType == NULL)
    566         goto bail;
    567 
    568     /*
    569      * Create an array with one entry for every exception that the class
    570      * is declared to throw.
    571      */
    572     exceptions = dvmGetMethodThrows(meth);
    573     if (dvmCheckException(dvmThreadSelf()))
    574         goto bail;
    575 
    576     /* method name */
    577     nameObj = dvmCreateStringFromCstr(meth->name);
    578     if (nameObj == NULL)
    579         goto bail;
    580 
    581     slot = methodToSlot(meth);
    582     method_idx = dvmGetMethodIdx(meth);
    583 
    584     JValue unused;
    585     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init,
    586         methObj, &unused, meth->clazz, params, exceptions, returnType,
    587         nameObj, slot, method_idx);
    588     if (dvmCheckException(dvmThreadSelf())) {
    589         ALOGD("Method class init threw exception");
    590         goto bail;
    591     }
    592 
    593     result = methObj;
    594 
    595 bail:
    596     dexStringCacheRelease(&mangle);
    597     if (result == NULL) {
    598         assert(dvmCheckException(dvmThreadSelf()));
    599     }
    600     dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
    601     dvmReleaseTrackedAlloc((Object*) params, NULL);
    602     dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
    603     if (result == NULL)
    604         dvmReleaseTrackedAlloc(methObj, NULL);
    605     return result;
    606 }
    607 
    608 /*
    609  * Get an array with all methods declared by a class.
    610  *
    611  * This includes both static and virtual methods, and can include private
    612  * members if "publicOnly" is false.  It does not include Miranda methods,
    613  * since those weren't declared in the class, or constructors.
    614  */
    615 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
    616 {
    617     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
    618         dvmInitClass(gDvm.classJavaLangReflectMethod);
    619 
    620     /*
    621      * Count up the #of relevant methods.
    622      *
    623      * Ignore virtual Miranda methods and direct class/object constructors.
    624      */
    625     size_t count = 0;
    626     Method* meth = clazz->virtualMethods;
    627     for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
    628         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    629             !dvmIsMirandaMethod(meth))
    630         {
    631             count++;
    632         }
    633     }
    634     meth = clazz->directMethods;
    635     for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
    636         if ((!publicOnly || dvmIsPublicMethod(meth)) && meth->name[0] != '<') {
    637             count++;
    638         }
    639     }
    640 
    641     /*
    642      * Create an array of Method objects.
    643      */
    644     ArrayObject* methodArray =
    645         dvmAllocArrayByClass(gDvm.classJavaLangReflectMethodArray, count, ALLOC_DEFAULT);
    646     if (methodArray == NULL)
    647         return NULL;
    648 
    649     /*
    650      * Fill out the array.
    651      */
    652     meth = clazz->virtualMethods;
    653     size_t methObjCount = 0;
    654     for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
    655         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    656             !dvmIsMirandaMethod(meth))
    657         {
    658             Object* methObj = dvmCreateReflectMethodObject(meth);
    659             if (methObj == NULL)
    660                 goto fail;
    661             dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
    662             ++methObjCount;
    663             dvmReleaseTrackedAlloc(methObj, NULL);
    664         }
    665     }
    666     meth = clazz->directMethods;
    667     for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
    668         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    669             meth->name[0] != '<')
    670         {
    671             Object* methObj = dvmCreateReflectMethodObject(meth);
    672             if (methObj == NULL)
    673                 goto fail;
    674             dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
    675             ++methObjCount;
    676             dvmReleaseTrackedAlloc(methObj, NULL);
    677         }
    678     }
    679 
    680     assert(methObjCount == methodArray->length);
    681 
    682     /* caller must call dvmReleaseTrackedAlloc */
    683     return methodArray;
    684 
    685 fail:
    686     dvmReleaseTrackedAlloc((Object*) methodArray, NULL);
    687     return NULL;
    688 }
    689 
    690 /*
    691  * Fills targetDescriptorCache with the descriptors of the classes in args.
    692  * This is the concatenation of the descriptors with no other adornment,
    693  * consistent with dexProtoGetParameterDescriptors.
    694  */
    695 static void createTargetDescriptor(ArrayObject* args,
    696     DexStringCache* targetDescriptorCache)
    697 {
    698     ClassObject** argsArray = (ClassObject**)(void*)args->contents;
    699     size_t length = 1; /* +1 for the terminating '\0' */
    700     for (size_t i = 0; i < args->length; ++i) {
    701         length += strlen(argsArray[i]->descriptor);
    702     }
    703 
    704     dexStringCacheAlloc(targetDescriptorCache, length);
    705 
    706     char* at = (char*) targetDescriptorCache->value;
    707     for (size_t i = 0; i < args->length; ++i) {
    708         const char* descriptor = argsArray[i]->descriptor;
    709         strcpy(at, descriptor);
    710         at += strlen(descriptor);
    711     }
    712 }
    713 
    714 static Object* findConstructorOrMethodInArray(int methodsCount, Method* methods,
    715     const char* name, const char* parameterDescriptors)
    716 {
    717     Method* method = NULL;
    718     Method* result = NULL;
    719     int i;
    720 
    721     for (i = 0; i < methodsCount; ++i) {
    722         method = &methods[i];
    723         if (strcmp(name, method->name) != 0
    724             || dvmIsMirandaMethod(method)
    725             || dexProtoCompareToParameterDescriptors(&method->prototype,
    726                     parameterDescriptors) != 0) {
    727             continue;
    728         }
    729 
    730         result = method;
    731 
    732         /*
    733          * Covariant return types permit the class to define multiple
    734          * methods with the same name and parameter types. Prefer to return
    735          * a non-synthetic method in such situations. We may still return
    736          * a synthetic method to handle situations like escalated visibility.
    737          */
    738         if (!dvmIsSyntheticMethod(method)) {
    739             break;
    740         }
    741     }
    742 
    743     if (result != NULL) {
    744         return dvmCreateReflectObjForMethod(result->clazz, result);
    745     }
    746 
    747     return NULL;
    748 }
    749 
    750 /*
    751  * Get the named method.
    752  */
    753 Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
    754     StringObject* nameObj, ArrayObject* args)
    755 {
    756     Object* result = NULL;
    757     DexStringCache targetDescriptorCache;
    758     char* name;
    759     const char* targetDescriptor;
    760 
    761     dexStringCacheInit(&targetDescriptorCache);
    762 
    763     name = dvmCreateCstrFromString(nameObj);
    764     createTargetDescriptor(args, &targetDescriptorCache);
    765     targetDescriptor = targetDescriptorCache.value;
    766 
    767     result = findConstructorOrMethodInArray(clazz->directMethodCount,
    768         clazz->directMethods, name, targetDescriptor);
    769     if (result == NULL) {
    770         result = findConstructorOrMethodInArray(clazz->virtualMethodCount,
    771             clazz->virtualMethods, name, targetDescriptor);
    772     }
    773 
    774     free(name);
    775     dexStringCacheRelease(&targetDescriptorCache);
    776     return result;
    777 }
    778 
    779 /*
    780  * Get the named field.
    781  */
    782 Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj)
    783 {
    784     int i;
    785     Object* fieldObj = NULL;
    786     char* name = dvmCreateCstrFromString(nameObj);
    787 
    788     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
    789         dvmInitClass(gDvm.classJavaLangReflectField);
    790 
    791     for (i = 0; i < clazz->sfieldCount; i++) {
    792         Field* field = &clazz->sfields[i];
    793         if (strcmp(name, field->name) == 0) {
    794             fieldObj = createFieldObject(field, clazz);
    795             break;
    796         }
    797     }
    798     if (fieldObj == NULL) {
    799         for (i = 0; i < clazz->ifieldCount; i++) {
    800             Field* field = &clazz->ifields[i];
    801             if (strcmp(name, field->name) == 0) {
    802                 fieldObj = createFieldObject(field, clazz);
    803                 break;
    804             }
    805         }
    806     }
    807 
    808     free(name);
    809     return fieldObj;
    810 }
    811 
    812 /*
    813  * Get all interfaces a class implements. If this is unable to allocate
    814  * the result array, this raises an OutOfMemoryError and returns NULL.
    815  */
    816 ArrayObject* dvmGetInterfaces(ClassObject* clazz)
    817 {
    818     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
    819         dvmInitClass(gDvm.classJavaLangReflectMethod);
    820 
    821     /*
    822      * Create an array of Class objects.
    823      */
    824     size_t count = clazz->interfaceCount;
    825     ArrayObject* interfaceArray =
    826         dvmAllocArrayByClass(gDvm.classJavaLangClassArray, count, ALLOC_DEFAULT);
    827     if (interfaceArray == NULL)
    828         return NULL;
    829 
    830     /*
    831      * Fill out the array.
    832      */
    833     memcpy(interfaceArray->contents, clazz->interfaces,
    834            count * sizeof(Object *));
    835     dvmWriteBarrierArray(interfaceArray, 0, count);
    836 
    837     /* caller must call dvmReleaseTrackedAlloc */
    838     return interfaceArray;
    839 }
    840 
    841 /*
    842  * Given a boxed primitive type, such as java/lang/Integer, return the
    843  * primitive type index.
    844  *
    845  * Returns PRIM_NOT for void, since we never "box" that.
    846  */
    847 static PrimitiveType getBoxedType(DataObject* arg)
    848 {
    849     static const int kJavaLangLen = 11;     // strlen("Ljava/lang/")
    850 
    851     if (arg == NULL)
    852         return PRIM_NOT;
    853 
    854     const char* name = arg->clazz->descriptor;
    855 
    856     if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0)
    857         return PRIM_NOT;
    858 
    859     if (strcmp(name + kJavaLangLen, "Boolean;") == 0)
    860         return PRIM_BOOLEAN;
    861     if (strcmp(name + kJavaLangLen, "Character;") == 0)
    862         return PRIM_CHAR;
    863     if (strcmp(name + kJavaLangLen, "Float;") == 0)
    864         return PRIM_FLOAT;
    865     if (strcmp(name + kJavaLangLen, "Double;") == 0)
    866         return PRIM_DOUBLE;
    867     if (strcmp(name + kJavaLangLen, "Byte;") == 0)
    868         return PRIM_BYTE;
    869     if (strcmp(name + kJavaLangLen, "Short;") == 0)
    870         return PRIM_SHORT;
    871     if (strcmp(name + kJavaLangLen, "Integer;") == 0)
    872         return PRIM_INT;
    873     if (strcmp(name + kJavaLangLen, "Long;") == 0)
    874         return PRIM_LONG;
    875     return PRIM_NOT;
    876 }
    877 
    878 /*
    879  * Convert primitive, boxed data from "srcPtr" to "dstPtr".
    880  *
    881  * Section v2 2.6 lists the various conversions and promotions.  We
    882  * allow the "widening" and "identity" conversions, but don't allow the
    883  * "narrowing" conversions.
    884  *
    885  * Allowed:
    886  *  byte to short, int, long, float, double
    887  *  short to int, long, float double
    888  *  char to int, long, float, double
    889  *  int to long, float, double
    890  *  long to float, double
    891  *  float to double
    892  * Values of types byte, char, and short are "internally" widened to int.
    893  *
    894  * Returns the width in 32-bit words of the destination primitive, or
    895  * -1 if the conversion is not allowed.
    896  *
    897  * TODO? use JValue rather than u4 pointers
    898  */
    899 int dvmConvertPrimitiveValue(PrimitiveType srcType,
    900     PrimitiveType dstType, const s4* srcPtr, s4* dstPtr)
    901 {
    902     enum Conversion {
    903         OK4, OK8, ItoJ, ItoD, JtoD, FtoD, ItoF, JtoF, bad
    904     };
    905 
    906     enum Conversion conv;
    907 #ifdef ARCH_HAVE_ALIGNED_DOUBLES
    908     double ret;
    909 #endif
    910 
    911     assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT));
    912     assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT));
    913 
    914     switch (dstType) {
    915         case PRIM_BOOLEAN:
    916         case PRIM_CHAR:
    917         case PRIM_BYTE: {
    918             conv = (srcType == dstType) ? OK4 : bad;
    919             break;
    920         }
    921         case PRIM_SHORT: {
    922             switch (srcType) {
    923                 case PRIM_BYTE:
    924                 case PRIM_SHORT: conv = OK4; break;
    925                 default:         conv = bad; break;
    926             }
    927             break;
    928         }
    929         case PRIM_INT: {
    930             switch (srcType) {
    931                 case PRIM_BYTE:
    932                 case PRIM_CHAR:
    933                 case PRIM_SHORT:
    934                 case PRIM_INT:   conv = OK4; break;
    935                 default:         conv = bad; break;
    936             }
    937             break;
    938         }
    939         case PRIM_LONG: {
    940             switch (srcType) {
    941                 case PRIM_BYTE:
    942                 case PRIM_CHAR:
    943                 case PRIM_SHORT:
    944                 case PRIM_INT:   conv = ItoJ; break;
    945                 case PRIM_LONG:  conv = OK8;  break;
    946                 default:         conv = bad;  break;
    947             }
    948             break;
    949         }
    950         case PRIM_FLOAT: {
    951             switch (srcType) {
    952                 case PRIM_BYTE:
    953                 case PRIM_CHAR:
    954                 case PRIM_SHORT:
    955                 case PRIM_INT:   conv = ItoF; break;
    956                 case PRIM_LONG:  conv = JtoF; break;
    957                 case PRIM_FLOAT: conv = OK4;  break;
    958                 default:         conv = bad;  break;
    959             }
    960             break;
    961         }
    962         case PRIM_DOUBLE: {
    963             switch (srcType) {
    964                 case PRIM_BYTE:
    965                 case PRIM_CHAR:
    966                 case PRIM_SHORT:
    967                 case PRIM_INT:    conv = ItoD; break;
    968                 case PRIM_LONG:   conv = JtoD; break;
    969                 case PRIM_FLOAT:  conv = FtoD; break;
    970                 case PRIM_DOUBLE: conv = OK8;  break;
    971                 default:          conv = bad;  break;
    972             }
    973             break;
    974         }
    975         case PRIM_VOID:
    976         case PRIM_NOT:
    977         default: {
    978             conv = bad;
    979             break;
    980         }
    981     }
    982 
    983     switch (conv) {
    984         case OK4:  *dstPtr = *srcPtr;                                   return 1;
    985         case OK8:  *(s8*) dstPtr = *(s8*)srcPtr;                        return 2;
    986         case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr);                return 2;
    987 #ifndef ARCH_HAVE_ALIGNED_DOUBLES
    988         case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr);        return 2;
    989         case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2;
    990         case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr);     return 2;
    991 #else
    992         case ItoD: ret = (double) (*(s4*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
    993         case JtoD: ret = (double) (*(long long*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
    994         case FtoD: ret = (double) (*(float*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
    995 #endif
    996         case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr);         return 1;
    997         case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr);   return 1;
    998         case bad: {
    999             ALOGV("illegal primitive conversion: '%s' to '%s'",
   1000                     dexGetPrimitiveTypeDescriptor(srcType),
   1001                     dexGetPrimitiveTypeDescriptor(dstType));
   1002             return -1;
   1003         }
   1004         default: {
   1005             dvmAbort();
   1006             return -1; // Keep the compiler happy.
   1007         }
   1008     }
   1009 }
   1010 
   1011 /*
   1012  * Convert types and widen primitives.  Puts the value of "arg" into
   1013  * "destPtr".
   1014  *
   1015  * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error.
   1016  */
   1017 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr)
   1018 {
   1019     int retVal;
   1020 
   1021     if (dvmIsPrimitiveClass(type)) {
   1022         /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */
   1023         PrimitiveType srcType;
   1024         s4* valuePtr;
   1025 
   1026         srcType = getBoxedType(arg);
   1027         if (srcType == PRIM_NOT) {     // didn't pass a boxed primitive in
   1028             LOGVV("conv arg: type '%s' not boxed primitive",
   1029                 arg->clazz->descriptor);
   1030             return -1;
   1031         }
   1032 
   1033         /* assumes value is stored in first instance field */
   1034         valuePtr = (s4*) arg->instanceData;
   1035 
   1036         retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType,
   1037                     valuePtr, destPtr);
   1038     } else {
   1039         /* verify object is compatible */
   1040         if ((arg == NULL) || dvmInstanceof(arg->clazz, type)) {
   1041             *destPtr = (s4) arg;
   1042             retVal = 1;
   1043         } else {
   1044             LOGVV("Arg %p (%s) not compatible with %s",
   1045                 arg, arg->clazz->descriptor, type->descriptor);
   1046             retVal = -1;
   1047         }
   1048     }
   1049 
   1050     return retVal;
   1051 }
   1052 
   1053 /*
   1054  * Create a wrapper object for a primitive data type.  If "returnType" is
   1055  * not primitive, this just casts "value" to an object and returns it.
   1056  *
   1057  * We could invoke the "toValue" method on the box types to take
   1058  * advantage of pre-created values, but running that through the
   1059  * interpreter is probably less efficient than just allocating storage here.
   1060  *
   1061  * The caller must call dvmReleaseTrackedAlloc on the result.
   1062  */
   1063 DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType)
   1064 {
   1065     ClassObject* wrapperClass;
   1066     DataObject* wrapperObj;
   1067     s4* dataPtr;
   1068     PrimitiveType typeIndex = returnType->primitiveType;
   1069     const char* classDescriptor;
   1070 
   1071     if (typeIndex == PRIM_NOT) {
   1072         /* add to tracking table so return value is always in table */
   1073         if (value.l != NULL)
   1074             dvmAddTrackedAlloc((Object*)value.l, NULL);
   1075         return (DataObject*) value.l;
   1076     }
   1077 
   1078     classDescriptor = dexGetBoxedTypeDescriptor(typeIndex);
   1079     if (classDescriptor == NULL) {
   1080         return NULL;
   1081     }
   1082 
   1083     wrapperClass = dvmFindSystemClass(classDescriptor);
   1084     if (wrapperClass == NULL) {
   1085         ALOGW("Unable to find '%s'", classDescriptor);
   1086         assert(dvmCheckException(dvmThreadSelf()));
   1087         return NULL;
   1088     }
   1089 
   1090     wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT);
   1091     if (wrapperObj == NULL)
   1092         return NULL;
   1093     dataPtr = (s4*) wrapperObj->instanceData;
   1094 
   1095     /* assumes value is stored in first instance field */
   1096     /* (see dvmValidateBoxClasses) */
   1097     if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE)
   1098         *(s8*)dataPtr = value.j;
   1099     else
   1100         *dataPtr = value.i;
   1101 
   1102     return wrapperObj;
   1103 }
   1104 
   1105 /*
   1106  * Unwrap a primitive data type, if necessary.
   1107  *
   1108  * If "returnType" is not primitive, we just tuck "value" into JValue and
   1109  * return it after verifying that it's the right type of object.
   1110  *
   1111  * Fails if the field is primitive and "value" is either not a boxed
   1112  * primitive or is of a type that cannot be converted.
   1113  *
   1114  * Returns "true" on success, "false" on failure.
   1115  */
   1116 bool dvmUnboxPrimitive(Object* value, ClassObject* returnType,
   1117     JValue* pResult)
   1118 {
   1119     PrimitiveType typeIndex = returnType->primitiveType;
   1120     PrimitiveType valueIndex;
   1121 
   1122     if (typeIndex == PRIM_NOT) {
   1123         if (value != NULL && !dvmInstanceof(value->clazz, returnType)) {
   1124             ALOGD("wrong object type: %s %s",
   1125                 value->clazz->descriptor, returnType->descriptor);
   1126             return false;
   1127         }
   1128         pResult->l = value;
   1129         return true;
   1130     } else if (typeIndex == PRIM_VOID) {
   1131         /* can't put anything into a void */
   1132         return false;
   1133     }
   1134 
   1135     valueIndex = getBoxedType((DataObject*)value);
   1136     if (valueIndex == PRIM_NOT)
   1137         return false;
   1138 
   1139     /* assumes value is stored in first instance field of "value" */
   1140     /* (see dvmValidateBoxClasses) */
   1141     if (dvmConvertPrimitiveValue(valueIndex, typeIndex,
   1142             (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0)
   1143     {
   1144         ALOGV("Prim conversion failed");
   1145         return false;
   1146     }
   1147 
   1148     return true;
   1149 }
   1150 
   1151 
   1152 /*
   1153  * Find the return type in the signature, and convert it to a class
   1154  * object.  For primitive types we use a boxed class, for reference types
   1155  * we do a name lookup.
   1156  *
   1157  * On failure, we return NULL with an exception raised.
   1158  */
   1159 ClassObject* dvmGetBoxedReturnType(const Method* meth)
   1160 {
   1161     const char* sig = dexProtoGetReturnType(&meth->prototype);
   1162 
   1163     switch (*sig) {
   1164     case 'Z':
   1165     case 'C':
   1166     case 'F':
   1167     case 'D':
   1168     case 'B':
   1169     case 'S':
   1170     case 'I':
   1171     case 'J':
   1172     case 'V':
   1173         return dvmFindPrimitiveClass(*sig);
   1174     case '[':
   1175     case 'L':
   1176         return dvmFindClass(sig, meth->clazz->classLoader);
   1177     default: {
   1178         /* should not have passed verification */
   1179         char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   1180         ALOGE("Bad return type in signature '%s'", desc);
   1181         free(desc);
   1182         dvmThrowInternalError(NULL);
   1183         return NULL;
   1184     }
   1185     }
   1186 }
   1187 
   1188 
   1189 /*
   1190  * JNI reflection support: convert reflection object to Field ptr.
   1191  */
   1192 Field* dvmGetFieldFromReflectObj(Object* obj)
   1193 {
   1194     ClassObject* clazz;
   1195     int slot;
   1196 
   1197     assert(obj->clazz == gDvm.classJavaLangReflectField);
   1198     clazz = (ClassObject*)dvmGetFieldObject(obj,
   1199                                 gDvm.offJavaLangReflectField_declClass);
   1200     slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot);
   1201 
   1202     /* must initialize the class before returning a field ID */
   1203     if (!dvmInitClass(clazz))
   1204         return NULL;
   1205 
   1206     return dvmSlotToField(clazz, slot);
   1207 }
   1208 
   1209 /*
   1210  * JNI reflection support: convert reflection object to Method ptr.
   1211  */
   1212 Method* dvmGetMethodFromReflectObj(Object* obj)
   1213 {
   1214     ClassObject* clazz;
   1215     int slot;
   1216 
   1217     if (obj->clazz == gDvm.classJavaLangReflectConstructor) {
   1218         clazz = (ClassObject*)dvmGetFieldObject(obj,
   1219                                 gDvm.offJavaLangReflectConstructor_declClass);
   1220         slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot);
   1221     } else if (obj->clazz == gDvm.classJavaLangReflectMethod) {
   1222         clazz = (ClassObject*)dvmGetFieldObject(obj,
   1223                                 gDvm.offJavaLangReflectMethod_declClass);
   1224         slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot);
   1225     } else {
   1226         assert(false);
   1227         return NULL;
   1228     }
   1229 
   1230     /* must initialize the class before returning a method ID */
   1231     if (!dvmInitClass(clazz))
   1232         return NULL;
   1233 
   1234     return dvmSlotToMethod(clazz, slot);
   1235 }
   1236 
   1237 /*
   1238  * JNI reflection support: convert Field to reflection object.
   1239  *
   1240  * The return value is a java.lang.reflect.Field.
   1241  *
   1242  * Caller must call dvmReleaseTrackedAlloc().
   1243  */
   1244 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field)
   1245 {
   1246     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
   1247         dvmInitClass(gDvm.classJavaLangReflectField);
   1248 
   1249     /* caller must dvmReleaseTrackedAlloc(result) */
   1250     return createFieldObject(field, clazz);
   1251 }
   1252 
   1253 /*
   1254  * JNI reflection support: convert Method to reflection object.
   1255  *
   1256  * The returned object will be either a java.lang.reflect.Method or
   1257  * .Constructor, depending on whether "method" is a constructor.
   1258  *
   1259  * This is also used for certain "system" annotations.
   1260  *
   1261  * Caller must call dvmReleaseTrackedAlloc().
   1262  */
   1263 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method)
   1264 {
   1265     UNUSED_PARAMETER(clazz);
   1266 
   1267     if (strcmp(method->name, "<init>") == 0) {
   1268         if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
   1269             dvmInitClass(gDvm.classJavaLangReflectConstructor);
   1270 
   1271         return createConstructorObject(method);
   1272     } else {
   1273         if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
   1274             dvmInitClass(gDvm.classJavaLangReflectMethod);
   1275 
   1276         return dvmCreateReflectMethodObject(method);
   1277     }
   1278 }
   1279