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#ifdef ARCH_HAVE_ALIGNED_DOUBLES
905    double ret;
906#endif
907
908    assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT));
909    assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT));
910
911    switch (dstType) {
912        case PRIM_BOOLEAN:
913        case PRIM_CHAR:
914        case PRIM_BYTE: {
915            conv = (srcType == dstType) ? OK4 : bad;
916            break;
917        }
918        case PRIM_SHORT: {
919            switch (srcType) {
920                case PRIM_BYTE:
921                case PRIM_SHORT: conv = OK4; break;
922                default:         conv = bad; break;
923            }
924            break;
925        }
926        case PRIM_INT: {
927            switch (srcType) {
928                case PRIM_BYTE:
929                case PRIM_CHAR:
930                case PRIM_SHORT:
931                case PRIM_INT:   conv = OK4; break;
932                default:         conv = bad; break;
933            }
934            break;
935        }
936        case PRIM_LONG: {
937            switch (srcType) {
938                case PRIM_BYTE:
939                case PRIM_CHAR:
940                case PRIM_SHORT:
941                case PRIM_INT:   conv = ItoJ; break;
942                case PRIM_LONG:  conv = OK8;  break;
943                default:         conv = bad;  break;
944            }
945            break;
946        }
947        case PRIM_FLOAT: {
948            switch (srcType) {
949                case PRIM_BYTE:
950                case PRIM_CHAR:
951                case PRIM_SHORT:
952                case PRIM_INT:   conv = ItoF; break;
953                case PRIM_LONG:  conv = JtoF; break;
954                case PRIM_FLOAT: conv = OK4;  break;
955                default:         conv = bad;  break;
956            }
957            break;
958        }
959        case PRIM_DOUBLE: {
960            switch (srcType) {
961                case PRIM_BYTE:
962                case PRIM_CHAR:
963                case PRIM_SHORT:
964                case PRIM_INT:    conv = ItoD; break;
965                case PRIM_LONG:   conv = JtoD; break;
966                case PRIM_FLOAT:  conv = FtoD; break;
967                case PRIM_DOUBLE: conv = OK8;  break;
968                default:          conv = bad;  break;
969            }
970            break;
971        }
972        case PRIM_VOID:
973        case PRIM_NOT:
974        default: {
975            conv = bad;
976            break;
977        }
978    }
979
980    switch (conv) {
981        case OK4:  *dstPtr = *srcPtr;                                   return 1;
982        case OK8:  *(s8*) dstPtr = *(s8*)srcPtr;                        return 2;
983        case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr);                return 2;
984#ifndef ARCH_HAVE_ALIGNED_DOUBLES
985        case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr);        return 2;
986        case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2;
987        case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr);     return 2;
988#else
989        case ItoD: ret = (double) (*(s4*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
990        case JtoD: ret = (double) (*(long long*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
991        case FtoD: ret = (double) (*(float*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
992#endif
993        case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr);         return 1;
994        case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr);   return 1;
995        case bad: {
996            ALOGV("illegal primitive conversion: '%s' to '%s'",
997                    dexGetPrimitiveTypeDescriptor(srcType),
998                    dexGetPrimitiveTypeDescriptor(dstType));
999            return -1;
1000        }
1001        default: {
1002            dvmAbort();
1003            return -1; // Keep the compiler happy.
1004        }
1005    }
1006}
1007
1008/*
1009 * Convert types and widen primitives.  Puts the value of "arg" into
1010 * "destPtr".
1011 *
1012 * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error.
1013 */
1014int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr)
1015{
1016    int retVal;
1017
1018    if (dvmIsPrimitiveClass(type)) {
1019        /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */
1020        PrimitiveType srcType;
1021        s4* valuePtr;
1022
1023        srcType = getBoxedType(arg);
1024        if (srcType == PRIM_NOT) {     // didn't pass a boxed primitive in
1025            LOGVV("conv arg: type '%s' not boxed primitive",
1026                arg->clazz->descriptor);
1027            return -1;
1028        }
1029
1030        /* assumes value is stored in first instance field */
1031        valuePtr = (s4*) arg->instanceData;
1032
1033        retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType,
1034                    valuePtr, destPtr);
1035    } else {
1036        /* verify object is compatible */
1037        if ((arg == NULL) || dvmInstanceof(arg->clazz, type)) {
1038            *destPtr = (s4) arg;
1039            retVal = 1;
1040        } else {
1041            LOGVV("Arg %p (%s) not compatible with %s",
1042                arg, arg->clazz->descriptor, type->descriptor);
1043            retVal = -1;
1044        }
1045    }
1046
1047    return retVal;
1048}
1049
1050/*
1051 * Create a wrapper object for a primitive data type.  If "returnType" is
1052 * not primitive, this just casts "value" to an object and returns it.
1053 *
1054 * We could invoke the "toValue" method on the box types to take
1055 * advantage of pre-created values, but running that through the
1056 * interpreter is probably less efficient than just allocating storage here.
1057 *
1058 * The caller must call dvmReleaseTrackedAlloc on the result.
1059 */
1060DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType)
1061{
1062    ClassObject* wrapperClass;
1063    DataObject* wrapperObj;
1064    s4* dataPtr;
1065    PrimitiveType typeIndex = returnType->primitiveType;
1066    const char* classDescriptor;
1067
1068    if (typeIndex == PRIM_NOT) {
1069        /* add to tracking table so return value is always in table */
1070        if (value.l != NULL)
1071            dvmAddTrackedAlloc((Object*)value.l, NULL);
1072        return (DataObject*) value.l;
1073    }
1074
1075    classDescriptor = dexGetBoxedTypeDescriptor(typeIndex);
1076    if (classDescriptor == NULL) {
1077        return NULL;
1078    }
1079
1080    wrapperClass = dvmFindSystemClass(classDescriptor);
1081    if (wrapperClass == NULL) {
1082        ALOGW("Unable to find '%s'", classDescriptor);
1083        assert(dvmCheckException(dvmThreadSelf()));
1084        return NULL;
1085    }
1086
1087    wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT);
1088    if (wrapperObj == NULL)
1089        return NULL;
1090    dataPtr = (s4*) wrapperObj->instanceData;
1091
1092    /* assumes value is stored in first instance field */
1093    /* (see dvmValidateBoxClasses) */
1094    if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE)
1095        *(s8*)dataPtr = value.j;
1096    else
1097        *dataPtr = value.i;
1098
1099    return wrapperObj;
1100}
1101
1102/*
1103 * Unwrap a primitive data type, if necessary.
1104 *
1105 * If "returnType" is not primitive, we just tuck "value" into JValue and
1106 * return it after verifying that it's the right type of object.
1107 *
1108 * Fails if the field is primitive and "value" is either not a boxed
1109 * primitive or is of a type that cannot be converted.
1110 *
1111 * Returns "true" on success, "false" on failure.
1112 */
1113bool dvmUnboxPrimitive(Object* value, ClassObject* returnType,
1114    JValue* pResult)
1115{
1116    PrimitiveType typeIndex = returnType->primitiveType;
1117    PrimitiveType valueIndex;
1118
1119    if (typeIndex == PRIM_NOT) {
1120        if (value != NULL && !dvmInstanceof(value->clazz, returnType)) {
1121            ALOGD("wrong object type: %s %s",
1122                value->clazz->descriptor, returnType->descriptor);
1123            return false;
1124        }
1125        pResult->l = value;
1126        return true;
1127    } else if (typeIndex == PRIM_VOID) {
1128        /* can't put anything into a void */
1129        return false;
1130    }
1131
1132    valueIndex = getBoxedType((DataObject*)value);
1133    if (valueIndex == PRIM_NOT)
1134        return false;
1135
1136    /* assumes value is stored in first instance field of "value" */
1137    /* (see dvmValidateBoxClasses) */
1138    if (dvmConvertPrimitiveValue(valueIndex, typeIndex,
1139            (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0)
1140    {
1141        ALOGV("Prim conversion failed");
1142        return false;
1143    }
1144
1145    return true;
1146}
1147
1148
1149/*
1150 * Find the return type in the signature, and convert it to a class
1151 * object.  For primitive types we use a boxed class, for reference types
1152 * we do a name lookup.
1153 *
1154 * On failure, we return NULL with an exception raised.
1155 */
1156ClassObject* dvmGetBoxedReturnType(const Method* meth)
1157{
1158    const char* sig = dexProtoGetReturnType(&meth->prototype);
1159
1160    switch (*sig) {
1161    case 'Z':
1162    case 'C':
1163    case 'F':
1164    case 'D':
1165    case 'B':
1166    case 'S':
1167    case 'I':
1168    case 'J':
1169    case 'V':
1170        return dvmFindPrimitiveClass(*sig);
1171    case '[':
1172    case 'L':
1173        return dvmFindClass(sig, meth->clazz->classLoader);
1174    default: {
1175        /* should not have passed verification */
1176        char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1177        ALOGE("Bad return type in signature '%s'", desc);
1178        free(desc);
1179        dvmThrowInternalError(NULL);
1180        return NULL;
1181    }
1182    }
1183}
1184
1185
1186/*
1187 * JNI reflection support: convert reflection object to Field ptr.
1188 */
1189Field* dvmGetFieldFromReflectObj(Object* obj)
1190{
1191    ClassObject* clazz;
1192    int slot;
1193
1194    assert(obj->clazz == gDvm.classJavaLangReflectField);
1195    clazz = (ClassObject*)dvmGetFieldObject(obj,
1196                                gDvm.offJavaLangReflectField_declClass);
1197    slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot);
1198
1199    /* must initialize the class before returning a field ID */
1200    if (!dvmInitClass(clazz))
1201        return NULL;
1202
1203    return dvmSlotToField(clazz, slot);
1204}
1205
1206/*
1207 * JNI reflection support: convert reflection object to Method ptr.
1208 */
1209Method* dvmGetMethodFromReflectObj(Object* obj)
1210{
1211    ClassObject* clazz;
1212    int slot;
1213
1214    if (obj->clazz == gDvm.classJavaLangReflectConstructor) {
1215        clazz = (ClassObject*)dvmGetFieldObject(obj,
1216                                gDvm.offJavaLangReflectConstructor_declClass);
1217        slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot);
1218    } else if (obj->clazz == gDvm.classJavaLangReflectMethod) {
1219        clazz = (ClassObject*)dvmGetFieldObject(obj,
1220                                gDvm.offJavaLangReflectMethod_declClass);
1221        slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot);
1222    } else {
1223        assert(false);
1224        return NULL;
1225    }
1226
1227    /* must initialize the class before returning a method ID */
1228    if (!dvmInitClass(clazz))
1229        return NULL;
1230
1231    return dvmSlotToMethod(clazz, slot);
1232}
1233
1234/*
1235 * JNI reflection support: convert Field to reflection object.
1236 *
1237 * The return value is a java.lang.reflect.Field.
1238 *
1239 * Caller must call dvmReleaseTrackedAlloc().
1240 */
1241Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field)
1242{
1243    if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
1244        dvmInitClass(gDvm.classJavaLangReflectField);
1245
1246    /* caller must dvmReleaseTrackedAlloc(result) */
1247    return createFieldObject(field, clazz);
1248}
1249
1250/*
1251 * JNI reflection support: convert Method to reflection object.
1252 *
1253 * The returned object will be either a java.lang.reflect.Method or
1254 * .Constructor, depending on whether "method" is a constructor.
1255 *
1256 * This is also used for certain "system" annotations.
1257 *
1258 * Caller must call dvmReleaseTrackedAlloc().
1259 */
1260Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method)
1261{
1262    UNUSED_PARAMETER(clazz);
1263
1264    if (strcmp(method->name, "<init>") == 0) {
1265        if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
1266            dvmInitClass(gDvm.classJavaLangReflectConstructor);
1267
1268        return createConstructorObject(method);
1269    } else {
1270        if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
1271            dvmInitClass(gDvm.classJavaLangReflectMethod);
1272
1273        return dvmCreateReflectMethodObject(method);
1274    }
1275}
1276