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