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             LOGE("Couldn't find '%s'", *ccp);
     53             return false;
     54         }
     55 
     56         if (clazz->ifieldCount != 1) {
     57             LOGE("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         LOGW("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;
    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 
    249     JValue unused;
    250     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init,
    251         fieldObj, &unused, clazz, type, nameObj, slot);
    252     if (dvmCheckException(dvmThreadSelf())) {
    253         LOGD("Field class init threw exception");
    254         goto bail;
    255     }
    256 
    257     result = fieldObj;
    258 
    259 bail:
    260     dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
    261     if (result == NULL)
    262         dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
    263     /* caller must dvmReleaseTrackedAlloc(result) */
    264     return result;
    265 }
    266 
    267 /*
    268  *
    269  * Get an array with all fields declared by a class.
    270  *
    271  * This includes both static and instance fields.
    272  */
    273 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
    274 {
    275     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
    276         dvmInitClass(gDvm.classJavaLangReflectField);
    277 
    278     /* count #of fields */
    279     size_t count;
    280     if (!publicOnly)
    281         count = clazz->sfieldCount + clazz->ifieldCount;
    282     else {
    283         count = 0;
    284         for (int i = 0; i < clazz->sfieldCount; i++) {
    285             if ((clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
    286                 count++;
    287         }
    288         for (int i = 0; i < clazz->ifieldCount; i++) {
    289             if ((clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
    290                 count++;
    291         }
    292     }
    293 
    294     /* create the Field[] array */
    295     ArrayObject* fieldArray =
    296         dvmAllocArrayByClass(gDvm.classJavaLangReflectFieldArray, count, ALLOC_DEFAULT);
    297     if (fieldArray == NULL)
    298         return NULL;
    299 
    300     /* populate */
    301     size_t fieldCount = 0;
    302     for (int i = 0; i < clazz->sfieldCount; i++) {
    303         if (!publicOnly ||
    304             (clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
    305         {
    306             Object* field = createFieldObject(&clazz->sfields[i], clazz);
    307             if (field == NULL) {
    308                 goto fail;
    309             }
    310             dvmSetObjectArrayElement(fieldArray, fieldCount, field);
    311             dvmReleaseTrackedAlloc(field, NULL);
    312             ++fieldCount;
    313         }
    314     }
    315     for (int i = 0; i < clazz->ifieldCount; i++) {
    316         if (!publicOnly ||
    317             (clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
    318         {
    319             Object* field = createFieldObject(&clazz->ifields[i], clazz);
    320             if (field == NULL) {
    321                 goto fail;
    322             }
    323             dvmSetObjectArrayElement(fieldArray, fieldCount, field);
    324             dvmReleaseTrackedAlloc(field, NULL);
    325             ++fieldCount;
    326         }
    327     }
    328 
    329     assert(fieldCount == fieldArray->length);
    330 
    331     /* caller must call dvmReleaseTrackedAlloc */
    332     return fieldArray;
    333 
    334 fail:
    335     dvmReleaseTrackedAlloc((Object*) fieldArray, NULL);
    336     return NULL;
    337 }
    338 
    339 
    340 /*
    341  * Convert a method pointer to a slot number.
    342  *
    343  * We use positive values starting from 0 for virtual methods, negative
    344  * values starting from -1 for static methods.
    345  */
    346 static int methodToSlot(const Method* meth)
    347 {
    348     ClassObject* clazz = meth->clazz;
    349     int slot;
    350 
    351     if (dvmIsDirectMethod(meth)) {
    352         slot = meth - clazz->directMethods;
    353         assert(slot >= 0 && slot < clazz->directMethodCount);
    354         slot = -(slot+1);
    355     } else {
    356         slot = meth - clazz->virtualMethods;
    357         assert(slot >= 0 && slot < clazz->virtualMethodCount);
    358     }
    359 
    360     return slot;
    361 }
    362 
    363 /*
    364  * Convert a slot number to a method pointer.
    365  */
    366 Method* dvmSlotToMethod(ClassObject* clazz, int slot)
    367 {
    368     if (slot < 0) {
    369         slot = -(slot+1);
    370         assert(slot < clazz->directMethodCount);
    371         return &clazz->directMethods[slot];
    372     } else {
    373         assert(slot < clazz->virtualMethodCount);
    374         return &clazz->virtualMethods[slot];
    375     }
    376 }
    377 
    378 /*
    379  * Create a new java/lang/reflect/Constructor object, using the contents of
    380  * "meth" to construct it.
    381  *
    382  * The spec doesn't specify the constructor.  We're going to use the
    383  * one from our existing class libs:
    384  *
    385  *  private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes,
    386  *      int slot)
    387  */
    388 static Object* createConstructorObject(Method* meth)
    389 {
    390     Object* result = NULL;
    391     ArrayObject* params = NULL;
    392     ArrayObject* exceptions = NULL;
    393     Object* consObj;
    394     DexStringCache mangle;
    395     char* cp;
    396     int slot;
    397 
    398     dexStringCacheInit(&mangle);
    399 
    400     /* parent should guarantee init so we don't have to check on every call */
    401     assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor));
    402 
    403     consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor,
    404                 ALLOC_DEFAULT);
    405     if (consObj == NULL)
    406         goto bail;
    407 
    408     /*
    409      * Convert the signature string into an array of classes representing
    410      * the arguments.
    411      */
    412     cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
    413     params = convertSignatureToClassArray(&cp, meth->clazz);
    414     if (params == NULL)
    415         goto bail;
    416     assert(*cp == ')');
    417     assert(*(cp+1) == 'V');
    418 
    419     /*
    420      * Create an array with one entry for every exception that the class
    421      * is declared to throw.
    422      */
    423     exceptions = dvmGetMethodThrows(meth);
    424     if (dvmCheckException(dvmThreadSelf()))
    425         goto bail;
    426 
    427     slot = methodToSlot(meth);
    428 
    429     JValue unused;
    430     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init,
    431         consObj, &unused, meth->clazz, params, exceptions, slot);
    432     if (dvmCheckException(dvmThreadSelf())) {
    433         LOGD("Constructor class init threw exception");
    434         goto bail;
    435     }
    436 
    437     result = consObj;
    438 
    439 bail:
    440     dexStringCacheRelease(&mangle);
    441     dvmReleaseTrackedAlloc((Object*) params, NULL);
    442     dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
    443     if (result == NULL) {
    444         assert(dvmCheckException(dvmThreadSelf()));
    445         dvmReleaseTrackedAlloc(consObj, NULL);
    446     }
    447     /* caller must dvmReleaseTrackedAlloc(result) */
    448     return result;
    449 }
    450 
    451 /*
    452  * Get an array with all constructors declared by a class.
    453  */
    454 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
    455 {
    456     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
    457         dvmInitClass(gDvm.classJavaLangReflectConstructor);
    458 
    459     /*
    460      * Ordinarily we init the class the first time we resolve a method.
    461      * We're bypassing the normal resolution mechanism, so we init it here.
    462      */
    463     if (!dvmIsClassInitialized(clazz))
    464         dvmInitClass(clazz);
    465 
    466     /*
    467      * Count up the #of relevant methods.
    468      */
    469     size_t count = 0;
    470     for (int i = 0; i < clazz->directMethodCount; ++i) {
    471         Method* meth = &clazz->directMethods[i];
    472         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    473             dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
    474         {
    475             count++;
    476         }
    477     }
    478 
    479     /*
    480      * Create an array of Constructor objects.
    481      */
    482     ClassObject* arrayClass = gDvm.classJavaLangReflectConstructorArray;
    483     ArrayObject* ctorArray = dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
    484     if (ctorArray == NULL)
    485         return NULL;
    486 
    487     /*
    488      * Fill out the array.
    489      */
    490     size_t ctorObjCount = 0;
    491     for (int i = 0; i < clazz->directMethodCount; ++i) {
    492         Method* meth = &clazz->directMethods[i];
    493         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    494             dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
    495         {
    496             Object* ctorObj = createConstructorObject(meth);
    497             if (ctorObj == NULL) {
    498               dvmReleaseTrackedAlloc((Object*) ctorArray, NULL);
    499               return NULL;
    500             }
    501             dvmSetObjectArrayElement(ctorArray, ctorObjCount, ctorObj);
    502             ++ctorObjCount;
    503             dvmReleaseTrackedAlloc(ctorObj, NULL);
    504         }
    505     }
    506 
    507     assert(ctorObjCount == ctorArray->length);
    508 
    509     /* caller must call dvmReleaseTrackedAlloc */
    510     return ctorArray;
    511 }
    512 
    513 /*
    514  * Create a new java/lang/reflect/Method object, using the contents of
    515  * "meth" to construct it.
    516  *
    517  * The spec doesn't specify the constructor.  We're going to use the
    518  * one from our existing class libs:
    519  *
    520  *  private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes,
    521  *      Class returnType, String name, int slot)
    522  *
    523  * The caller must call dvmReleaseTrackedAlloc() on the result.
    524  */
    525 Object* dvmCreateReflectMethodObject(const Method* meth)
    526 {
    527     Object* result = NULL;
    528     ArrayObject* params = NULL;
    529     ArrayObject* exceptions = NULL;
    530     StringObject* nameObj = NULL;
    531     Object* methObj;
    532     ClassObject* returnType;
    533     DexStringCache mangle;
    534     char* cp;
    535     int slot;
    536 
    537     if (dvmCheckException(dvmThreadSelf())) {
    538         LOGW("WARNING: dvmCreateReflectMethodObject called with "
    539              "exception pending");
    540         return NULL;
    541     }
    542 
    543     dexStringCacheInit(&mangle);
    544 
    545     /* parent should guarantee init so we don't have to check on every call */
    546     assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod));
    547 
    548     methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT);
    549     if (methObj == NULL)
    550         goto bail;
    551 
    552     /*
    553      * Convert the signature string into an array of classes representing
    554      * the arguments, and a class for the return type.
    555      */
    556     cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
    557     params = convertSignatureToClassArray(&cp, meth->clazz);
    558     if (params == NULL)
    559         goto bail;
    560     assert(*cp == ')');
    561     cp++;
    562     returnType = convertSignaturePartToClass(&cp, meth->clazz);
    563     if (returnType == NULL)
    564         goto bail;
    565 
    566     /*
    567      * Create an array with one entry for every exception that the class
    568      * is declared to throw.
    569      */
    570     exceptions = dvmGetMethodThrows(meth);
    571     if (dvmCheckException(dvmThreadSelf()))
    572         goto bail;
    573 
    574     /* method name */
    575     nameObj = dvmCreateStringFromCstr(meth->name);
    576     if (nameObj == NULL)
    577         goto bail;
    578 
    579     slot = methodToSlot(meth);
    580 
    581     JValue unused;
    582     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init,
    583         methObj, &unused, meth->clazz, params, exceptions, returnType,
    584         nameObj, slot);
    585     if (dvmCheckException(dvmThreadSelf())) {
    586         LOGD("Method class init threw exception");
    587         goto bail;
    588     }
    589 
    590     result = methObj;
    591 
    592 bail:
    593     dexStringCacheRelease(&mangle);
    594     if (result == NULL) {
    595         assert(dvmCheckException(dvmThreadSelf()));
    596     }
    597     dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
    598     dvmReleaseTrackedAlloc((Object*) params, NULL);
    599     dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
    600     if (result == NULL)
    601         dvmReleaseTrackedAlloc(methObj, NULL);
    602     return result;
    603 }
    604 
    605 /*
    606  * Get an array with all methods declared by a class.
    607  *
    608  * This includes both static and virtual methods, and can include private
    609  * members if "publicOnly" is false.  It does not include Miranda methods,
    610  * since those weren't declared in the class, or constructors.
    611  */
    612 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
    613 {
    614     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
    615         dvmInitClass(gDvm.classJavaLangReflectMethod);
    616 
    617     /*
    618      * Count up the #of relevant methods.
    619      *
    620      * Ignore virtual Miranda methods and direct class/object constructors.
    621      */
    622     size_t count = 0;
    623     Method* meth = clazz->virtualMethods;
    624     for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
    625         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    626             !dvmIsMirandaMethod(meth))
    627         {
    628             count++;
    629         }
    630     }
    631     meth = clazz->directMethods;
    632     for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
    633         if ((!publicOnly || dvmIsPublicMethod(meth)) && meth->name[0] != '<') {
    634             count++;
    635         }
    636     }
    637 
    638     /*
    639      * Create an array of Method objects.
    640      */
    641     ArrayObject* methodArray =
    642         dvmAllocArrayByClass(gDvm.classJavaLangReflectMethodArray, count, ALLOC_DEFAULT);
    643     if (methodArray == NULL)
    644         return NULL;
    645 
    646     /*
    647      * Fill out the array.
    648      */
    649     meth = clazz->virtualMethods;
    650     size_t methObjCount = 0;
    651     for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
    652         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    653             !dvmIsMirandaMethod(meth))
    654         {
    655             Object* methObj = dvmCreateReflectMethodObject(meth);
    656             if (methObj == NULL)
    657                 goto fail;
    658             dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
    659             ++methObjCount;
    660             dvmReleaseTrackedAlloc(methObj, NULL);
    661         }
    662     }
    663     meth = clazz->directMethods;
    664     for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
    665         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
    666             meth->name[0] != '<')
    667         {
    668             Object* methObj = dvmCreateReflectMethodObject(meth);
    669             if (methObj == NULL)
    670                 goto fail;
    671             dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
    672             ++methObjCount;
    673             dvmReleaseTrackedAlloc(methObj, NULL);
    674         }
    675     }
    676 
    677     assert(methObjCount == methodArray->length);
    678 
    679     /* caller must call dvmReleaseTrackedAlloc */
    680     return methodArray;
    681 
    682 fail:
    683     dvmReleaseTrackedAlloc((Object*) methodArray, NULL);
    684     return NULL;
    685 }
    686 
    687 /*
    688  * Fills targetDescriptorCache with the descriptors of the classes in args.
    689  * This is the concatenation of the descriptors with no other adornment,
    690  * consistent with dexProtoGetParameterDescriptors.
    691  */
    692 static void createTargetDescriptor(ArrayObject* args,
    693     DexStringCache* targetDescriptorCache)
    694 {
    695     ClassObject** argsArray = (ClassObject**)(void*)args->contents;
    696     size_t length = 1; /* +1 for the terminating '\0' */
    697     for (size_t i = 0; i < args->length; ++i) {
    698         length += strlen(argsArray[i]->descriptor);
    699     }
    700 
    701     dexStringCacheAlloc(targetDescriptorCache, length);
    702 
    703     char* at = (char*) targetDescriptorCache->value;
    704     for (size_t i = 0; i < args->length; ++i) {
    705         const char* descriptor = argsArray[i]->descriptor;
    706         strcpy(at, descriptor);
    707         at += strlen(descriptor);
    708     }
    709 }
    710 
    711 static Object* findConstructorOrMethodInArray(int methodsCount, Method* methods,
    712     const char* name, const char* parameterDescriptors)
    713 {
    714     Method* method = NULL;
    715     Method* result = NULL;
    716     int i;
    717 
    718     for (i = 0; i < methodsCount; ++i) {
    719         method = &methods[i];
    720         if (strcmp(name, method->name) != 0
    721             || dvmIsMirandaMethod(method)
    722             || dexProtoCompareToParameterDescriptors(&method->prototype,
    723                     parameterDescriptors) != 0) {
    724             continue;
    725         }
    726 
    727         result = method;
    728 
    729         /*
    730          * Covariant return types permit the class to define multiple
    731          * methods with the same name and parameter types. Prefer to return
    732          * a non-synthetic method in such situations. We may still return
    733          * a synthetic method to handle situations like escalated visibility.
    734          */
    735         if (!dvmIsSyntheticMethod(method)) {
    736             break;
    737         }
    738     }
    739 
    740     if (result != NULL) {
    741         return dvmCreateReflectObjForMethod(result->clazz, result);
    742     }
    743 
    744     return NULL;
    745 }
    746 
    747 /*
    748  * Get the named method.
    749  */
    750 Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
    751     StringObject* nameObj, ArrayObject* args)
    752 {
    753     Object* result = NULL;
    754     DexStringCache targetDescriptorCache;
    755     char* name;
    756     const char* targetDescriptor;
    757 
    758     dexStringCacheInit(&targetDescriptorCache);
    759 
    760     name = dvmCreateCstrFromString(nameObj);
    761     createTargetDescriptor(args, &targetDescriptorCache);
    762     targetDescriptor = targetDescriptorCache.value;
    763 
    764     result = findConstructorOrMethodInArray(clazz->directMethodCount,
    765         clazz->directMethods, name, targetDescriptor);
    766     if (result == NULL) {
    767         result = findConstructorOrMethodInArray(clazz->virtualMethodCount,
    768             clazz->virtualMethods, name, targetDescriptor);
    769     }
    770 
    771     free(name);
    772     dexStringCacheRelease(&targetDescriptorCache);
    773     return result;
    774 }
    775 
    776 /*
    777  * Get the named field.
    778  */
    779 Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj)
    780 {
    781     int i;
    782     Object* fieldObj = NULL;
    783     char* name = dvmCreateCstrFromString(nameObj);
    784 
    785     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
    786         dvmInitClass(gDvm.classJavaLangReflectField);
    787 
    788     for (i = 0; i < clazz->sfieldCount; i++) {
    789         Field* field = &clazz->sfields[i];
    790         if (strcmp(name, field->name) == 0) {
    791             fieldObj = createFieldObject(field, clazz);
    792             break;
    793         }
    794     }
    795     if (fieldObj == NULL) {
    796         for (i = 0; i < clazz->ifieldCount; i++) {
    797             Field* field = &clazz->ifields[i];
    798             if (strcmp(name, field->name) == 0) {
    799                 fieldObj = createFieldObject(field, clazz);
    800                 break;
    801             }
    802         }
    803     }
    804 
    805     free(name);
    806     return fieldObj;
    807 }
    808 
    809 /*
    810  * Get all interfaces a class implements. If this is unable to allocate
    811  * the result array, this raises an OutOfMemoryError and returns NULL.
    812  */
    813 ArrayObject* dvmGetInterfaces(ClassObject* clazz)
    814 {
    815     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
    816         dvmInitClass(gDvm.classJavaLangReflectMethod);
    817 
    818     /*
    819      * Create an array of Class objects.
    820      */
    821     size_t count = clazz->interfaceCount;
    822     ArrayObject* interfaceArray =
    823         dvmAllocArrayByClass(gDvm.classJavaLangClassArray, count, ALLOC_DEFAULT);
    824     if (interfaceArray == NULL)
    825         return NULL;
    826 
    827     /*
    828      * Fill out the array.
    829      */
    830     memcpy(interfaceArray->contents, clazz->interfaces,
    831            count * sizeof(Object *));
    832     dvmWriteBarrierArray(interfaceArray, 0, count);
    833 
    834     /* caller must call dvmReleaseTrackedAlloc */
    835     return interfaceArray;
    836 }
    837 
    838 /*
    839  * Given a boxed primitive type, such as java/lang/Integer, return the
    840  * primitive type index.
    841  *
    842  * Returns PRIM_NOT for void, since we never "box" that.
    843  */
    844 static PrimitiveType getBoxedType(DataObject* arg)
    845 {
    846     static const int kJavaLangLen = 11;     // strlen("Ljava/lang/")
    847 
    848     if (arg == NULL)
    849         return PRIM_NOT;
    850 
    851     const char* name = arg->clazz->descriptor;
    852 
    853     if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0)
    854         return PRIM_NOT;
    855 
    856     if (strcmp(name + kJavaLangLen, "Boolean;") == 0)
    857         return PRIM_BOOLEAN;
    858     if (strcmp(name + kJavaLangLen, "Character;") == 0)
    859         return PRIM_CHAR;
    860     if (strcmp(name + kJavaLangLen, "Float;") == 0)
    861         return PRIM_FLOAT;
    862     if (strcmp(name + kJavaLangLen, "Double;") == 0)
    863         return PRIM_DOUBLE;
    864     if (strcmp(name + kJavaLangLen, "Byte;") == 0)
    865         return PRIM_BYTE;
    866     if (strcmp(name + kJavaLangLen, "Short;") == 0)
    867         return PRIM_SHORT;
    868     if (strcmp(name + kJavaLangLen, "Integer;") == 0)
    869         return PRIM_INT;
    870     if (strcmp(name + kJavaLangLen, "Long;") == 0)
    871         return PRIM_LONG;
    872     return PRIM_NOT;
    873 }
    874 
    875 /*
    876  * Convert primitive, boxed data from "srcPtr" to "dstPtr".
    877  *
    878  * Section v2 2.6 lists the various conversions and promotions.  We
    879  * allow the "widening" and "identity" conversions, but don't allow the
    880  * "narrowing" conversions.
    881  *
    882  * Allowed:
    883  *  byte to short, int, long, float, double
    884  *  short to int, long, float double
    885  *  char to int, long, float, double
    886  *  int to long, float, double
    887  *  long to float, double
    888  *  float to double
    889  * Values of types byte, char, and short are "internally" widened to int.
    890  *
    891  * Returns the width in 32-bit words of the destination primitive, or
    892  * -1 if the conversion is not allowed.
    893  *
    894  * TODO? use JValue rather than u4 pointers
    895  */
    896 int dvmConvertPrimitiveValue(PrimitiveType srcType,
    897     PrimitiveType dstType, const s4* srcPtr, s4* dstPtr)
    898 {
    899     enum Conversion {
    900         OK4, OK8, ItoJ, ItoD, JtoD, FtoD, ItoF, JtoF, bad
    901     };
    902 
    903     enum Conversion conv;
    904 
    905     assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT));
    906     assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT));
    907 
    908     switch (dstType) {
    909         case PRIM_BOOLEAN:
    910         case PRIM_CHAR:
    911         case PRIM_BYTE: {
    912             conv = (srcType == dstType) ? OK4 : bad;
    913             break;
    914         }
    915         case PRIM_SHORT: {
    916             switch (srcType) {
    917                 case PRIM_BYTE:
    918                 case PRIM_SHORT: conv = OK4; break;
    919                 default:         conv = bad; break;
    920             }
    921             break;
    922         }
    923         case PRIM_INT: {
    924             switch (srcType) {
    925                 case PRIM_BYTE:
    926                 case PRIM_CHAR:
    927                 case PRIM_SHORT:
    928                 case PRIM_INT:   conv = OK4; break;
    929                 default:         conv = bad; break;
    930             }
    931             break;
    932         }
    933         case PRIM_LONG: {
    934             switch (srcType) {
    935                 case PRIM_BYTE:
    936                 case PRIM_CHAR:
    937                 case PRIM_SHORT:
    938                 case PRIM_INT:   conv = ItoJ; break;
    939                 case PRIM_LONG:  conv = OK8;  break;
    940                 default:         conv = bad;  break;
    941             }
    942             break;
    943         }
    944         case PRIM_FLOAT: {
    945             switch (srcType) {
    946                 case PRIM_BYTE:
    947                 case PRIM_CHAR:
    948                 case PRIM_SHORT:
    949                 case PRIM_INT:   conv = ItoF; break;
    950                 case PRIM_LONG:  conv = JtoF; break;
    951                 case PRIM_FLOAT: conv = OK4;  break;
    952                 default:         conv = bad;  break;
    953             }
    954             break;
    955         }
    956         case PRIM_DOUBLE: {
    957             switch (srcType) {
    958                 case PRIM_BYTE:
    959                 case PRIM_CHAR:
    960                 case PRIM_SHORT:
    961                 case PRIM_INT:    conv = ItoD; break;
    962                 case PRIM_LONG:   conv = JtoD; break;
    963                 case PRIM_FLOAT:  conv = FtoD; break;
    964                 case PRIM_DOUBLE: conv = OK8;  break;
    965                 default:          conv = bad;  break;
    966             }
    967             break;
    968         }
    969         case PRIM_VOID:
    970         case PRIM_NOT:
    971         default: {
    972             conv = bad;
    973             break;
    974         }
    975     }
    976 
    977     switch (conv) {
    978         case OK4:  *dstPtr = *srcPtr;                                   return 1;
    979         case OK8:  *(s8*) dstPtr = *(s8*)srcPtr;                        return 2;
    980         case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr);                return 2;
    981         case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr);        return 2;
    982         case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2;
    983         case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr);     return 2;
    984         case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr);         return 1;
    985         case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr);   return 1;
    986         case bad: {
    987             LOGV("illegal primitive conversion: '%s' to '%s'",
    988                     dexGetPrimitiveTypeDescriptor(srcType),
    989                     dexGetPrimitiveTypeDescriptor(dstType));
    990             return -1;
    991         }
    992         default: {
    993             dvmAbort();
    994             return -1; // Keep the compiler happy.
    995         }
    996     }
    997 }
    998 
    999 /*
   1000  * Convert types and widen primitives.  Puts the value of "arg" into
   1001  * "destPtr".
   1002  *
   1003  * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error.
   1004  */
   1005 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr)
   1006 {
   1007     int retVal;
   1008 
   1009     if (dvmIsPrimitiveClass(type)) {
   1010         /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */
   1011         PrimitiveType srcType;
   1012         s4* valuePtr;
   1013 
   1014         srcType = getBoxedType(arg);
   1015         if (srcType == PRIM_NOT) {     // didn't pass a boxed primitive in
   1016             LOGVV("conv arg: type '%s' not boxed primitive",
   1017                 arg->clazz->descriptor);
   1018             return -1;
   1019         }
   1020 
   1021         /* assumes value is stored in first instance field */
   1022         valuePtr = (s4*) arg->instanceData;
   1023 
   1024         retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType,
   1025                     valuePtr, destPtr);
   1026     } else {
   1027         /* verify object is compatible */
   1028         if ((arg == NULL) || dvmInstanceof(arg->clazz, type)) {
   1029             *destPtr = (s4) arg;
   1030             retVal = 1;
   1031         } else {
   1032             LOGVV("Arg %p (%s) not compatible with %s",
   1033                 arg, arg->clazz->descriptor, type->descriptor);
   1034             retVal = -1;
   1035         }
   1036     }
   1037 
   1038     return retVal;
   1039 }
   1040 
   1041 /*
   1042  * Create a wrapper object for a primitive data type.  If "returnType" is
   1043  * not primitive, this just casts "value" to an object and returns it.
   1044  *
   1045  * We could invoke the "toValue" method on the box types to take
   1046  * advantage of pre-created values, but running that through the
   1047  * interpreter is probably less efficient than just allocating storage here.
   1048  *
   1049  * The caller must call dvmReleaseTrackedAlloc on the result.
   1050  */
   1051 DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType)
   1052 {
   1053     ClassObject* wrapperClass;
   1054     DataObject* wrapperObj;
   1055     s4* dataPtr;
   1056     PrimitiveType typeIndex = returnType->primitiveType;
   1057     const char* classDescriptor;
   1058 
   1059     if (typeIndex == PRIM_NOT) {
   1060         /* add to tracking table so return value is always in table */
   1061         if (value.l != NULL)
   1062             dvmAddTrackedAlloc((Object*)value.l, NULL);
   1063         return (DataObject*) value.l;
   1064     }
   1065 
   1066     classDescriptor = dexGetBoxedTypeDescriptor(typeIndex);
   1067     if (classDescriptor == NULL) {
   1068         return NULL;
   1069     }
   1070 
   1071     wrapperClass = dvmFindSystemClass(classDescriptor);
   1072     if (wrapperClass == NULL) {
   1073         LOGW("Unable to find '%s'", classDescriptor);
   1074         assert(dvmCheckException(dvmThreadSelf()));
   1075         return NULL;
   1076     }
   1077 
   1078     wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT);
   1079     if (wrapperObj == NULL)
   1080         return NULL;
   1081     dataPtr = (s4*) wrapperObj->instanceData;
   1082 
   1083     /* assumes value is stored in first instance field */
   1084     /* (see dvmValidateBoxClasses) */
   1085     if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE)
   1086         *(s8*)dataPtr = value.j;
   1087     else
   1088         *dataPtr = value.i;
   1089 
   1090     return wrapperObj;
   1091 }
   1092 
   1093 /*
   1094  * Unwrap a primitive data type, if necessary.
   1095  *
   1096  * If "returnType" is not primitive, we just tuck "value" into JValue and
   1097  * return it after verifying that it's the right type of object.
   1098  *
   1099  * Fails if the field is primitive and "value" is either not a boxed
   1100  * primitive or is of a type that cannot be converted.
   1101  *
   1102  * Returns "true" on success, "false" on failure.
   1103  */
   1104 bool dvmUnboxPrimitive(Object* value, ClassObject* returnType,
   1105     JValue* pResult)
   1106 {
   1107     PrimitiveType typeIndex = returnType->primitiveType;
   1108     PrimitiveType valueIndex;
   1109 
   1110     if (typeIndex == PRIM_NOT) {
   1111         if (value != NULL && !dvmInstanceof(value->clazz, returnType)) {
   1112             LOGD("wrong object type: %s %s",
   1113                 value->clazz->descriptor, returnType->descriptor);
   1114             return false;
   1115         }
   1116         pResult->l = value;
   1117         return true;
   1118     } else if (typeIndex == PRIM_VOID) {
   1119         /* can't put anything into a void */
   1120         return false;
   1121     }
   1122 
   1123     valueIndex = getBoxedType((DataObject*)value);
   1124     if (valueIndex == PRIM_NOT)
   1125         return false;
   1126 
   1127     /* assumes value is stored in first instance field of "value" */
   1128     /* (see dvmValidateBoxClasses) */
   1129     if (dvmConvertPrimitiveValue(valueIndex, typeIndex,
   1130             (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0)
   1131     {
   1132         LOGV("Prim conversion failed");
   1133         return false;
   1134     }
   1135 
   1136     return true;
   1137 }
   1138 
   1139 
   1140 /*
   1141  * Find the return type in the signature, and convert it to a class
   1142  * object.  For primitive types we use a boxed class, for reference types
   1143  * we do a name lookup.
   1144  *
   1145  * On failure, we return NULL with an exception raised.
   1146  */
   1147 ClassObject* dvmGetBoxedReturnType(const Method* meth)
   1148 {
   1149     const char* sig = dexProtoGetReturnType(&meth->prototype);
   1150 
   1151     switch (*sig) {
   1152     case 'Z':
   1153     case 'C':
   1154     case 'F':
   1155     case 'D':
   1156     case 'B':
   1157     case 'S':
   1158     case 'I':
   1159     case 'J':
   1160     case 'V':
   1161         return dvmFindPrimitiveClass(*sig);
   1162     case '[':
   1163     case 'L':
   1164         return dvmFindClass(sig, meth->clazz->classLoader);
   1165     default: {
   1166         /* should not have passed verification */
   1167         char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
   1168         LOGE("Bad return type in signature '%s'", desc);
   1169         free(desc);
   1170         dvmThrowInternalError(NULL);
   1171         return NULL;
   1172     }
   1173     }
   1174 }
   1175 
   1176 
   1177 /*
   1178  * JNI reflection support: convert reflection object to Field ptr.
   1179  */
   1180 Field* dvmGetFieldFromReflectObj(Object* obj)
   1181 {
   1182     ClassObject* clazz;
   1183     int slot;
   1184 
   1185     assert(obj->clazz == gDvm.classJavaLangReflectField);
   1186     clazz = (ClassObject*)dvmGetFieldObject(obj,
   1187                                 gDvm.offJavaLangReflectField_declClass);
   1188     slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot);
   1189 
   1190     /* must initialize the class before returning a field ID */
   1191     if (!dvmInitClass(clazz))
   1192         return NULL;
   1193 
   1194     return dvmSlotToField(clazz, slot);
   1195 }
   1196 
   1197 /*
   1198  * JNI reflection support: convert reflection object to Method ptr.
   1199  */
   1200 Method* dvmGetMethodFromReflectObj(Object* obj)
   1201 {
   1202     ClassObject* clazz;
   1203     int slot;
   1204 
   1205     if (obj->clazz == gDvm.classJavaLangReflectConstructor) {
   1206         clazz = (ClassObject*)dvmGetFieldObject(obj,
   1207                                 gDvm.offJavaLangReflectConstructor_declClass);
   1208         slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot);
   1209     } else if (obj->clazz == gDvm.classJavaLangReflectMethod) {
   1210         clazz = (ClassObject*)dvmGetFieldObject(obj,
   1211                                 gDvm.offJavaLangReflectMethod_declClass);
   1212         slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot);
   1213     } else {
   1214         assert(false);
   1215         return NULL;
   1216     }
   1217 
   1218     /* must initialize the class before returning a method ID */
   1219     if (!dvmInitClass(clazz))
   1220         return NULL;
   1221 
   1222     return dvmSlotToMethod(clazz, slot);
   1223 }
   1224 
   1225 /*
   1226  * JNI reflection support: convert Field to reflection object.
   1227  *
   1228  * The return value is a java.lang.reflect.Field.
   1229  *
   1230  * Caller must call dvmReleaseTrackedAlloc().
   1231  */
   1232 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field)
   1233 {
   1234     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
   1235         dvmInitClass(gDvm.classJavaLangReflectField);
   1236 
   1237     /* caller must dvmReleaseTrackedAlloc(result) */
   1238     return createFieldObject(field, clazz);
   1239 }
   1240 
   1241 /*
   1242  * JNI reflection support: convert Method to reflection object.
   1243  *
   1244  * The returned object will be either a java.lang.reflect.Method or
   1245  * .Constructor, depending on whether "method" is a constructor.
   1246  *
   1247  * This is also used for certain "system" annotations.
   1248  *
   1249  * Caller must call dvmReleaseTrackedAlloc().
   1250  */
   1251 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method)
   1252 {
   1253     UNUSED_PARAMETER(clazz);
   1254 
   1255     if (strcmp(method->name, "<init>") == 0) {
   1256         if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
   1257             dvmInitClass(gDvm.classJavaLangReflectConstructor);
   1258 
   1259         return createConstructorObject(method);
   1260     } else {
   1261         if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
   1262             dvmInitClass(gDvm.classJavaLangReflectMethod);
   1263 
   1264         return dvmCreateReflectMethodObject(method);
   1265     }
   1266 }
   1267