diff options
| author | Dan Bornstein <danfuzz@android.com> | 2011-03-11 16:49:32 -0800 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-03-11 16:49:32 -0800 |
| commit | a5e5f6eb3ecb7950812a4718b8e795299ce79783 (patch) | |
| tree | 1f2453e1cbf675f2242ee04acfe2c748585141bf /vm | |
| parent | 190b97277ab6f1163ac3ccde34bd521940f73630 (diff) | |
| parent | a9c49df6714b3a37b7a7d0522932e622be2b35ac (diff) | |
| download | android_dalvik-a5e5f6eb3ecb7950812a4718b8e795299ce79783.tar.gz android_dalvik-a5e5f6eb3ecb7950812a4718b8e795299ce79783.tar.bz2 android_dalvik-a5e5f6eb3ecb7950812a4718b8e795299ce79783.zip | |
Merge "Clean up how primitive types are handled." into dalvik-dev
Diffstat (limited to 'vm')
| -rw-r--r-- | vm/CheckJni.c | 56 | ||||
| -rw-r--r-- | vm/Globals.h | 16 | ||||
| -rw-r--r-- | vm/alloc/Visit.c | 30 | ||||
| -rw-r--r-- | vm/analysis/CodeVerify.c | 37 | ||||
| -rw-r--r-- | vm/native/java_lang_reflect_Array.c | 5 | ||||
| -rw-r--r-- | vm/native/java_lang_reflect_Field.c | 63 | ||||
| -rw-r--r-- | vm/oo/Array.c | 115 | ||||
| -rw-r--r-- | vm/oo/Array.h | 6 | ||||
| -rw-r--r-- | vm/oo/Class.c | 105 | ||||
| -rw-r--r-- | vm/oo/Class.h | 7 | ||||
| -rw-r--r-- | vm/oo/Object.h | 25 | ||||
| -rw-r--r-- | vm/reflect/Reflect.c | 176 |
12 files changed, 310 insertions, 331 deletions
diff --git a/vm/CheckJni.c b/vm/CheckJni.c index 922646eab..5b9ea1211 100644 --- a/vm/CheckJni.c +++ b/vm/CheckJni.c @@ -403,6 +403,25 @@ static void checkThread(JNIEnv* env, int flags, const char* func) } /* + * Get a human-oriented name for a given primitive type. + */ +static const char* primitiveTypeToName(PrimitiveType primType) { + switch (primType) { + case PRIM_VOID: return "void"; + case PRIM_BOOLEAN: return "boolean"; + case PRIM_BYTE: return "byte"; + case PRIM_SHORT: return "short"; + case PRIM_CHAR: return "char"; + case PRIM_INT: return "int"; + case PRIM_LONG: return "long"; + case PRIM_FLOAT: return "float"; + case PRIM_DOUBLE: return "double"; + case PRIM_NOT: return "Object/Array"; + default: return "???"; + } +} + +/* * Verify that the field is of the appropriate type. If the field has an * object type, "obj" is the object we're trying to assign into it. * @@ -411,11 +430,6 @@ static void checkThread(JNIEnv* env, int flags, const char* func) static void checkFieldType(JNIEnv* env, jobject jobj, jfieldID fieldID, PrimitiveType prim, bool isStatic, const char* func) { - static const char* primNameList[] = { - "Object/Array", "boolean", "char", "float", "double", - "byte", "short", "int", "long", "void" - }; - const char** primNames = &primNameList[1]; // shift up for PRIM_NOT Field* field = (Field*) fieldID; bool printWarn = false; @@ -440,9 +454,9 @@ static void checkFieldType(JNIEnv* env, jobject jobj, jfieldID fieldID, printWarn = true; } } - } else if (field->signature[0] != PRIM_TYPE_TO_LETTER[prim]) { + } else if (dexGetPrimitiveTypeFromDescriptorChar(field->signature[0]) != prim) { LOGW("JNI WARNING: field '%s' with type '%s' set with wrong type (%s)", - field->name, field->signature, primNames[prim]); + field->name, field->signature, primitiveTypeToName(prim)); printWarn = true; } else if (isStatic && !dvmIsStaticField(field)) { if (isStatic) @@ -1087,19 +1101,21 @@ static size_t getGuardedCopyOriginalLen(const void* dataBuf) */ static int dvmPrimitiveTypeWidth(PrimitiveType primType) { - static const int lengths[PRIM_MAX] = { - 1, // boolean - 2, // char - 4, // float - 8, // double - 1, // byte - 2, // short - 4, // int - 8, // long - -1, // void - }; - assert(primType >= 0 && primType < PRIM_MAX); - return lengths[primType]; + switch (primType) { + case PRIM_BOOLEAN: return 1; + case PRIM_BYTE: return 1; + case PRIM_SHORT: return 2; + case PRIM_CHAR: return 2; + case PRIM_INT: return 4; + case PRIM_LONG: return 8; + case PRIM_FLOAT: return 4; + case PRIM_DOUBLE: return 8; + case PRIM_VOID: + default: { + assert(false); + return -1; + } + } } /* diff --git a/vm/Globals.h b/vm/Globals.h index 28cd17317..813373cc5 100644 --- a/vm/Globals.h +++ b/vm/Globals.h @@ -306,6 +306,17 @@ struct DvmGlobals { ClassObject* exVerifyError; ClassObject* exVirtualMachineError; + /* synthetic classes representing primitive types */ + ClassObject* typeVoid; + ClassObject* typeBoolean; + ClassObject* typeByte; + ClassObject* typeShort; + ClassObject* typeChar; + ClassObject* typeInt; + ClassObject* typeLong; + ClassObject* typeFloat; + ClassObject* typeDouble; + /* synthetic classes for arrays of primitives */ ClassObject* classArrayBoolean; ClassObject* classArrayChar; @@ -399,11 +410,6 @@ struct DvmGlobals { int offJavaNioBuffer_effectiveDirectAddress; /* - * VM-synthesized primitive classes, for arrays and reflection - */ - ClassObject* volatile primitiveClass[PRIM_MAX]; - - /* * Thread list. This always has at least one element in it (main), * and main is always the first entry. * diff --git a/vm/alloc/Visit.c b/vm/alloc/Visit.c index 7e44198f7..1961fc9a7 100644 --- a/vm/alloc/Visit.c +++ b/vm/alloc/Visit.c @@ -51,21 +51,6 @@ static void visitHashTable(RootVisitor *visitor, HashTable *table, } /* - * Applies a verification function to all elements in the array. - */ -static void visitArray(RootVisitor *visitor, Object **array, size_t length, - RootType type, void *arg) -{ - size_t i; - - assert(visitor != NULL); - assert(array != NULL); - for (i = 0; i < length; ++i) { - (*visitor)(&array[i], 0, type, arg); - } -} - -/* * Visits all entries in the reference table. */ static void visitReferenceTable(RootVisitor *visitor, ReferenceTable *table, @@ -232,6 +217,19 @@ static void visitThreads(RootVisitor *visitor, void *arg) dvmUnlockThreadList(); } +static void visitPrimitiveTypes(RootVisitor *visitor, void *arg) +{ + (*visitor)(&gDvm.typeVoid, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeBoolean, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeByte, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeShort, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeChar, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeInt, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeLong, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeFloat, 0, ROOT_STICKY_CLASS, arg); + (*visitor)(&gDvm.typeDouble, 0, ROOT_STICKY_CLASS, arg); +} + /* * Visits roots. TODO: visit cached global references. */ @@ -239,7 +237,7 @@ void dvmVisitRoots(RootVisitor *visitor, void *arg) { assert(visitor != NULL); visitHashTable(visitor, gDvm.loadedClasses, ROOT_STICKY_CLASS, arg); - visitArray(visitor, (Object **)gDvm.primitiveClass, NELEM(gDvm.primitiveClass), ROOT_STICKY_CLASS, arg); + visitPrimitiveTypes(visitor, arg); if (gDvm.dbgRegistry != NULL) { visitHashTable(visitor, gDvm.dbgRegistry, ROOT_DEBUGGER, arg); } diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c index 37a895180..2d00ebd85 100644 --- a/vm/analysis/CodeVerify.c +++ b/vm/analysis/CodeVerify.c @@ -320,30 +320,21 @@ static bool checkFieldArrayStore1nr(RegType instrType, RegType targetType) */ static RegType primitiveTypeToRegType(PrimitiveType primType) { - static const struct { - RegType regType; /* type equivalent */ - PrimitiveType primType; /* verification */ - } convTab[] = { - /* must match order of enum in Object.h */ - { kRegTypeBoolean, PRIM_BOOLEAN }, - { kRegTypeChar, PRIM_CHAR }, - { kRegTypeFloat, PRIM_FLOAT }, - { kRegTypeDoubleLo, PRIM_DOUBLE }, - { kRegTypeByte, PRIM_BYTE }, - { kRegTypeShort, PRIM_SHORT }, - { kRegTypeInteger, PRIM_INT }, - { kRegTypeLongLo, PRIM_LONG }, - // PRIM_VOID - }; - - if (primType < 0 || primType > (int) (sizeof(convTab) / sizeof(convTab[0]))) - { - assert(false); - return kRegTypeUnknown; + switch (primType) { + case PRIM_BOOLEAN: return kRegTypeBoolean; + case PRIM_BYTE: return kRegTypeByte; + case PRIM_SHORT: return kRegTypeShort; + case PRIM_CHAR: return kRegTypeChar; + case PRIM_INT: return kRegTypeInteger; + case PRIM_LONG: return kRegTypeLongLo; + case PRIM_FLOAT: return kRegTypeFloat; + case PRIM_DOUBLE: return kRegTypeDoubleLo; + case PRIM_VOID: + default: { + assert(false); + return kRegTypeUnknown; + } } - - assert(convTab[primType].primType == primType); - return convTab[primType].regType; } /* diff --git a/vm/native/java_lang_reflect_Array.c b/vm/native/java_lang_reflect_Array.c index bc7e5eca2..fe6647cdd 100644 --- a/vm/native/java_lang_reflect_Array.c +++ b/vm/native/java_lang_reflect_Array.c @@ -64,7 +64,6 @@ static void Dalvik_java_lang_reflect_Array_createObjectArray(const u4* args, static void Dalvik_java_lang_reflect_Array_createMultiArray(const u4* args, JValue* pResult) { - static const char kPrimLetter[] = PRIM_TYPE_TO_LETTER; ClassObject* elementClass = (ClassObject*) args[0]; ArrayObject* dimArray = (ArrayObject*) args[1]; ClassObject* arrayClass; @@ -106,8 +105,8 @@ static void Dalvik_java_lang_reflect_Array_createMultiArray(const u4* args, LOGVV("#### element name = '%s'\n", elementClass->descriptor); if (dvmIsPrimitiveClass(elementClass)) { - assert(elementClass->primitiveType >= 0); - acDescriptor[numDim] = kPrimLetter[elementClass->primitiveType]; + assert(elementClass->primitiveType != PRIM_NOT); + acDescriptor[numDim] = dexGetPrimitiveTypeDescriptorChar(elementClass->primitiveType); acDescriptor[numDim+1] = '\0'; } else { strcpy(acDescriptor+numDim, elementClass->descriptor); diff --git a/vm/native/java_lang_reflect_Field.c b/vm/native/java_lang_reflect_Field.c index 2713d8c0b..eb5d4e26e 100644 --- a/vm/native/java_lang_reflect_Field.c +++ b/vm/native/java_lang_reflect_Field.c @@ -515,26 +515,9 @@ static void Dalvik_java_lang_reflect_Field_setField(const u4* args, } /* - * Convert a reflection primitive type ordinal (inherited from the previous - * VM's reflection classes) to our value. - */ -static PrimitiveType convPrimType(int typeNum) -{ - static const PrimitiveType conv[PRIM_MAX] = { - PRIM_NOT, PRIM_BOOLEAN, PRIM_BYTE, PRIM_CHAR, PRIM_SHORT, - PRIM_INT, PRIM_FLOAT, PRIM_LONG, PRIM_DOUBLE - }; - if (typeNum <= 0 || typeNum > 8) - return PRIM_NOT; - return conv[typeNum]; -} - -/* * Primitive field getters, e.g.: * private double getIField(Object o, Class declaringClass, - * Class type, int slot, boolean noAccessCheck, int type_no) - * - * The "type_no" is defined by the java.lang.reflect.Field class. + * Class type, int slot, boolean noAccessCheck, char descriptor) */ static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args, JValue* pResult) @@ -545,8 +528,8 @@ static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args, ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); - int typeNum = args[6]; - PrimitiveType targetType = convPrimType(typeNum); + jchar descriptor = args[6]; + PrimitiveType targetType = dexGetPrimitiveTypeFromDescriptorChar(descriptor); const Field* field; JValue value; @@ -574,9 +557,7 @@ static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args, /* * Primitive field setters, e.g.: * private void setIField(Object o, Class declaringClass, - * Class type, int slot, boolean noAccessCheck, int type_no, int value) - * - * The "type_no" is defined by the java.lang.reflect.Field class. + * Class type, int slot, boolean noAccessCheck, char descriptor, int value) */ static void Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4* args, JValue* pResult) @@ -587,9 +568,9 @@ static void Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4* args, ClassObject* fieldType = (ClassObject*) args[3]; int slot = args[4]; bool noAccessCheck = (args[5] != 0); - int typeNum = args[6]; + jchar descriptor = args[6]; const s4* valuePtr = (s4*) &args[7]; /* 64-bit vars spill into args[8] */ - PrimitiveType srcType = convPrimType(typeNum); + PrimitiveType srcType = dexGetPrimitiveTypeFromDescriptorChar(descriptor); Field* field; JValue value; @@ -662,39 +643,39 @@ const DalvikNativeMethod dvm_java_lang_reflect_Field[] = { Dalvik_java_lang_reflect_Field_getFieldModifiers }, { "getField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;", Dalvik_java_lang_reflect_Field_getField }, - { "getBField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)B", + { "getBField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)B", Dalvik_java_lang_reflect_Field_getPrimitiveField }, - { "getCField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)C", + { "getCField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)C", Dalvik_java_lang_reflect_Field_getPrimitiveField }, - { "getDField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)D", + { "getDField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)D", Dalvik_java_lang_reflect_Field_getPrimitiveField }, - { "getFField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)F", + { "getFField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)F", Dalvik_java_lang_reflect_Field_getPrimitiveField }, - { "getIField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)I", + { "getIField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)I", Dalvik_java_lang_reflect_Field_getPrimitiveField }, - { "getJField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)J", + { "getJField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)J", Dalvik_java_lang_reflect_Field_getPrimitiveField }, - { "getSField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)S", + { "getSField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)S", Dalvik_java_lang_reflect_Field_getPrimitiveField }, - { "getZField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)Z", + { "getZField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZC)Z", Dalvik_java_lang_reflect_Field_getPrimitiveField }, { "setField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZLjava/lang/Object;)V", Dalvik_java_lang_reflect_Field_setField }, - { "setBField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIB)V", + { "setBField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCB)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, - { "setCField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIC)V", + { "setCField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCC)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, - { "setDField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZID)V", + { "setDField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCD)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, - { "setFField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIF)V", + { "setFField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCF)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, - { "setIField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZII)V", + { "setIField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCI)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, - { "setJField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIJ)V", + { "setJField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCJ)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, - { "setSField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIS)V", + { "setSField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCS)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, - { "setZField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIZ)V", + { "setZField", "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZCZ)V", Dalvik_java_lang_reflect_Field_setPrimitiveField }, { "getDeclaredAnnotations", "(Ljava/lang/Class;I)[Ljava/lang/annotation/Annotation;", Dalvik_java_lang_reflect_Field_getDeclaredAnnotations }, diff --git a/vm/oo/Array.c b/vm/oo/Array.c index 99630cad0..48602d1e8 100644 --- a/vm/oo/Array.c +++ b/vm/oo/Array.c @@ -23,9 +23,6 @@ #include <limits.h> static ClassObject* createArrayClass(const char* descriptor, Object* loader); -static ClassObject* createPrimitiveClass(int idx); - -static const char gPrimLetter[] = PRIM_TYPE_TO_LETTER; /* * Allocate space for a new array object. This is the lowest-level array @@ -218,7 +215,7 @@ ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim, LOGVV(" end: array class (prim) is '%s'\n", arrayClass->descriptor); newArray = dvmAllocPrimitiveArray( - gPrimLetter[arrayClass->elementClass->primitiveType], + dexGetPrimitiveTypeDescriptorChar(arrayClass->elementClass->primitiveType), *dimensions, ALLOC_DEFAULT); } } else { @@ -517,116 +514,6 @@ static ClassObject* createArrayClass(const char* descriptor, Object* loader) } /* - * Get a class we generated for the primitive types. - * - * These correspond to e.g. Integer.TYPE, and are used as the element - * class in arrays of primitives. - * - * "type" should be 'I', 'J', 'Z', etc. - * - * Returns NULL if the type doesn't correspond to a known primitive type. - */ -ClassObject* dvmFindPrimitiveClass(char type) -{ - int idx; - - switch (type) { - case 'Z': - idx = PRIM_BOOLEAN; - break; - case 'C': - idx = PRIM_CHAR; - break; - case 'F': - idx = PRIM_FLOAT; - break; - case 'D': - idx = PRIM_DOUBLE; - break; - case 'B': - idx = PRIM_BYTE; - break; - case 'S': - idx = PRIM_SHORT; - break; - case 'I': - idx = PRIM_INT; - break; - case 'J': - idx = PRIM_LONG; - break; - case 'V': - idx = PRIM_VOID; - break; - default: - LOGW("Unknown primitive type '%c'\n", type); - return NULL; - } - - /* - * Create the primitive class if it hasn't already been, and add it - * to the table. - */ - if (gDvm.primitiveClass[idx] == NULL) { - ClassObject* primClass = createPrimitiveClass(idx); - dvmReleaseTrackedAlloc((Object*) primClass, NULL); - - if (android_atomic_release_cas(0, (int) primClass, - (int*) &gDvm.primitiveClass[idx]) != 0) - { - /* - * Looks like somebody beat us to it. Free up the one we - * just created and use the other one. - */ - dvmFreeClassInnards(primClass); - } - } - - return gDvm.primitiveClass[idx]; -} - -/* - * Synthesize a primitive class. - * - * Just creates the class and returns it (does not add it to the class list). - */ -static ClassObject* createPrimitiveClass(int idx) -{ - ClassObject* newClass; - static const char* kClassDescriptors[PRIM_MAX] = { - "Z", "C", "F", "D", "B", "S", "I", "J", "V" - }; - - assert(gDvm.classJavaLangClass != NULL); - assert(idx >= 0 && idx < PRIM_MAX); - - /* - * Fill out a few fields in the ClassObject. - * - * Note that primitive classes do not sub-class java/lang/Object. This - * matters for "instanceof" checks. Also, we assume that the primitive - * class does not override finalize(). - */ - newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); - if (newClass == NULL) - return NULL; - DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass); - dvmSetClassSerialNumber(newClass); - newClass->accessFlags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; - newClass->primitiveType = idx; - newClass->descriptorAlloc = NULL; - newClass->descriptor = kClassDescriptors[idx]; - //newClass->super = gDvm.classJavaLangObject; - newClass->status = CLASS_INITIALIZED; - - /* don't need to set newClass->objectSize */ - - LOGVV("Created primitive class '%s'\n", kClassDescriptors[idx]); - - return newClass; -} - -/* * Copy the entire contents of one array of objects to another. If the copy * is impossible because of a type clash, we fail and return "false". */ diff --git a/vm/oo/Array.h b/vm/oo/Array.h index 9cd79968b..9a873e6b9 100644 --- a/vm/oo/Array.h +++ b/vm/oo/Array.h @@ -97,12 +97,6 @@ ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim, const int* dimensions); /* - * Find the synthesized object for the primitive class, generating it - * if this is the first reference. - */ -ClassObject* dvmFindPrimitiveClass(char type); - -/* * Verify that the object is actually an array. * * Does not verify that the object is actually a non-NULL object. diff --git a/vm/oo/Class.c b/vm/oo/Class.c index 45f101693..c2f666a58 100644 --- a/vm/oo/Class.c +++ b/vm/oo/Class.c @@ -301,6 +301,89 @@ size_t dvmClassObjectSize(const ClassObject *clazz) return classObjectSize(clazz->sfieldCount); } +/* (documented in header) */ +ClassObject* dvmFindPrimitiveClass(char type) +{ + PrimitiveType primitiveType = dexGetPrimitiveTypeFromDescriptorChar(type); + + switch (primitiveType) { + case PRIM_VOID: return gDvm.typeVoid; + case PRIM_BOOLEAN: return gDvm.typeBoolean; + case PRIM_BYTE: return gDvm.typeByte; + case PRIM_SHORT: return gDvm.typeShort; + case PRIM_CHAR: return gDvm.typeChar; + case PRIM_INT: return gDvm.typeInt; + case PRIM_LONG: return gDvm.typeLong; + case PRIM_FLOAT: return gDvm.typeFloat; + case PRIM_DOUBLE: return gDvm.typeDouble; + default: { + LOGW("Unknown primitive type '%c'\n", type); + return NULL; + } + } +} + +/* + * Synthesize a primitive class. + * + * Just creates the class and returns it (does not add it to the class list). + */ +static bool createPrimitiveType(PrimitiveType primitiveType, ClassObject** pClass) +{ + /* + * Fill out a few fields in the ClassObject. + * + * Note that primitive classes do not sub-class the class Object. + * This matters for "instanceof" checks. Also, we assume that the + * primitive class does not override finalize(). + */ + + const char* descriptor = dexGetPrimitiveTypeDescriptor(primitiveType); + assert(descriptor != NULL); + + ClassObject* newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); + if (newClass == NULL) { + return false; + } + + DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass); + dvmSetClassSerialNumber(newClass); + newClass->accessFlags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; + newClass->primitiveType = primitiveType; + newClass->descriptorAlloc = NULL; + newClass->descriptor = descriptor; + newClass->super = NULL; + newClass->status = CLASS_INITIALIZED; + + /* don't need to set newClass->objectSize */ + + LOGVV("Created class for primitive type '%s'\n", newClass->descriptor); + + *pClass = newClass; + dvmReleaseTrackedAlloc((Object*) newClass, NULL); + + return true; +} + +/* + * Create the classes representing primitive types. + */ +static bool createPrimitiveTypes(void) { + bool ok = true; + + ok &= createPrimitiveType(PRIM_VOID, &gDvm.typeVoid); + ok &= createPrimitiveType(PRIM_BOOLEAN, &gDvm.typeBoolean); + ok &= createPrimitiveType(PRIM_BYTE, &gDvm.typeByte); + ok &= createPrimitiveType(PRIM_SHORT, &gDvm.typeShort); + ok &= createPrimitiveType(PRIM_CHAR, &gDvm.typeChar); + ok &= createPrimitiveType(PRIM_INT, &gDvm.typeInt); + ok &= createPrimitiveType(PRIM_LONG, &gDvm.typeLong); + ok &= createPrimitiveType(PRIM_FLOAT, &gDvm.typeFloat); + ok &= createPrimitiveType(PRIM_DOUBLE, &gDvm.typeDouble); + + return ok; +} + /* * Initialize the bootstrap class loader. * @@ -350,6 +433,15 @@ bool dvmClassStartup(void) gDvm.classJavaLangClass->descriptor = "Ljava/lang/Class;"; /* + * Initialize the classes representing primitive types. These are + * instances of the class Class, but other than that they're fairly + * different from regular classes. + */ + if (!createPrimitiveTypes()) { + return false; + } + + /* * Process the bootstrap class path. This means opening the specified * DEX or Jar files and possibly running them through the optimizer. */ @@ -367,15 +459,20 @@ bool dvmClassStartup(void) */ void dvmClassShutdown(void) { - int i; - /* discard all system-loaded classes */ dvmHashTableFree(gDvm.loadedClasses); gDvm.loadedClasses = NULL; /* discard primitive classes created for arrays */ - for (i = 0; i < PRIM_MAX; i++) - dvmFreeClassInnards(gDvm.primitiveClass[i]); + dvmFreeClassInnards(gDvm.typeVoid); + dvmFreeClassInnards(gDvm.typeBoolean); + dvmFreeClassInnards(gDvm.typeByte); + dvmFreeClassInnards(gDvm.typeShort); + dvmFreeClassInnards(gDvm.typeChar); + dvmFreeClassInnards(gDvm.typeInt); + dvmFreeClassInnards(gDvm.typeLong); + dvmFreeClassInnards(gDvm.typeFloat); + dvmFreeClassInnards(gDvm.typeDouble); /* this closes DEX files, JAR files, etc. */ freeCpeArray(gDvm.bootClassPath); diff --git a/vm/oo/Class.h b/vm/oo/Class.h index e27ef79bc..3ad44bd5b 100644 --- a/vm/oo/Class.h +++ b/vm/oo/Class.h @@ -69,6 +69,13 @@ bool dvmClassPathContains(const ClassPathEntry* cpe, const char* path); void dvmSetClassSerialNumber(ClassObject* clazz); /* + * Find the class object representing the primitive type with the + * given descriptor. This returns NULL if the given type character + * is invalid. + */ +ClassObject* dvmFindPrimitiveClass(char type); + +/* * Find the class with the given descriptor. Load it if it hasn't already * been. * diff --git a/vm/oo/Object.h b/vm/oo/Object.h index fd37da0ae..7f2fbf662 100644 --- a/vm/oo/Object.h +++ b/vm/oo/Object.h @@ -149,31 +149,6 @@ typedef enum ClassStatus { } ClassStatus; /* - * Primitive type identifiers. We use these values as indexes into an - * array of synthesized classes, so these start at zero and count up. - * The order is arbitrary (mimics table in doc for newarray opcode), - * but can't be changed without shuffling some reflection tables. - * - * PRIM_VOID can't be used as an array type, but we include it here for - * other uses (e.g. Void.TYPE). - */ -typedef enum PrimitiveType { - PRIM_NOT = -1, /* value is not a primitive type */ - PRIM_BOOLEAN = 0, - PRIM_CHAR = 1, - PRIM_FLOAT = 2, - PRIM_DOUBLE = 3, - PRIM_BYTE = 4, - PRIM_SHORT = 5, - PRIM_INT = 6, - PRIM_LONG = 7, - PRIM_VOID = 8, - - PRIM_MAX -} PrimitiveType; -#define PRIM_TYPE_TO_LETTER "ZCFDBSIJV" /* must match order in enum */ - -/* * Definitions for packing refOffsets in ClassObject. */ /* diff --git a/vm/reflect/Reflect.c b/vm/reflect/Reflect.c index dd87d44fc..ae165dcc6 100644 --- a/vm/reflect/Reflect.c +++ b/vm/reflect/Reflect.c @@ -885,72 +885,111 @@ static PrimitiveType getBoxedType(DataObject* arg) * float to double * Values of types byte, char, and short are "internally" widened to int. * - * Returns the width in bytes of the destination primitive, or -1 if the - * conversion is not allowed. + * Returns the width in 32-bit words of the destination primitive, or + * -1 if the conversion is not allowed. * * TODO? use JValue rather than u4 pointers */ int dvmConvertPrimitiveValue(PrimitiveType srcType, PrimitiveType dstType, const s4* srcPtr, s4* dstPtr) { - enum { - OK4, OK8, ItoJ, - ItoD, JtoD, FtoD, - ItoF, JtoF, - bad, kMax + enum Conversion { + OK4, OK8, ItoJ, ItoD, JtoD, FtoD, ItoF, JtoF, bad }; - /* [src][dst] */ - static const int kConvMode[kMax][kMax] = { - /*FROM *TO: bool char float double byte short int long */ - /*bool */ { OK4, bad, bad, bad, bad, bad, bad, bad }, - /*char */ { bad, OK4, ItoF, ItoD, bad, bad, OK4, ItoJ }, - /*float*/ { bad, bad, OK4, FtoD, bad, bad, bad, bad }, - /*doubl*/ { bad, bad, bad, OK8, bad, bad, bad, bad }, - /*byte */ { bad, bad, ItoF, ItoD, OK4, OK4, OK4, ItoJ }, - /*short*/ { bad, bad, ItoF, ItoD, bad, OK4, OK4, ItoJ }, - /*int */ { bad, bad, ItoF, ItoD, bad, bad, OK4, ItoJ }, - /*long */ { bad, bad, JtoF, JtoD, bad, bad, bad, OK8 }, - }; - int result; - - assert(srcType != PRIM_NOT && dstType != PRIM_NOT && - srcType != PRIM_VOID && dstType != PRIM_VOID); - result = kConvMode[srcType][dstType]; - - //LOGV("+++ convprim: src=%d dst=%d result=%d\n", srcType, dstType, result); - - switch (result) { - case OK4: - *dstPtr = *srcPtr; - return 1; - case OK8: - *(s8*)dstPtr = *(s8*)srcPtr; - return 2; - case ItoJ: - *(s8*)dstPtr = (s8) (*(s4*) srcPtr); - return 2; - case ItoD: - *(double*)dstPtr = (double) (*(s4*) srcPtr); - return 2; - case JtoD: - *(double*)dstPtr = (double) (*(long long*) srcPtr); - return 2; - case FtoD: - *(double*)dstPtr = (double) (*(float*) srcPtr); - return 2; - case ItoF: - *(float*)dstPtr = (float) (*(int*) srcPtr); - return 1; - case JtoF: - *(float*)dstPtr = (float) (*(long long*) srcPtr); - return 1; - case bad: - LOGV("convert primitive: prim %d to %d not allowed\n", - srcType, dstType); - return -1; - default: - assert(false); - return -1; + + enum Conversion conv; + + assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT)); + assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT)); + + switch (dstType) { + case PRIM_BOOLEAN: + case PRIM_CHAR: + case PRIM_BYTE: { + conv = (srcType == dstType) ? OK4 : bad; + break; + } + case PRIM_SHORT: { + switch (srcType) { + case PRIM_BYTE: + case PRIM_SHORT: conv = OK4; break; + default: conv = bad; break; + } + break; + } + case PRIM_INT: { + switch (srcType) { + case PRIM_BYTE: + case PRIM_CHAR: + case PRIM_SHORT: + case PRIM_INT: conv = OK4; break; + default: conv = bad; break; + } + break; + } + case PRIM_LONG: { + switch (srcType) { + case PRIM_BYTE: + case PRIM_CHAR: + case PRIM_SHORT: + case PRIM_INT: conv = ItoJ; break; + case PRIM_LONG: conv = OK8; break; + default: conv = bad; break; + } + break; + } + case PRIM_FLOAT: { + switch (srcType) { + case PRIM_BYTE: + case PRIM_CHAR: + case PRIM_SHORT: + case PRIM_INT: conv = ItoF; break; + case PRIM_LONG: conv = JtoF; break; + case PRIM_FLOAT: conv = OK4; break; + default: conv = bad; break; + } + break; + } + case PRIM_DOUBLE: { + switch (srcType) { + case PRIM_BYTE: + case PRIM_CHAR: + case PRIM_SHORT: + case PRIM_INT: conv = ItoD; break; + case PRIM_LONG: conv = JtoD; break; + case PRIM_FLOAT: conv = FtoD; break; + case PRIM_DOUBLE: conv = OK8; break; + default: conv = bad; break; + } + break; + } + case PRIM_VOID: + case PRIM_NOT: + default: { + conv = bad; + break; + } + } + + switch (conv) { + case OK4: *dstPtr = *srcPtr; return 1; + case OK8: *(s8*) dstPtr = *(s8*)srcPtr; return 2; + case ItoJ: *(s8*) dstPtr = (s8) (*(s4*) srcPtr); return 2; + case ItoD: *(double*) dstPtr = (double) (*(s4*) srcPtr); return 2; + case JtoD: *(double*) dstPtr = (double) (*(long long*) srcPtr); return 2; + case FtoD: *(double*) dstPtr = (double) (*(float*) srcPtr); return 2; + case ItoF: *(float*) dstPtr = (float) (*(int*) srcPtr); return 1; + case JtoF: *(float*) dstPtr = (float) (*(long long*) srcPtr); return 1; + case bad: { + LOGV("illegal primitive conversion: '%s' to '%s'\n", + dexGetPrimitiveTypeDescriptor(srcType), + dexGetPrimitiveTypeDescriptor(dstType)); + return -1; + } + default: { + dvmAbort(); + return -1; // Keep the compiler happy. + } } } @@ -970,7 +1009,7 @@ int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr) s4* valuePtr; srcType = getBoxedType(arg); - if (srcType < 0) { // didn't pass a boxed primitive in + if (srcType == PRIM_NOT) { // didn't pass a boxed primitive in LOGVV("conv arg: type '%s' not boxed primitive\n", arg->obj.clazz->descriptor); return -1; @@ -1008,16 +1047,6 @@ int dvmConvertArgument(DataObject* arg, ClassObject* type, s4* destPtr) */ DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType) { - static const char* boxTypes[] = { // order from enum PrimitiveType - "Ljava/lang/Boolean;", - "Ljava/lang/Character;", - "Ljava/lang/Float;", - "Ljava/lang/Double;", - "Ljava/lang/Byte;", - "Ljava/lang/Short;", - "Ljava/lang/Integer;", - "Ljava/lang/Long;" - }; ClassObject* wrapperClass; DataObject* wrapperObj; s4* dataPtr; @@ -1031,11 +1060,10 @@ DataObject* dvmBoxPrimitive(JValue value, ClassObject* returnType) return (DataObject*) value.l; } - assert(typeIndex >= 0 && typeIndex < PRIM_MAX); - if (typeIndex == PRIM_VOID) + classDescriptor = dexGetBoxedTypeDescriptor(typeIndex); + if (classDescriptor == NULL) { return NULL; - - classDescriptor = boxTypes[typeIndex]; + } wrapperClass = dvmFindSystemClass(classDescriptor); if (wrapperClass == NULL) { |
