OSDN Git Service

am e5310471: am d8232960: am 68719a17: Reconcile with jb-mr1-release - do not merge
[android-x86/dalvik.git] / vm / reflect / Reflect.cpp
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  * Basic reflection calls and utility functions.
18  */
19 #include "Dalvik.h"
20
21 #include <stdlib.h>
22
23 /*
24  * For some of the reflection stuff we need to un-box primitives, e.g.
25  * convert a java/lang/Integer to int or even a float.  We assume that
26  * the first instance field holds the value.
27  *
28  * To verify this, we either need to ensure that the class has only one
29  * instance field, or we need to look up the field by name and verify
30  * that it comes first.  The former is simpler, and should work.
31  */
32 bool dvmValidateBoxClasses()
33 {
34     static const char* classes[] = {
35         "Ljava/lang/Boolean;",
36         "Ljava/lang/Character;",
37         "Ljava/lang/Float;",
38         "Ljava/lang/Double;",
39         "Ljava/lang/Byte;",
40         "Ljava/lang/Short;",
41         "Ljava/lang/Integer;",
42         "Ljava/lang/Long;",
43         NULL
44     };
45     const char** ccp;
46
47     for (ccp = classes; *ccp != NULL; ccp++) {
48         ClassObject* clazz;
49
50         clazz = dvmFindClassNoInit(*ccp, NULL);
51         if (clazz == NULL) {
52             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  */
74 static ClassObject* convertSignaturePartToClass(char** pSignature,
75     const ClassObject* defClass)
76 {
77     ClassObject* clazz = NULL;
78     char* signature = *pSignature;
79
80     if (*signature == '[') {
81         /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */
82         char savedChar;
83
84         while (*++signature == '[')
85             ;
86         if (*signature == 'L') {
87             while (*++signature != ';')
88                 ;
89         }
90
91         /* advance past ';', and stomp on whatever comes next */
92         savedChar = *++signature;
93         *signature = '\0';
94         clazz = dvmFindArrayClass(*pSignature, defClass->classLoader);
95         *signature = savedChar;
96     } else if (*signature == 'L') {
97         /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */
98         char savedChar;
99         while (*++signature != ';')
100             ;
101         savedChar = *++signature;
102         *signature = '\0';
103         clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader);
104         *signature = savedChar;
105     } else {
106         clazz = dvmFindPrimitiveClass(*signature++);
107     }
108
109     if (clazz == NULL) {
110         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  */
125 static ArrayObject* convertSignatureToClassArray(char** pSignature,
126     ClassObject* defClass)
127 {
128     char* signature = *pSignature;
129
130     assert(*signature == '(');
131     signature++;
132
133     /* count up the number of parameters */
134     size_t count = 0;
135     char* cp = signature;
136     while (*cp != ')') {
137         count++;
138
139         if (*cp == '[') {
140             while (*++cp == '[')
141                 ;
142         }
143         if (*cp == 'L') {
144             while (*++cp != ';')
145                 ;
146         }
147         cp++;
148     }
149     LOGVV("REFLECT found %d parameters in '%s'", count, *pSignature);
150
151     /* create an array to hold them */
152     ArrayObject* classArray = dvmAllocArrayByClass(gDvm.classJavaLangClassArray,
153                      count, ALLOC_DEFAULT);
154     if (classArray == NULL)
155         return NULL;
156
157     /* fill it in */
158     cp = signature;
159     for (size_t i = 0; i < count; i++) {
160         ClassObject* clazz = convertSignaturePartToClass(&cp, defClass);
161         if (clazz == NULL) {
162             assert(dvmCheckException(dvmThreadSelf()));
163             return NULL;
164         }
165         LOGVV("REFLECT  %d: '%s'", i, clazz->descriptor);
166         dvmSetObjectArrayElement(classArray, i, (Object *)clazz);
167     }
168
169     *pSignature = cp;
170
171     /* caller must call dvmReleaseTrackedAlloc */
172     return classArray;
173 }
174
175
176 /*
177  * Convert a field pointer to a slot number.
178  *
179  * We use positive values starting from 0 for instance fields, negative
180  * values starting from -1 for static fields.
181  */
182 static int fieldToSlot(const Field* field, const ClassObject* clazz)
183 {
184     int slot;
185
186     if (dvmIsStaticField(field)) {
187         slot = (StaticField*)field - &clazz->sfields[0];
188         assert(slot >= 0 && slot < clazz->sfieldCount);
189         slot = -(slot+1);
190     } else {
191         slot = (InstField*)field - clazz->ifields;
192         assert(slot >= 0 && slot < clazz->ifieldCount);
193     }
194
195     return slot;
196 }
197
198 /*
199  * Convert a slot number to a field pointer.
200  */
201 Field* dvmSlotToField(ClassObject* clazz, int slot)
202 {
203     if (slot < 0) {
204         slot = -(slot+1);
205         assert(slot < clazz->sfieldCount);
206         return (Field*)(void*)&clazz->sfields[slot];
207     } else {
208         assert(slot < clazz->ifieldCount);
209         return (Field*)(void*)&clazz->ifields[slot];
210     }
211 }
212
213 /*
214  * Create a new java.lang.reflect.Field object from "field".
215  *
216  * The Field spec doesn't specify the constructor.  We're going to use the
217  * one from our existing class libs:
218  *
219  *  private Field(Class declaringClass, Class type, String name, int slot)
220  */
221 static Object* createFieldObject(Field* field, const ClassObject* clazz)
222 {
223     Object* result = NULL;
224     Object* fieldObj = NULL;
225     StringObject* nameObj = NULL;
226     ClassObject* type;
227     char* mangle;
228     char* cp;
229     int slot;
230
231     assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField));
232
233     fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT);
234     if (fieldObj == NULL)
235         goto bail;
236
237     cp = mangle = strdup(field->signature);
238     type = convertSignaturePartToClass(&cp, clazz);
239     free(mangle);
240     if (type == NULL)
241         goto bail;
242
243     nameObj = dvmCreateStringFromCstr(field->name);
244     if (nameObj == NULL)
245         goto bail;
246
247     slot = fieldToSlot(field, clazz);
248
249     JValue unused;
250     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init,
251         fieldObj, &unused, clazz, type, nameObj, slot);
252     if (dvmCheckException(dvmThreadSelf())) {
253         ALOGD("Field class init threw exception");
254         goto bail;
255     }
256
257     result = fieldObj;
258
259 bail:
260     dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
261     if (result == NULL)
262         dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
263     /* caller must dvmReleaseTrackedAlloc(result) */
264     return result;
265 }
266
267 /*
268  *
269  * Get an array with all fields declared by a class.
270  *
271  * This includes both static and instance fields.
272  */
273 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
274 {
275     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
276         dvmInitClass(gDvm.classJavaLangReflectField);
277
278     /* count #of fields */
279     size_t count;
280     if (!publicOnly)
281         count = clazz->sfieldCount + clazz->ifieldCount;
282     else {
283         count = 0;
284         for (int i = 0; i < clazz->sfieldCount; i++) {
285             if ((clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
286                 count++;
287         }
288         for (int i = 0; i < clazz->ifieldCount; i++) {
289             if ((clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
290                 count++;
291         }
292     }
293
294     /* create the Field[] array */
295     ArrayObject* fieldArray =
296         dvmAllocArrayByClass(gDvm.classJavaLangReflectFieldArray, count, ALLOC_DEFAULT);
297     if (fieldArray == NULL)
298         return NULL;
299
300     /* populate */
301     size_t fieldCount = 0;
302     for (int i = 0; i < clazz->sfieldCount; i++) {
303         if (!publicOnly ||
304             (clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
305         {
306             Object* field = createFieldObject(&clazz->sfields[i], clazz);
307             if (field == NULL) {
308                 goto fail;
309             }
310             dvmSetObjectArrayElement(fieldArray, fieldCount, field);
311             dvmReleaseTrackedAlloc(field, NULL);
312             ++fieldCount;
313         }
314     }
315     for (int i = 0; i < clazz->ifieldCount; i++) {
316         if (!publicOnly ||
317             (clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
318         {
319             Object* field = createFieldObject(&clazz->ifields[i], clazz);
320             if (field == NULL) {
321                 goto fail;
322             }
323             dvmSetObjectArrayElement(fieldArray, fieldCount, field);
324             dvmReleaseTrackedAlloc(field, NULL);
325             ++fieldCount;
326         }
327     }
328
329     assert(fieldCount == fieldArray->length);
330
331     /* caller must call dvmReleaseTrackedAlloc */
332     return fieldArray;
333
334 fail:
335     dvmReleaseTrackedAlloc((Object*) fieldArray, NULL);
336     return NULL;
337 }
338
339
340 /*
341  * Convert a method pointer to a slot number.
342  *
343  * We use positive values starting from 0 for virtual methods, negative
344  * values starting from -1 for static methods.
345  */
346 static int methodToSlot(const Method* meth)
347 {
348     ClassObject* clazz = meth->clazz;
349     int slot;
350
351     if (dvmIsDirectMethod(meth)) {
352         slot = meth - clazz->directMethods;
353         assert(slot >= 0 && slot < clazz->directMethodCount);
354         slot = -(slot+1);
355     } else {
356         slot = meth - clazz->virtualMethods;
357         assert(slot >= 0 && slot < clazz->virtualMethodCount);
358     }
359
360     return slot;
361 }
362
363 /*
364  * Convert a slot number to a method pointer.
365  */
366 Method* dvmSlotToMethod(ClassObject* clazz, int slot)
367 {
368     if (slot < 0) {
369         slot = -(slot+1);
370         assert(slot < clazz->directMethodCount);
371         return &clazz->directMethods[slot];
372     } else {
373         assert(slot < clazz->virtualMethodCount);
374         return &clazz->virtualMethods[slot];
375     }
376 }
377
378 /*
379  * Create a new java/lang/reflect/Constructor object, using the contents of
380  * "meth" to construct it.
381  *
382  * The spec doesn't specify the constructor.  We're going to use the
383  * one from our existing class libs:
384  *
385  *  private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes,
386  *      int slot)
387  */
388 static Object* createConstructorObject(Method* meth)
389 {
390     Object* result = NULL;
391     ArrayObject* params = NULL;
392     ArrayObject* exceptions = NULL;
393     Object* consObj;
394     DexStringCache mangle;
395     char* cp;
396     int slot;
397
398     dexStringCacheInit(&mangle);
399
400     /* parent should guarantee init so we don't have to check on every call */
401     assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor));
402
403     consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor,
404                 ALLOC_DEFAULT);
405     if (consObj == NULL)
406         goto bail;
407
408     /*
409      * Convert the signature string into an array of classes representing
410      * the arguments.
411      */
412     cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
413     params = convertSignatureToClassArray(&cp, meth->clazz);
414     if (params == NULL)
415         goto bail;
416     assert(*cp == ')');
417     assert(*(cp+1) == 'V');
418
419     /*
420      * Create an array with one entry for every exception that the class
421      * is declared to throw.
422      */
423     exceptions = dvmGetMethodThrows(meth);
424     if (dvmCheckException(dvmThreadSelf()))
425         goto bail;
426
427     slot = methodToSlot(meth);
428
429     JValue unused;
430     dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init,
431         consObj, &unused, meth->clazz, params, exceptions, slot);
432     if (dvmCheckException(dvmThreadSelf())) {
433         ALOGD("Constructor class init threw exception");
434         goto bail;
435     }
436
437     result = consObj;
438
439 bail:
440     dexStringCacheRelease(&mangle);
441     dvmReleaseTrackedAlloc((Object*) params, NULL);
442     dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
443     if (result == NULL) {
444         assert(dvmCheckException(dvmThreadSelf()));
445         dvmReleaseTrackedAlloc(consObj, NULL);
446     }
447     /* caller must dvmReleaseTrackedAlloc(result) */
448     return result;
449 }
450
451 /*
452  * Get an array with all constructors declared by a class.
453  */
454 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
455 {
456     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
457         dvmInitClass(gDvm.classJavaLangReflectConstructor);
458
459     /*
460      * Ordinarily we init the class the first time we resolve a method.
461      * We're bypassing the normal resolution mechanism, so we init it here.
462      */
463     if (!dvmIsClassInitialized(clazz))
464         dvmInitClass(clazz);
465
466     /*
467      * Count up the #of relevant methods.
468      */
469     size_t count = 0;
470     for (int i = 0; i < clazz->directMethodCount; ++i) {
471         Method* meth = &clazz->directMethods[i];
472         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
473             dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
474         {
475             count++;
476         }
477     }
478
479     /*
480      * Create an array of Constructor objects.
481      */
482     ClassObject* arrayClass = gDvm.classJavaLangReflectConstructorArray;
483     ArrayObject* ctorArray = dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
484     if (ctorArray == NULL)
485         return NULL;
486
487     /*
488      * Fill out the array.
489      */
490     size_t ctorObjCount = 0;
491     for (int i = 0; i < clazz->directMethodCount; ++i) {
492         Method* meth = &clazz->directMethods[i];
493         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
494             dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
495         {
496             Object* ctorObj = createConstructorObject(meth);
497             if (ctorObj == NULL) {
498               dvmReleaseTrackedAlloc((Object*) ctorArray, NULL);
499               return NULL;
500             }
501             dvmSetObjectArrayElement(ctorArray, ctorObjCount, ctorObj);
502             ++ctorObjCount;
503             dvmReleaseTrackedAlloc(ctorObj, NULL);
504         }
505     }
506
507     assert(ctorObjCount == ctorArray->length);
508
509     /* caller must call dvmReleaseTrackedAlloc */
510     return ctorArray;
511 }
512
513 /*
514  * Create a new java/lang/reflect/Method object, using the contents of
515  * "meth" to construct it.
516  *
517  * The spec doesn't specify the constructor.  We're going to use the
518  * one from our existing class libs:
519  *
520  *  private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes,
521  *      Class returnType, String name, int slot)
522  *
523  * The caller must call dvmReleaseTrackedAlloc() on the result.
524  */
525 Object* dvmCreateReflectMethodObject(const Method* meth)
526 {
527     Object* result = NULL;
528     ArrayObject* params = NULL;
529     ArrayObject* exceptions = NULL;
530     StringObject* nameObj = NULL;
531     Object* methObj;
532     ClassObject* returnType;
533     DexStringCache mangle;
534     char* cp;
535     int slot;
536
537     if (dvmCheckException(dvmThreadSelf())) {
538         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
592 bail:
593     dexStringCacheRelease(&mangle);
594     if (result == NULL) {
595         assert(dvmCheckException(dvmThreadSelf()));
596     }
597     dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
598     dvmReleaseTrackedAlloc((Object*) params, NULL);
599     dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
600     if (result == NULL)
601         dvmReleaseTrackedAlloc(methObj, NULL);
602     return result;
603 }
604
605 /*
606  * Get an array with all methods declared by a class.
607  *
608  * This includes both static and virtual methods, and can include private
609  * members if "publicOnly" is false.  It does not include Miranda methods,
610  * since those weren't declared in the class, or constructors.
611  */
612 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
613 {
614     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
615         dvmInitClass(gDvm.classJavaLangReflectMethod);
616
617     /*
618      * Count up the #of relevant methods.
619      *
620      * Ignore virtual Miranda methods and direct class/object constructors.
621      */
622     size_t count = 0;
623     Method* meth = clazz->virtualMethods;
624     for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
625         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
626             !dvmIsMirandaMethod(meth))
627         {
628             count++;
629         }
630     }
631     meth = clazz->directMethods;
632     for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
633         if ((!publicOnly || dvmIsPublicMethod(meth)) && meth->name[0] != '<') {
634             count++;
635         }
636     }
637
638     /*
639      * Create an array of Method objects.
640      */
641     ArrayObject* methodArray =
642         dvmAllocArrayByClass(gDvm.classJavaLangReflectMethodArray, count, ALLOC_DEFAULT);
643     if (methodArray == NULL)
644         return NULL;
645
646     /*
647      * Fill out the array.
648      */
649     meth = clazz->virtualMethods;
650     size_t methObjCount = 0;
651     for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
652         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
653             !dvmIsMirandaMethod(meth))
654         {
655             Object* methObj = dvmCreateReflectMethodObject(meth);
656             if (methObj == NULL)
657                 goto fail;
658             dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
659             ++methObjCount;
660             dvmReleaseTrackedAlloc(methObj, NULL);
661         }
662     }
663     meth = clazz->directMethods;
664     for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
665         if ((!publicOnly || dvmIsPublicMethod(meth)) &&
666             meth->name[0] != '<')
667         {
668             Object* methObj = dvmCreateReflectMethodObject(meth);
669             if (methObj == NULL)
670                 goto fail;
671             dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
672             ++methObjCount;
673             dvmReleaseTrackedAlloc(methObj, NULL);
674         }
675     }
676
677     assert(methObjCount == methodArray->length);
678
679     /* caller must call dvmReleaseTrackedAlloc */
680     return methodArray;
681
682 fail:
683     dvmReleaseTrackedAlloc((Object*) methodArray, NULL);
684     return NULL;
685 }
686
687 /*
688  * Fills targetDescriptorCache with the descriptors of the classes in args.
689  * This is the concatenation of the descriptors with no other adornment,
690  * consistent with dexProtoGetParameterDescriptors.
691  */
692 static void createTargetDescriptor(ArrayObject* args,
693     DexStringCache* targetDescriptorCache)
694 {
695     ClassObject** argsArray = (ClassObject**)(void*)args->contents;
696     size_t length = 1; /* +1 for the terminating '\0' */
697     for (size_t i = 0; i < args->length; ++i) {
698         length += strlen(argsArray[i]->descriptor);
699     }
700
701     dexStringCacheAlloc(targetDescriptorCache, length);
702
703     char* at = (char*) targetDescriptorCache->value;
704     for (size_t i = 0; i < args->length; ++i) {
705         const char* descriptor = argsArray[i]->descriptor;
706         strcpy(at, descriptor);
707         at += strlen(descriptor);
708     }
709 }
710
711 static Object* findConstructorOrMethodInArray(int methodsCount, Method* methods,
712     const char* name, const char* parameterDescriptors)
713 {
714     Method* method = NULL;
715     Method* result = NULL;
716     int i;
717
718     for (i = 0; i < methodsCount; ++i) {
719         method = &methods[i];
720         if (strcmp(name, method->name) != 0
721             || dvmIsMirandaMethod(method)
722             || dexProtoCompareToParameterDescriptors(&method->prototype,
723                     parameterDescriptors) != 0) {
724             continue;
725         }
726
727         result = method;
728
729         /*
730          * Covariant return types permit the class to define multiple
731          * methods with the same name and parameter types. Prefer to return
732          * a non-synthetic method in such situations. We may still return
733          * a synthetic method to handle situations like escalated visibility.
734          */
735         if (!dvmIsSyntheticMethod(method)) {
736             break;
737         }
738     }
739
740     if (result != NULL) {
741         return dvmCreateReflectObjForMethod(result->clazz, result);
742     }
743
744     return NULL;
745 }
746
747 /*
748  * Get the named method.
749  */
750 Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
751     StringObject* nameObj, ArrayObject* args)
752 {
753     Object* result = NULL;
754     DexStringCache targetDescriptorCache;
755     char* name;
756     const char* targetDescriptor;
757
758     dexStringCacheInit(&targetDescriptorCache);
759
760     name = dvmCreateCstrFromString(nameObj);
761     createTargetDescriptor(args, &targetDescriptorCache);
762     targetDescriptor = targetDescriptorCache.value;
763
764     result = findConstructorOrMethodInArray(clazz->directMethodCount,
765         clazz->directMethods, name, targetDescriptor);
766     if (result == NULL) {
767         result = findConstructorOrMethodInArray(clazz->virtualMethodCount,
768             clazz->virtualMethods, name, targetDescriptor);
769     }
770
771     free(name);
772     dexStringCacheRelease(&targetDescriptorCache);
773     return result;
774 }
775
776 /*
777  * Get the named field.
778  */
779 Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj)
780 {
781     int i;
782     Object* fieldObj = NULL;
783     char* name = dvmCreateCstrFromString(nameObj);
784
785     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
786         dvmInitClass(gDvm.classJavaLangReflectField);
787
788     for (i = 0; i < clazz->sfieldCount; i++) {
789         Field* field = &clazz->sfields[i];
790         if (strcmp(name, field->name) == 0) {
791             fieldObj = createFieldObject(field, clazz);
792             break;
793         }
794     }
795     if (fieldObj == NULL) {
796         for (i = 0; i < clazz->ifieldCount; i++) {
797             Field* field = &clazz->ifields[i];
798             if (strcmp(name, field->name) == 0) {
799                 fieldObj = createFieldObject(field, clazz);
800                 break;
801             }
802         }
803     }
804
805     free(name);
806     return fieldObj;
807 }
808
809 /*
810  * Get all interfaces a class implements. If this is unable to allocate
811  * the result array, this raises an OutOfMemoryError and returns NULL.
812  */
813 ArrayObject* dvmGetInterfaces(ClassObject* clazz)
814 {
815     if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
816         dvmInitClass(gDvm.classJavaLangReflectMethod);
817
818     /*
819      * Create an array of Class objects.
820      */
821     size_t count = clazz->interfaceCount;
822     ArrayObject* interfaceArray =
823         dvmAllocArrayByClass(gDvm.classJavaLangClassArray, count, ALLOC_DEFAULT);
824     if (interfaceArray == NULL)
825         return NULL;
826
827     /*
828      * Fill out the array.
829      */
830     memcpy(interfaceArray->contents, clazz->interfaces,
831            count * sizeof(Object *));
832     dvmWriteBarrierArray(interfaceArray, 0, count);
833
834     /* caller must call dvmReleaseTrackedAlloc */
835     return interfaceArray;
836 }
837
838 /*
839  * Given a boxed primitive type, such as java/lang/Integer, return the
840  * primitive type index.
841  *
842  * Returns PRIM_NOT for void, since we never "box" that.
843  */
844 static PrimitiveType getBoxedType(DataObject* arg)
845 {
846     static const int kJavaLangLen = 11;     // strlen("Ljava/lang/")
847
848     if (arg == NULL)
849         return PRIM_NOT;
850
851     const char* name = arg->clazz->descriptor;
852
853     if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0)
854         return PRIM_NOT;
855
856     if (strcmp(name + kJavaLangLen, "Boolean;") == 0)
857         return PRIM_BOOLEAN;
858     if (strcmp(name + kJavaLangLen, "Character;") == 0)
859         return PRIM_CHAR;
860     if (strcmp(name + kJavaLangLen, "Float;") == 0)
861         return PRIM_FLOAT;
862     if (strcmp(name + kJavaLangLen, "Double;") == 0)
863         return PRIM_DOUBLE;
864     if (strcmp(name + kJavaLangLen, "Byte;") == 0)
865         return PRIM_BYTE;
866     if (strcmp(name + kJavaLangLen, "Short;") == 0)
867         return PRIM_SHORT;
868     if (strcmp(name + kJavaLangLen, "Integer;") == 0)
869         return PRIM_INT;
870     if (strcmp(name + kJavaLangLen, "Long;") == 0)
871         return PRIM_LONG;
872     return PRIM_NOT;
873 }
874
875 /*
876  * Convert primitive, boxed data from "srcPtr" to "dstPtr".
877  *
878  * Section v2 2.6 lists the various conversions and promotions.  We
879  * allow the "widening" and "identity" conversions, but don't allow the
880  * "narrowing" conversions.
881  *
882  * Allowed:
883  *  byte to short, int, long, float, double
884  *  short to int, long, float double
885  *  char to int, long, float, double
886  *  int to long, float, double
887  *  long to float, double
888  *  float to double
889  * Values of types byte, char, and short are "internally" widened to int.
890  *
891  * Returns the width in 32-bit words of the destination primitive, or
892  * -1 if the conversion is not allowed.
893  *
894  * TODO? use JValue rather than u4 pointers
895  */
896 int dvmConvertPrimitiveValue(PrimitiveType srcType,
897     PrimitiveType dstType, const s4* srcPtr, s4* dstPtr)
898 {
899     enum Conversion {
900         OK4, OK8, ItoJ, ItoD, JtoD, FtoD, ItoF, JtoF, bad
901     };
902
903     enum Conversion conv;
904 #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  */
1014 int 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  */
1060 DataObject* 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  */
1113 bool 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  */
1156 ClassObject* 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  */
1189 Field* 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  */
1209 Method* 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  */
1241 Object* 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  */
1260 Object* 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 }