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.
24 * For some of the reflection stuff we need to un-box primitives, e.g.
25 * convert a java/lang/Integer to int or even a float. We assume that
26 * the first instance field holds the value.
28 * To verify this, we either need to ensure that the class has only one
29 * instance field, or we need to look up the field by name and verify
30 * that it comes first. The former is simpler, and should work.
32 bool dvmValidateBoxClasses()
34 static const char* classes[] = {
35 "Ljava/lang/Boolean;",
36 "Ljava/lang/Character;",
41 "Ljava/lang/Integer;",
47 for (ccp = classes; *ccp != NULL; ccp++) {
50 clazz = dvmFindClassNoInit(*ccp, NULL);
52 ALOGE("Couldn't find '%s'", *ccp);
56 if (clazz->ifieldCount != 1) {
57 ALOGE("Found %d instance fields in '%s'",
58 clazz->ifieldCount, *ccp);
68 * Find the named class object. We have to trim "*pSignature" down to just
69 * the first token, do the lookup, and then restore anything important
70 * that we've stomped on.
72 * "pSig" will be advanced to the start of the next token.
74 static ClassObject* convertSignaturePartToClass(char** pSignature,
75 const ClassObject* defClass)
77 ClassObject* clazz = NULL;
78 char* signature = *pSignature;
80 if (*signature == '[') {
81 /* looks like "[[[Landroid/debug/Stuff;"; we want the whole thing */
84 while (*++signature == '[')
86 if (*signature == 'L') {
87 while (*++signature != ';')
91 /* advance past ';', and stomp on whatever comes next */
92 savedChar = *++signature;
94 clazz = dvmFindArrayClass(*pSignature, defClass->classLoader);
95 *signature = savedChar;
96 } else if (*signature == 'L') {
97 /* looks like 'Landroid/debug/Stuff;"; we want the whole thing */
99 while (*++signature != ';')
101 savedChar = *++signature;
103 clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader);
104 *signature = savedChar;
106 clazz = dvmFindPrimitiveClass(*signature++);
110 ALOGW("Unable to match class for part: '%s'", *pSignature);
112 *pSignature = signature;
117 * Convert the method signature to an array of classes.
119 * The tokenization process may mangle "*pSignature". On return, it will
120 * be pointing at the closing ')'.
122 * "defClass" is the method's class, which is needed to make class loaders
125 static ArrayObject* convertSignatureToClassArray(char** pSignature,
126 ClassObject* defClass)
128 char* signature = *pSignature;
130 assert(*signature == '(');
133 /* count up the number of parameters */
135 char* cp = signature;
149 LOGVV("REFLECT found %d parameters in '%s'", count, *pSignature);
151 /* create an array to hold them */
152 ArrayObject* classArray = dvmAllocArrayByClass(gDvm.classJavaLangClassArray,
153 count, ALLOC_DEFAULT);
154 if (classArray == NULL)
159 for (size_t i = 0; i < count; i++) {
160 ClassObject* clazz = convertSignaturePartToClass(&cp, defClass);
162 assert(dvmCheckException(dvmThreadSelf()));
165 LOGVV("REFLECT %d: '%s'", i, clazz->descriptor);
166 dvmSetObjectArrayElement(classArray, i, (Object *)clazz);
171 /* caller must call dvmReleaseTrackedAlloc */
177 * Convert a field pointer to a slot number.
179 * We use positive values starting from 0 for instance fields, negative
180 * values starting from -1 for static fields.
182 static int fieldToSlot(const Field* field, const ClassObject* clazz)
186 if (dvmIsStaticField(field)) {
187 slot = (StaticField*)field - &clazz->sfields[0];
188 assert(slot >= 0 && slot < clazz->sfieldCount);
191 slot = (InstField*)field - clazz->ifields;
192 assert(slot >= 0 && slot < clazz->ifieldCount);
199 * Convert a slot number to a field pointer.
201 Field* dvmSlotToField(ClassObject* clazz, int slot)
205 assert(slot < clazz->sfieldCount);
206 return (Field*)(void*)&clazz->sfields[slot];
208 assert(slot < clazz->ifieldCount);
209 return (Field*)(void*)&clazz->ifields[slot];
214 * Create a new java.lang.reflect.Field object from "field".
216 * The Field spec doesn't specify the constructor. We're going to use the
217 * one from our existing class libs:
219 * private Field(Class declaringClass, Class type, String name, int slot)
221 static Object* createFieldObject(Field* field, const ClassObject* clazz)
223 Object* result = NULL;
224 Object* fieldObj = NULL;
225 StringObject* nameObj = NULL;
231 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectField));
233 fieldObj = dvmAllocObject(gDvm.classJavaLangReflectField, ALLOC_DEFAULT);
234 if (fieldObj == NULL)
237 cp = mangle = strdup(field->signature);
238 type = convertSignaturePartToClass(&cp, clazz);
243 nameObj = dvmCreateStringFromCstr(field->name);
247 slot = fieldToSlot(field, clazz);
250 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectField_init,
251 fieldObj, &unused, clazz, type, nameObj, slot);
252 if (dvmCheckException(dvmThreadSelf())) {
253 ALOGD("Field class init threw exception");
260 dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
262 dvmReleaseTrackedAlloc((Object*) fieldObj, NULL);
263 /* caller must dvmReleaseTrackedAlloc(result) */
269 * Get an array with all fields declared by a class.
271 * This includes both static and instance fields.
273 ArrayObject* dvmGetDeclaredFields(ClassObject* clazz, bool publicOnly)
275 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
276 dvmInitClass(gDvm.classJavaLangReflectField);
278 /* count #of fields */
281 count = clazz->sfieldCount + clazz->ifieldCount;
284 for (int i = 0; i < clazz->sfieldCount; i++) {
285 if ((clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
288 for (int i = 0; i < clazz->ifieldCount; i++) {
289 if ((clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
294 /* create the Field[] array */
295 ArrayObject* fieldArray =
296 dvmAllocArrayByClass(gDvm.classJavaLangReflectFieldArray, count, ALLOC_DEFAULT);
297 if (fieldArray == NULL)
301 size_t fieldCount = 0;
302 for (int i = 0; i < clazz->sfieldCount; i++) {
304 (clazz->sfields[i].accessFlags & ACC_PUBLIC) != 0)
306 Object* field = createFieldObject(&clazz->sfields[i], clazz);
310 dvmSetObjectArrayElement(fieldArray, fieldCount, field);
311 dvmReleaseTrackedAlloc(field, NULL);
315 for (int i = 0; i < clazz->ifieldCount; i++) {
317 (clazz->ifields[i].accessFlags & ACC_PUBLIC) != 0)
319 Object* field = createFieldObject(&clazz->ifields[i], clazz);
323 dvmSetObjectArrayElement(fieldArray, fieldCount, field);
324 dvmReleaseTrackedAlloc(field, NULL);
329 assert(fieldCount == fieldArray->length);
331 /* caller must call dvmReleaseTrackedAlloc */
335 dvmReleaseTrackedAlloc((Object*) fieldArray, NULL);
341 * Convert a method pointer to a slot number.
343 * We use positive values starting from 0 for virtual methods, negative
344 * values starting from -1 for static methods.
346 static int methodToSlot(const Method* meth)
348 ClassObject* clazz = meth->clazz;
351 if (dvmIsDirectMethod(meth)) {
352 slot = meth - clazz->directMethods;
353 assert(slot >= 0 && slot < clazz->directMethodCount);
356 slot = meth - clazz->virtualMethods;
357 assert(slot >= 0 && slot < clazz->virtualMethodCount);
364 * Convert a slot number to a method pointer.
366 Method* dvmSlotToMethod(ClassObject* clazz, int slot)
370 assert(slot < clazz->directMethodCount);
371 return &clazz->directMethods[slot];
373 assert(slot < clazz->virtualMethodCount);
374 return &clazz->virtualMethods[slot];
379 * Create a new java/lang/reflect/Constructor object, using the contents of
380 * "meth" to construct it.
382 * The spec doesn't specify the constructor. We're going to use the
383 * one from our existing class libs:
385 * private Constructor (Class declaringClass, Class[] ptypes, Class[] extypes,
388 static Object* createConstructorObject(Method* meth)
390 Object* result = NULL;
391 ArrayObject* params = NULL;
392 ArrayObject* exceptions = NULL;
394 DexStringCache mangle;
398 dexStringCacheInit(&mangle);
400 /* parent should guarantee init so we don't have to check on every call */
401 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor));
403 consObj = dvmAllocObject(gDvm.classJavaLangReflectConstructor,
409 * Convert the signature string into an array of classes representing
412 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
413 params = convertSignatureToClassArray(&cp, meth->clazz);
417 assert(*(cp+1) == 'V');
420 * Create an array with one entry for every exception that the class
421 * is declared to throw.
423 exceptions = dvmGetMethodThrows(meth);
424 if (dvmCheckException(dvmThreadSelf()))
427 slot = methodToSlot(meth);
430 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectConstructor_init,
431 consObj, &unused, meth->clazz, params, exceptions, slot);
432 if (dvmCheckException(dvmThreadSelf())) {
433 ALOGD("Constructor class init threw exception");
440 dexStringCacheRelease(&mangle);
441 dvmReleaseTrackedAlloc((Object*) params, NULL);
442 dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
443 if (result == NULL) {
444 assert(dvmCheckException(dvmThreadSelf()));
445 dvmReleaseTrackedAlloc(consObj, NULL);
447 /* caller must dvmReleaseTrackedAlloc(result) */
452 * Get an array with all constructors declared by a class.
454 ArrayObject* dvmGetDeclaredConstructors(ClassObject* clazz, bool publicOnly)
456 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
457 dvmInitClass(gDvm.classJavaLangReflectConstructor);
460 * Ordinarily we init the class the first time we resolve a method.
461 * We're bypassing the normal resolution mechanism, so we init it here.
463 if (!dvmIsClassInitialized(clazz))
467 * Count up the #of relevant methods.
470 for (int i = 0; i < clazz->directMethodCount; ++i) {
471 Method* meth = &clazz->directMethods[i];
472 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
473 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
480 * Create an array of Constructor objects.
482 ClassObject* arrayClass = gDvm.classJavaLangReflectConstructorArray;
483 ArrayObject* ctorArray = dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
484 if (ctorArray == NULL)
488 * Fill out the array.
490 size_t ctorObjCount = 0;
491 for (int i = 0; i < clazz->directMethodCount; ++i) {
492 Method* meth = &clazz->directMethods[i];
493 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
494 dvmIsConstructorMethod(meth) && !dvmIsStaticMethod(meth))
496 Object* ctorObj = createConstructorObject(meth);
497 if (ctorObj == NULL) {
498 dvmReleaseTrackedAlloc((Object*) ctorArray, NULL);
501 dvmSetObjectArrayElement(ctorArray, ctorObjCount, ctorObj);
503 dvmReleaseTrackedAlloc(ctorObj, NULL);
507 assert(ctorObjCount == ctorArray->length);
509 /* caller must call dvmReleaseTrackedAlloc */
514 * Create a new java/lang/reflect/Method object, using the contents of
515 * "meth" to construct it.
517 * The spec doesn't specify the constructor. We're going to use the
518 * one from our existing class libs:
520 * private Method(Class declaring, Class[] paramTypes, Class[] exceptTypes,
521 * Class returnType, String name, int slot)
523 * The caller must call dvmReleaseTrackedAlloc() on the result.
525 Object* dvmCreateReflectMethodObject(const Method* meth)
527 Object* result = NULL;
528 ArrayObject* params = NULL;
529 ArrayObject* exceptions = NULL;
530 StringObject* nameObj = NULL;
532 ClassObject* returnType;
533 DexStringCache mangle;
537 if (dvmCheckException(dvmThreadSelf())) {
538 ALOGW("WARNING: dvmCreateReflectMethodObject called with "
539 "exception pending");
543 dexStringCacheInit(&mangle);
545 /* parent should guarantee init so we don't have to check on every call */
546 assert(dvmIsClassInitialized(gDvm.classJavaLangReflectMethod));
548 methObj = dvmAllocObject(gDvm.classJavaLangReflectMethod, ALLOC_DEFAULT);
553 * Convert the signature string into an array of classes representing
554 * the arguments, and a class for the return type.
556 cp = dvmCopyDescriptorStringFromMethod(meth, &mangle);
557 params = convertSignatureToClassArray(&cp, meth->clazz);
562 returnType = convertSignaturePartToClass(&cp, meth->clazz);
563 if (returnType == NULL)
567 * Create an array with one entry for every exception that the class
568 * is declared to throw.
570 exceptions = dvmGetMethodThrows(meth);
571 if (dvmCheckException(dvmThreadSelf()))
575 nameObj = dvmCreateStringFromCstr(meth->name);
579 slot = methodToSlot(meth);
582 dvmCallMethod(dvmThreadSelf(), gDvm.methJavaLangReflectMethod_init,
583 methObj, &unused, meth->clazz, params, exceptions, returnType,
585 if (dvmCheckException(dvmThreadSelf())) {
586 ALOGD("Method class init threw exception");
593 dexStringCacheRelease(&mangle);
594 if (result == NULL) {
595 assert(dvmCheckException(dvmThreadSelf()));
597 dvmReleaseTrackedAlloc((Object*) nameObj, NULL);
598 dvmReleaseTrackedAlloc((Object*) params, NULL);
599 dvmReleaseTrackedAlloc((Object*) exceptions, NULL);
601 dvmReleaseTrackedAlloc(methObj, NULL);
606 * Get an array with all methods declared by a class.
608 * This includes both static and virtual methods, and can include private
609 * members if "publicOnly" is false. It does not include Miranda methods,
610 * since those weren't declared in the class, or constructors.
612 ArrayObject* dvmGetDeclaredMethods(ClassObject* clazz, bool publicOnly)
614 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
615 dvmInitClass(gDvm.classJavaLangReflectMethod);
618 * Count up the #of relevant methods.
620 * Ignore virtual Miranda methods and direct class/object constructors.
623 Method* meth = clazz->virtualMethods;
624 for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
625 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
626 !dvmIsMirandaMethod(meth))
631 meth = clazz->directMethods;
632 for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
633 if ((!publicOnly || dvmIsPublicMethod(meth)) && meth->name[0] != '<') {
639 * Create an array of Method objects.
641 ArrayObject* methodArray =
642 dvmAllocArrayByClass(gDvm.classJavaLangReflectMethodArray, count, ALLOC_DEFAULT);
643 if (methodArray == NULL)
647 * Fill out the array.
649 meth = clazz->virtualMethods;
650 size_t methObjCount = 0;
651 for (int i = 0; i < clazz->virtualMethodCount; i++, meth++) {
652 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
653 !dvmIsMirandaMethod(meth))
655 Object* methObj = dvmCreateReflectMethodObject(meth);
658 dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
660 dvmReleaseTrackedAlloc(methObj, NULL);
663 meth = clazz->directMethods;
664 for (int i = 0; i < clazz->directMethodCount; i++, meth++) {
665 if ((!publicOnly || dvmIsPublicMethod(meth)) &&
666 meth->name[0] != '<')
668 Object* methObj = dvmCreateReflectMethodObject(meth);
671 dvmSetObjectArrayElement(methodArray, methObjCount, methObj);
673 dvmReleaseTrackedAlloc(methObj, NULL);
677 assert(methObjCount == methodArray->length);
679 /* caller must call dvmReleaseTrackedAlloc */
683 dvmReleaseTrackedAlloc((Object*) methodArray, NULL);
688 * Fills targetDescriptorCache with the descriptors of the classes in args.
689 * This is the concatenation of the descriptors with no other adornment,
690 * consistent with dexProtoGetParameterDescriptors.
692 static void createTargetDescriptor(ArrayObject* args,
693 DexStringCache* targetDescriptorCache)
695 ClassObject** argsArray = (ClassObject**)(void*)args->contents;
696 size_t length = 1; /* +1 for the terminating '\0' */
697 for (size_t i = 0; i < args->length; ++i) {
698 length += strlen(argsArray[i]->descriptor);
701 dexStringCacheAlloc(targetDescriptorCache, length);
703 char* at = (char*) targetDescriptorCache->value;
704 for (size_t i = 0; i < args->length; ++i) {
705 const char* descriptor = argsArray[i]->descriptor;
706 strcpy(at, descriptor);
707 at += strlen(descriptor);
711 static Object* findConstructorOrMethodInArray(int methodsCount, Method* methods,
712 const char* name, const char* parameterDescriptors)
714 Method* method = NULL;
715 Method* result = NULL;
718 for (i = 0; i < methodsCount; ++i) {
719 method = &methods[i];
720 if (strcmp(name, method->name) != 0
721 || dvmIsMirandaMethod(method)
722 || dexProtoCompareToParameterDescriptors(&method->prototype,
723 parameterDescriptors) != 0) {
730 * Covariant return types permit the class to define multiple
731 * methods with the same name and parameter types. Prefer to return
732 * a non-synthetic method in such situations. We may still return
733 * a synthetic method to handle situations like escalated visibility.
735 if (!dvmIsSyntheticMethod(method)) {
740 if (result != NULL) {
741 return dvmCreateReflectObjForMethod(result->clazz, result);
748 * Get the named method.
750 Object* dvmGetDeclaredConstructorOrMethod(ClassObject* clazz,
751 StringObject* nameObj, ArrayObject* args)
753 Object* result = NULL;
754 DexStringCache targetDescriptorCache;
756 const char* targetDescriptor;
758 dexStringCacheInit(&targetDescriptorCache);
760 name = dvmCreateCstrFromString(nameObj);
761 createTargetDescriptor(args, &targetDescriptorCache);
762 targetDescriptor = targetDescriptorCache.value;
764 result = findConstructorOrMethodInArray(clazz->directMethodCount,
765 clazz->directMethods, name, targetDescriptor);
766 if (result == NULL) {
767 result = findConstructorOrMethodInArray(clazz->virtualMethodCount,
768 clazz->virtualMethods, name, targetDescriptor);
772 dexStringCacheRelease(&targetDescriptorCache);
777 * Get the named field.
779 Object* dvmGetDeclaredField(ClassObject* clazz, StringObject* nameObj)
782 Object* fieldObj = NULL;
783 char* name = dvmCreateCstrFromString(nameObj);
785 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
786 dvmInitClass(gDvm.classJavaLangReflectField);
788 for (i = 0; i < clazz->sfieldCount; i++) {
789 Field* field = &clazz->sfields[i];
790 if (strcmp(name, field->name) == 0) {
791 fieldObj = createFieldObject(field, clazz);
795 if (fieldObj == NULL) {
796 for (i = 0; i < clazz->ifieldCount; i++) {
797 Field* field = &clazz->ifields[i];
798 if (strcmp(name, field->name) == 0) {
799 fieldObj = createFieldObject(field, clazz);
810 * Get all interfaces a class implements. If this is unable to allocate
811 * the result array, this raises an OutOfMemoryError and returns NULL.
813 ArrayObject* dvmGetInterfaces(ClassObject* clazz)
815 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
816 dvmInitClass(gDvm.classJavaLangReflectMethod);
819 * Create an array of Class objects.
821 size_t count = clazz->interfaceCount;
822 ArrayObject* interfaceArray =
823 dvmAllocArrayByClass(gDvm.classJavaLangClassArray, count, ALLOC_DEFAULT);
824 if (interfaceArray == NULL)
828 * Fill out the array.
830 memcpy(interfaceArray->contents, clazz->interfaces,
831 count * sizeof(Object *));
832 dvmWriteBarrierArray(interfaceArray, 0, count);
834 /* caller must call dvmReleaseTrackedAlloc */
835 return interfaceArray;
839 * Given a boxed primitive type, such as java/lang/Integer, return the
840 * primitive type index.
842 * Returns PRIM_NOT for void, since we never "box" that.
844 static PrimitiveType getBoxedType(DataObject* arg)
846 static const int kJavaLangLen = 11; // strlen("Ljava/lang/")
851 const char* name = arg->clazz->descriptor;
853 if (strncmp(name, "Ljava/lang/", kJavaLangLen) != 0)
856 if (strcmp(name + kJavaLangLen, "Boolean;") == 0)
858 if (strcmp(name + kJavaLangLen, "Character;") == 0)
860 if (strcmp(name + kJavaLangLen, "Float;") == 0)
862 if (strcmp(name + kJavaLangLen, "Double;") == 0)
864 if (strcmp(name + kJavaLangLen, "Byte;") == 0)
866 if (strcmp(name + kJavaLangLen, "Short;") == 0)
868 if (strcmp(name + kJavaLangLen, "Integer;") == 0)
870 if (strcmp(name + kJavaLangLen, "Long;") == 0)
876 * Convert primitive, boxed data from "srcPtr" to "dstPtr".
878 * Section v2 2.6 lists the various conversions and promotions. We
879 * allow the "widening" and "identity" conversions, but don't allow the
880 * "narrowing" conversions.
883 * byte to short, int, long, float, double
884 * short to int, long, float double
885 * char to int, long, float, double
886 * int to long, float, double
887 * long to float, double
889 * Values of types byte, char, and short are "internally" widened to int.
891 * Returns the width in 32-bit words of the destination primitive, or
892 * -1 if the conversion is not allowed.
894 * TODO? use JValue rather than u4 pointers
896 int dvmConvertPrimitiveValue(PrimitiveType srcType,
897 PrimitiveType dstType, const s4* srcPtr, s4* dstPtr)
900 OK4, OK8, ItoJ, ItoD, JtoD, FtoD, ItoF, JtoF, bad
903 enum Conversion conv;
904 #ifdef ARCH_HAVE_ALIGNED_DOUBLES
908 assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT));
909 assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT));
915 conv = (srcType == dstType) ? OK4 : bad;
921 case PRIM_SHORT: conv = OK4; break;
922 default: conv = bad; break;
931 case PRIM_INT: conv = OK4; break;
932 default: conv = bad; break;
941 case PRIM_INT: conv = ItoJ; break;
942 case PRIM_LONG: conv = OK8; break;
943 default: conv = bad; break;
952 case PRIM_INT: conv = ItoF; break;
953 case PRIM_LONG: conv = JtoF; break;
954 case PRIM_FLOAT: conv = OK4; break;
955 default: conv = bad; break;
964 case PRIM_INT: conv = ItoD; break;
965 case PRIM_LONG: conv = JtoD; break;
966 case PRIM_FLOAT: conv = FtoD; break;
967 case PRIM_DOUBLE: conv = OK8; break;
968 default: conv = bad; break;
981 case OK4: *dstPtr = *srcPtr; return 1;
982 case OK8: *(s8*) dstPtr = *(s8*)srcPtr; return 2;
983 case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr); return 2;
984 #ifndef ARCH_HAVE_ALIGNED_DOUBLES
985 case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr); return 2;
986 case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2;
987 case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr); return 2;
989 case ItoD: ret = (double) (*(s4*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
990 case JtoD: ret = (double) (*(long long*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
991 case FtoD: ret = (double) (*(float*) srcPtr); memcpy(dstPtr, &ret, 8); return 2;
993 case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr); return 1;
994 case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr); return 1;
996 ALOGV("illegal primitive conversion: '%s' to '%s'",
997 dexGetPrimitiveTypeDescriptor(srcType),
998 dexGetPrimitiveTypeDescriptor(dstType));
1003 return -1; // Keep the compiler happy.
1009 * Convert types and widen primitives. Puts the value of "arg" into
1012 * Returns the width of the argument in 32-bit words (1 or 2), or -1 on error.
1014 int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr)
1018 if (dvmIsPrimitiveClass(type)) {
1019 /* e.g.: "arg" is java/lang/Float instance, "type" is VM float class */
1020 PrimitiveType srcType;
1023 srcType = getBoxedType(arg);
1024 if (srcType == PRIM_NOT) { // didn't pass a boxed primitive in
1025 LOGVV("conv arg: type '%s' not boxed primitive",
1026 arg->clazz->descriptor);
1030 /* assumes value is stored in first instance field */
1031 valuePtr = (s4*) arg->instanceData;
1033 retVal = dvmConvertPrimitiveValue(srcType, type->primitiveType,
1036 /* verify object is compatible */
1037 if ((arg == NULL) || dvmInstanceof(arg->clazz, type)) {
1038 *destPtr = (s4) arg;
1041 LOGVV("Arg %p (%s) not compatible with %s",
1042 arg, arg->clazz->descriptor, type->descriptor);
1051 * Create a wrapper object for a primitive data type. If "returnType" is
1052 * not primitive, this just casts "value" to an object and returns it.
1054 * We could invoke the "toValue" method on the box types to take
1055 * advantage of pre-created values, but running that through the
1056 * interpreter is probably less efficient than just allocating storage here.
1058 * The caller must call dvmReleaseTrackedAlloc on the result.
1060 DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType)
1062 ClassObject* wrapperClass;
1063 DataObject* wrapperObj;
1065 PrimitiveType typeIndex = returnType->primitiveType;
1066 const char* classDescriptor;
1068 if (typeIndex == PRIM_NOT) {
1069 /* add to tracking table so return value is always in table */
1070 if (value.l != NULL)
1071 dvmAddTrackedAlloc((Object*)value.l, NULL);
1072 return (DataObject*) value.l;
1075 classDescriptor = dexGetBoxedTypeDescriptor(typeIndex);
1076 if (classDescriptor == NULL) {
1080 wrapperClass = dvmFindSystemClass(classDescriptor);
1081 if (wrapperClass == NULL) {
1082 ALOGW("Unable to find '%s'", classDescriptor);
1083 assert(dvmCheckException(dvmThreadSelf()));
1087 wrapperObj = (DataObject*) dvmAllocObject(wrapperClass, ALLOC_DEFAULT);
1088 if (wrapperObj == NULL)
1090 dataPtr = (s4*) wrapperObj->instanceData;
1092 /* assumes value is stored in first instance field */
1093 /* (see dvmValidateBoxClasses) */
1094 if (typeIndex == PRIM_LONG || typeIndex == PRIM_DOUBLE)
1095 *(s8*)dataPtr = value.j;
1103 * Unwrap a primitive data type, if necessary.
1105 * If "returnType" is not primitive, we just tuck "value" into JValue and
1106 * return it after verifying that it's the right type of object.
1108 * Fails if the field is primitive and "value" is either not a boxed
1109 * primitive or is of a type that cannot be converted.
1111 * Returns "true" on success, "false" on failure.
1113 bool dvmUnboxPrimitive(Object* value, ClassObject* returnType,
1116 PrimitiveType typeIndex = returnType->primitiveType;
1117 PrimitiveType valueIndex;
1119 if (typeIndex == PRIM_NOT) {
1120 if (value != NULL && !dvmInstanceof(value->clazz, returnType)) {
1121 ALOGD("wrong object type: %s %s",
1122 value->clazz->descriptor, returnType->descriptor);
1127 } else if (typeIndex == PRIM_VOID) {
1128 /* can't put anything into a void */
1132 valueIndex = getBoxedType((DataObject*)value);
1133 if (valueIndex == PRIM_NOT)
1136 /* assumes value is stored in first instance field of "value" */
1137 /* (see dvmValidateBoxClasses) */
1138 if (dvmConvertPrimitiveValue(valueIndex, typeIndex,
1139 (s4*) ((DataObject*)value)->instanceData, (s4*)pResult) < 0)
1141 ALOGV("Prim conversion failed");
1150 * Find the return type in the signature, and convert it to a class
1151 * object. For primitive types we use a boxed class, for reference types
1152 * we do a name lookup.
1154 * On failure, we return NULL with an exception raised.
1156 ClassObject* dvmGetBoxedReturnType(const Method* meth)
1158 const char* sig = dexProtoGetReturnType(&meth->prototype);
1170 return dvmFindPrimitiveClass(*sig);
1173 return dvmFindClass(sig, meth->clazz->classLoader);
1175 /* should not have passed verification */
1176 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1177 ALOGE("Bad return type in signature '%s'", desc);
1179 dvmThrowInternalError(NULL);
1187 * JNI reflection support: convert reflection object to Field ptr.
1189 Field* dvmGetFieldFromReflectObj(Object* obj)
1194 assert(obj->clazz == gDvm.classJavaLangReflectField);
1195 clazz = (ClassObject*)dvmGetFieldObject(obj,
1196 gDvm.offJavaLangReflectField_declClass);
1197 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectField_slot);
1199 /* must initialize the class before returning a field ID */
1200 if (!dvmInitClass(clazz))
1203 return dvmSlotToField(clazz, slot);
1207 * JNI reflection support: convert reflection object to Method ptr.
1209 Method* dvmGetMethodFromReflectObj(Object* obj)
1214 if (obj->clazz == gDvm.classJavaLangReflectConstructor) {
1215 clazz = (ClassObject*)dvmGetFieldObject(obj,
1216 gDvm.offJavaLangReflectConstructor_declClass);
1217 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectConstructor_slot);
1218 } else if (obj->clazz == gDvm.classJavaLangReflectMethod) {
1219 clazz = (ClassObject*)dvmGetFieldObject(obj,
1220 gDvm.offJavaLangReflectMethod_declClass);
1221 slot = dvmGetFieldInt(obj, gDvm.offJavaLangReflectMethod_slot);
1227 /* must initialize the class before returning a method ID */
1228 if (!dvmInitClass(clazz))
1231 return dvmSlotToMethod(clazz, slot);
1235 * JNI reflection support: convert Field to reflection object.
1237 * The return value is a java.lang.reflect.Field.
1239 * Caller must call dvmReleaseTrackedAlloc().
1241 Object* dvmCreateReflectObjForField(const ClassObject* clazz, Field* field)
1243 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectField))
1244 dvmInitClass(gDvm.classJavaLangReflectField);
1246 /* caller must dvmReleaseTrackedAlloc(result) */
1247 return createFieldObject(field, clazz);
1251 * JNI reflection support: convert Method to reflection object.
1253 * The returned object will be either a java.lang.reflect.Method or
1254 * .Constructor, depending on whether "method" is a constructor.
1256 * This is also used for certain "system" annotations.
1258 * Caller must call dvmReleaseTrackedAlloc().
1260 Object* dvmCreateReflectObjForMethod(const ClassObject* clazz, Method* method)
1262 UNUSED_PARAMETER(clazz);
1264 if (strcmp(method->name, "<init>") == 0) {
1265 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectConstructor))
1266 dvmInitClass(gDvm.classJavaLangReflectConstructor);
1268 return createConstructorObject(method);
1270 if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod))
1271 dvmInitClass(gDvm.classJavaLangReflectMethod);
1273 return dvmCreateReflectMethodObject(method);