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