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