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