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