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