2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * Basic reflection calls and utility functions.
26 bool dvmReflectStartup(void)
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)
53 LOGE("Could not find one or more reflection classes\n");
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)
70 LOGE("Could not find reflection constructors\n");
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)
81 LOGE("Could not find class-array or object-array class\n");
85 gDvm.offJavaLangReflectAccessibleObject_flag =
86 dvmFindFieldOffset(gDvm.classJavaLangReflectAccessibleObject, "flag",
89 gDvm.offJavaLangReflectConstructor_slot =
90 dvmFindFieldOffset(gDvm.classJavaLangReflectConstructor, "slot", "I");
91 gDvm.offJavaLangReflectConstructor_declClass =
92 dvmFindFieldOffset(gDvm.classJavaLangReflectConstructor,
93 "declaringClass", "Ljava/lang/Class;");
95 gDvm.offJavaLangReflectField_slot =
96 dvmFindFieldOffset(gDvm.classJavaLangReflectField, "slot", "I");
97 gDvm.offJavaLangReflectField_declClass =
98 dvmFindFieldOffset(gDvm.classJavaLangReflectField,
99 "declaringClass", "Ljava/lang/Class;");
101 gDvm.offJavaLangReflectMethod_slot =
102 dvmFindFieldOffset(gDvm.classJavaLangReflectMethod, "slot", "I");
103 gDvm.offJavaLangReflectMethod_declClass =
104 dvmFindFieldOffset(gDvm.classJavaLangReflectMethod,
105 "declaringClass", "Ljava/lang/Class;");
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)
115 LOGE("Could not find reflection fields\n");
119 if (!dvmReflectProxyStartup())
121 if (!dvmReflectAnnotationStartup())
130 void dvmReflectShutdown(void)
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.
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.
144 bool dvmValidateBoxClasses()
146 static const char* classes[] = {
147 "Ljava/lang/Boolean;",
148 "Ljava/lang/Character;",
150 "Ljava/lang/Double;",
153 "Ljava/lang/Integer;",
159 for (ccp = classes; *ccp != NULL; ccp++) {
162 clazz = dvmFindClassNoInit(*ccp, NULL);
164 LOGE("Couldn't find '%s'\n", *ccp);
168 if (clazz->ifieldCount != 1) {
169 LOGE("Found %d instance fields in '%s'\n",
170 clazz->ifieldCount, *ccp);
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.
184 * "pSig" will be advanced to the start of the next token.
186 static ClassObject* convertSignaturePartToClass(char** pSignature,
187 const ClassObject* defClass)
189 ClassObject* clazz = NULL;
190 char* signature = *pSignature;
192 if (*signature == '[') {
193 /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */
196 while (*++signature == '[')
198 if (*signature == 'L') {
199 while (*++signature != ';')
203 /* advance past ';', and stomp on whatever comes next */
204 savedChar = *++signature;
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 */
211 while (*++signature != ';')
213 savedChar = *++signature;
215 clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader);
216 *signature = savedChar;
218 clazz = dvmFindPrimitiveClass(*signature++);
222 LOGW("Unable to match class for part: '%s'\n", *pSignature);
224 *pSignature = signature;
229 * Convert the method signature to an array of classes.
231 * The tokenization process may mangle "*pSignature". On return, it will
232 * be pointing at the closing ')'.
234 * "defClass" is the method's class, which is needed to make class loaders
237 static ArrayObject* convertSignatureToClassArray(char** pSignature,
238 ClassObject* defClass)
240 ArrayObject* classArray;
241 char* signature = *pSignature;
245 assert(*signature == '(');
248 /* count up the number of parameters */
264 LOGVV("REFLECT found %d parameters in '%s'\n", count, *pSignature);
266 /* create an array to hold them */
267 classArray = dvmAllocArray(gDvm.classJavaLangClassArray, count,
268 kObjectArrayRefWidth, ALLOC_DEFAULT);
269 if (classArray == NULL)
274 for (i = 0; i < count; i++) {
277 clazz = convertSignaturePartToClass(&cp, defClass);
279 assert(dvmCheckException(dvmThreadSelf()));
282 LOGVV("REFLECT %d: '%s'\n", i, clazz->descriptor);
283 dvmSetObjectArrayElement(classArray, i, (Object *)clazz);
288 /* caller must call dvmReleaseTrackedAlloc */
294 * Convert a field pointer to a slot number.
296 * We use positive values starting from 0 for instance fields, negative
297 * values starting from -1 for static fields.
299 static int fieldToSlot(const Field* field, const ClassObject* clazz)
303 if (dvmIsStaticField(field)) {
304 slot = (StaticField*)field - &clazz->sfields[0];
305 assert(slot >= 0 && slot < clazz->sfieldCount);
308 slot = (InstField*)field - clazz->ifields;
309 assert(slot >= 0 && slot < clazz->ifieldCount);
316 * Convert a slot number to a field pointer.
318 Field* dvmSlotToField(ClassObject* clazz, int slot)
322 assert(slot < clazz->sfieldCount);
323 return (Field*) &clazz->sfields[slot];
325 assert(slot < clazz->ifieldCount);
326 return (Field*) &clazz->ifields[slot];
331 * Create a new java.lang.reflect.Field object from "field".
333 * The Field spec doesn't specify the constructor. We're going to use the
334 * one from our existing class libs:
336 * private Field(Class declaringClass, Class type, String name, int slot)
338 static Object* createFieldObject(Field* field, const ClassObject* clazz)
340 Object* result = NULL;
341 Object* fieldObj = NULL;
342 StringObject* nameObj = NULL;
348 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField));
350 fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT);
351 if (fieldObj == NULL)
354 cp = mangle = strdup(field->signature);
355 type = convertSignaturePartToClass(&cp, clazz);
360 nameObj = dvmCreateStringFromCstr(field->name);
364 slot = fieldToSlot(field, clazz);
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");
377 dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
379 dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
380 /* caller must dvmReleaseTrackedAlloc(result) */
386 * Get an array with all fields declared by a class.
388 * This includes both static and instance fields.
390 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
392 ArrayObject* fieldArray = NULL;
395 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
396 dvmInitClass(gDvm.classJavaLangReflectField);
398 /* count #of fields */
400 count = clazz->sfieldCount + clazz->ifieldCount;
403 for (i = 0; i < clazz->sfieldCount; i++) {
404 if ((clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0)
407 for (i = 0; i < clazz->ifieldCount; i++) {
408 if ((clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0)
413 /* create the Field[] array */
414 fieldArray = dvmAllocArray(gDvm.classJavaLangReflectFieldArray, count,
415 kObjectArrayRefWidth, ALLOC_DEFAULT);
416 if (fieldArray == NULL)
420 size_t fieldCount = 0;
421 for (i = 0; i < clazz->sfieldCount; i++) {
423 (clazz->sfields[i].field.accessFlags & ACC_PUBLIC) != 0)
425 Object* field = createFieldObject(&clazz->sfields[i].field, clazz);
429 dvmSetObjectArrayElement(fieldArray, fieldCount, field);
430 dvmReleaseTrackedAlloc(field, NULL);
434 for (i = 0; i < clazz->ifieldCount; i++) {
436 (clazz->ifields[i].field.accessFlags & ACC_PUBLIC) != 0)
438 Object* field = createFieldObject(&clazz->ifields[i].field, clazz);
442 dvmSetObjectArrayElement(fieldArray, fieldCount, field);
443 dvmReleaseTrackedAlloc(field, NULL);
448 assert(fieldCount == fieldArray->length);
450 /* caller must call dvmReleaseTrackedAlloc */
454 dvmReleaseTrackedAlloc((Object*) fieldArray, NULL);
460 * Convert a method pointer to a slot number.
462 * We use positive values starting from 0 for virtual methods, negative
463 * values starting from -1 for static methods.
465 static int methodToSlot(const Method* meth)
467 ClassObject* clazz = meth->clazz;
470 if (dvmIsDirectMethod(meth)) {
471 slot = meth - clazz->directMethods;
472 assert(slot >= 0 && slot < clazz->directMethodCount);
475 slot = meth - clazz->virtualMethods;
476 assert(slot >= 0 && slot < clazz->virtualMethodCount);
483 * Convert a slot number to a method pointer.
485 Method* dvmSlotToMethod(ClassObject* clazz, int slot)
489 assert(slot < clazz->directMethodCount);
490 return &clazz->directMethods[slot];
492 assert(slot < clazz->virtualMethodCount);
493 return &clazz->virtualMethods[slot];
498 * Create a new java/lang/reflect/Constructor object, using the contents of
499 * "meth" to construct it.
501 * The spec doesn't specify the constructor. We're going to use the
502 * one from our existing class libs:
504 * private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes,
507 static Object* createConstructorObject(Method* meth)
509 Object* result = NULL;
510 ArrayObject* params = NULL;
511 ArrayObject* exceptions = NULL;
513 DexStringCache mangle;
517 dexStringCacheInit(&mangle);
519 /* parent should guarantee init so we don't have to check on every call */
520 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor));
522 consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor,
528 * Convert the signature string into an array of classes representing
531 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
532 params = convertSignatureToClassArray(&cp, meth->clazz);
536 assert(*(cp+1) == 'V');
539 * Create an array with one entry for every exception that the class
540 * is declared to throw.
542 exceptions = dvmGetMethodThrows(meth);
543 if (dvmCheckException(dvmThreadSelf()))
546 slot = methodToSlot(meth);
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");
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);
566 /* caller must dvmReleaseTrackedAlloc(result) */
571 * Get an array with all constructors declared by a class.
573 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
575 ArrayObject* consArray;
579 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
580 dvmInitClass(gDvm.classJavaLangReflectConstructor);
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.
586 if (!dvmIsClassInitialized(clazz))
590 * Count up the #of relevant methods.
593 meth = clazz->directMethods;
594 for (i = 0; i < clazz->directMethodCount; i++, meth++) {
595 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
596 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
603 * Create an array of Constructor objects.
605 consArray = dvmAllocArray(gDvm.classJavaLangReflectConstructorArray, count,
606 kObjectArrayRefWidth, ALLOC_DEFAULT);
607 if (consArray == NULL)
611 * Fill out the array.
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))
619 Object* consObj = createConstructorObject(meth);
622 dvmSetObjectArrayElement(consArray, consObjCount, consObj);
624 dvmReleaseTrackedAlloc(consObj, NULL);
628 assert(consObjCount == consArray->length);
630 /* caller must call dvmReleaseTrackedAlloc */
634 dvmReleaseTrackedAlloc((Object*) consArray, NULL);
639 * Create a new java/lang/reflect/Method object, using the contents of
640 * "meth" to construct it.
642 * The spec doesn't specify the constructor. We're going to use the
643 * one from our existing class libs:
645 * private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes,
646 * Class returnType, String name, int slot)
648 * The caller must call dvmReleaseTrackedAlloc() on the result.
650 Object* dvmCreateReflectMethodObject(const Method* meth)
652 Object* result = NULL;
653 ArrayObject* params = NULL;
654 ArrayObject* exceptions = NULL;
655 StringObject* nameObj = NULL;
657 ClassObject* returnType;
658 DexStringCache mangle;
662 if (dvmCheckException(dvmThreadSelf())) {
663 LOGW("WARNING: dvmCreateReflectMethodObject called with "
664 "exception pending\n");
668 dexStringCacheInit(&mangle);
670 /* parent should guarantee init so we don't have to check on every call */
671 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod));
673 methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT);
678 * Convert the signature string into an array of classes representing
679 * the arguments, and a class for the return type.
681 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
682 params = convertSignatureToClassArray(&cp, meth->clazz);
687 returnType = convertSignaturePartToClass(&cp, meth->clazz);
688 if (returnType == NULL)
692 * Create an array with one entry for every exception that the class
693 * is declared to throw.
695 exceptions = dvmGetMethodThrows(meth);
696 if (dvmCheckException(dvmThreadSelf()))
700 nameObj = dvmCreateStringFromCstr(meth->name);
704 slot = methodToSlot(meth);
707 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init,
708 methObj, &unused, meth->clazz, params, exceptions, returnType,
710 if (dvmCheckException(dvmThreadSelf())) {
711 LOGD("Method class init threw exception\n");
718 dexStringCacheRelease(&mangle);
719 if (result == NULL) {
720 assert(dvmCheckException(dvmThreadSelf()));
722 dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
723 dvmReleaseTrackedAlloc((Object*) params, NULL);
724 dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
726 dvmReleaseTrackedAlloc(methObj, NULL);
731 * Get an array with all methods declared by a class.
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.
737 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
739 ArrayObject* methodArray;
743 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
744 dvmInitClass(gDvm.classJavaLangReflectMethod);
747 * Count up the #of relevant methods.
749 * Ignore virtual Miranda methods and direct class/object constructors.
752 meth = clazz->virtualMethods;
753 for (i = 0; i < clazz->virtualMethodCount; i++, meth++) {
754 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
755 !dvmIsMirandaMethod(meth))
760 meth = clazz->directMethods;
761 for (i = 0; i < clazz->directMethodCount; i++, meth++) {
762 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
763 meth->name[0] != '<')
770 * Create an array of Method objects.
772 methodArray = dvmAllocArray(gDvm.classJavaLangReflectMethodArray, count,
773 kObjectArrayRefWidth, ALLOC_DEFAULT);
774 if (methodArray == NULL)
779 * Fill out the array.
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))
787 Object* methObj = dvmCreateReflectMethodObject(meth);
790 dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
792 dvmReleaseTrackedAlloc(methObj, NULL);
795 meth = clazz->directMethods;
796 for (i = 0; i < clazz->directMethodCount; i++, meth++) {
797 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
798 meth->name[0] != '<')
800 Object* methObj = dvmCreateReflectMethodObject(meth);
803 dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
805 dvmReleaseTrackedAlloc(methObj, NULL);
809 assert(methObjCount == methodArray->length);
811 /* caller must call dvmReleaseTrackedAlloc */
815 dvmReleaseTrackedAlloc((Object*) methodArray, NULL);
820 * Get all interfaces a class implements. If this is unable to allocate
821 * the result array, this raises an OutOfMemoryError and returns NULL.
823 ArrayObject* dvmGetInterfaces(ClassObject* clazz)
825 ArrayObject* interfaceArray;
827 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
828 dvmInitClass(gDvm.classJavaLangReflectMethod);
831 * Create an array of Class objects.
833 int count = clazz->interfaceCount;
834 interfaceArray = dvmAllocArray(gDvm.classJavaLangClassArray, count,
835 kObjectArrayRefWidth, ALLOC_DEFAULT);
836 if (interfaceArray == NULL)
840 * Fill out the array.
842 memcpy(interfaceArray->contents, clazz->interfaces,
843 count * sizeof(Object *));
844 dvmWriteBarrierArray(interfaceArray, 0, count);
846 /* caller must call dvmReleaseTrackedAlloc */
847 return interfaceArray;
851 * Given a boxed primitive type, such as java/lang/Integer, return the
852 * primitive type index.
854 * Returns PRIM_NOT for void, since we never "box" that.
856 static PrimitiveType getBoxedType(DataObject* arg)
858 static const int kJavaLangLen = 11; // strlen("Ljava/lang/")
864 name = arg->obj.clazz->descriptor;
866 if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0)
869 if (strcmp(name + kJavaLangLen, "Boolean;") == 0)
871 if (strcmp(name + kJavaLangLen, "Character;") == 0)
873 if (strcmp(name + kJavaLangLen, "Float;") == 0)
875 if (strcmp(name + kJavaLangLen, "Double;") == 0)
877 if (strcmp(name + kJavaLangLen, "Byte;") == 0)
879 if (strcmp(name + kJavaLangLen, "Short;") == 0)
881 if (strcmp(name + kJavaLangLen, "Integer;") == 0)
883 if (strcmp(name + kJavaLangLen, "Long;") == 0)
889 * Convert primitive, boxed data from "srcPtr" to "dstPtr".
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.
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
902 * Values of types byte, char, and short are "internally" widened to int.
904 * Returns the width in bytes of the destination primitive, or -1 if the
905 * conversion is not allowed.
907 * TODO? use JValue rather than u4 pointers
909 int dvmConvertPrimitiveValue(PrimitiveType srcType,
910 PrimitiveType dstType, const s4* srcPtr, s4* dstPtr)
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 },
932 assert(srcType != PRIM_NOT && dstType != PRIM_NOT &&
933 srcType != PRIM_VOID && dstType != PRIM_VOID);
934 result = kConvMode[srcType][dstType];
936 //LOGV("+++ convprim: src=%d dst=%d result=%d\n", srcType, dstType, result);
943 *(s8*)dstPtr = *(s8*)srcPtr;
946 *(s8*)dstPtr = (s8) (*(s4*) srcPtr);
949 *(double*)dstPtr = (double) (*(s4*) srcPtr);
952 *(double*)dstPtr = (double) (*(long long*) srcPtr);
955 *(double*)dstPtr = (double) (*(float*) srcPtr);
958 *(float*)dstPtr = (float) (*(int*) srcPtr);
961 *(float*)dstPtr = (float) (*(long long*) srcPtr);
964 LOGV("convert primitive: prim %d to %d not allowed\n",
974 * Convert types and widen primitives. Puts the value of "arg" into
977 * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error.
979 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr)
983 if (dvmIsPrimitiveClass(type)) {
984 /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */
985 PrimitiveType srcType;
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);
995 /* assumes value is stored in first instance field */
996 valuePtr = (s4*) arg->instanceData;
998 retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType,
1001 /* verify object is compatible */
1002 if ((arg == NULL) || dvmInstanceof(arg->obj.clazz, type)) {
1003 *destPtr = (s4) arg;
1006 LOGVV("Arg %p (%s) not compatible with %s\n",
1007 arg, arg->obj.clazz->descriptor, type->descriptor);
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.
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.
1023 * The caller must call dvmReleaseTrackedAlloc on the result.
1025 DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType)
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;",
1033 "Ljava/lang/Short;",
1034 "Ljava/lang/Integer;",
1037 ClassObject* wrapperClass;
1038 DataObject* wrapperObj;
1040 PrimitiveType typeIndex = returnType->primitiveType;
1041 const char* classDescriptor;
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;
1050 assert(typeIndex >= 0 && typeIndex < PRIM_MAX);
1051 if (typeIndex == PRIM_VOID)
1054 classDescriptor = boxTypes[typeIndex];
1056 wrapperClass = dvmFindSystemClass(classDescriptor);
1057 if (wrapperClass == NULL) {
1058 LOGW("Unable to find '%s'\n", classDescriptor);
1059 assert(dvmCheckException(dvmThreadSelf()));
1063 wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT);
1064 if (wrapperObj == NULL)
1066 dataPtr = (s4*) wrapperObj->instanceData;
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;
1079 * Unwrap a primitive data type, if necessary.
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.
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.
1087 * Returns "true" on success, "false" on failure.
1089 bool dvmUnboxPrimitive(Object* value, ClassObject* returnType,
1092 PrimitiveType typeIndex = returnType->primitiveType;
1093 PrimitiveType valueIndex;
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);
1103 } else if (typeIndex == PRIM_VOID) {
1104 /* can't put anything into a void */
1108 valueIndex = getBoxedType((DataObject*)value);
1109 if (valueIndex == PRIM_NOT)
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)
1117 LOGV("Prim conversion failed\n");
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.
1130 * On failure, we return NULL with an exception raised.
1132 ClassObject* dvmGetBoxedReturnType(const Method* meth)
1134 const char* sig = dexProtoGetReturnType(&meth->prototype);
1146 return dvmFindPrimitiveClass(*sig);
1149 return dvmFindClass(sig, meth->clazz->classLoader);
1151 /* should not have passed verification */
1152 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1153 LOGE("Bad return type in signature '%s'\n", desc);
1155 dvmThrowException("Ljava/lang/InternalError;", NULL);
1163 * JNI reflection support: convert reflection object to Field ptr.
1165 Field* dvmGetFieldFromReflectObj(Object* obj)
1170 assert(obj->clazz == gDvm.classJavaLangReflectField);
1171 clazz = (ClassObject*)dvmGetFieldObject(obj,
1172 gDvm.offJavaLangReflectField_declClass);
1173 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot);
1175 /* must initialize the class before returning a field ID */
1176 if (!dvmInitClass(clazz))
1179 return dvmSlotToField(clazz, slot);
1183 * JNI reflection support: convert reflection object to Method ptr.
1185 Method* dvmGetMethodFromReflectObj(Object* obj)
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);
1203 /* must initialize the class before returning a method ID */
1204 if (!dvmInitClass(clazz))
1207 return dvmSlotToMethod(clazz, slot);
1211 * JNI reflection support: convert Field to reflection object.
1213 * The return value is a java.lang.reflect.Field.
1215 * Caller must call dvmReleaseTrackedAlloc().
1217 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field)
1219 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
1220 dvmInitClass(gDvm.classJavaLangReflectField);
1222 /* caller must dvmReleaseTrackedAlloc(result) */
1223 return createFieldObject(field, clazz);
1227 * JNI reflection support: convert Method to reflection object.
1229 * The returned object will be either a java.lang.reflect.Method or
1230 * .Constructor, depending on whether "method" is a constructor.
1232 * This is also used for certain "system" annotations.
1234 * Caller must call dvmReleaseTrackedAlloc().
1236 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method)
1238 UNUSED_PARAMETER(clazz);
1240 if (strcmp(method->name, "<init>") == 0) {
1241 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
1242 dvmInitClass(gDvm.classJavaLangReflectConstructor);
1244 return createConstructorObject(method);
1246 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
1247 dvmInitClass(gDvm.classJavaLangReflectMethod);
1249 return dvmCreateReflectMethodObject(method);