OSDN Git Service

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