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