Clean up how primitive types are handled.

The PrimitiveType enum got "promoted" to libdex, and I added a
few helper functions there. I also quashed the idea that there
is some sort of canonical ordering of the enumerated values.

In the vm (per se), I made PrimitiveType uses where it had assumed
an ordering instead switch(). This mostly made things much simpler.

I also split out the array of type classes in Globals.h into
individual ClassObject*s. This mostly made things simpler, but the gc
got a tiny bit of extra cruft because of it.

Finally, I made it so that the type classes get created explicitly
during vm startup, instead of happening implicitly the first time
they're accessed. This both simplified the code and, in particular,
made it so that the type classes didn't have to be declared volatile.

There are still a couple of related items that could stand to be
cleaned up, but I think what's here is enough for one patch.

Change-Id: Id14a6dfdb200abce9f30911c330ba32d9c2a4c3f
diff --git a/libdex/DexFile.c b/libdex/DexFile.c
index 6567dea..d4b64db 100644
--- a/libdex/DexFile.c
+++ b/libdex/DexFile.c
@@ -43,6 +43,62 @@
 static const bool kVerifyChecksum = false;
 static const bool kVerifySignature = false;
 
+/* (documented in header) */
+char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type) {
+    const char* string = dexGetPrimitiveTypeDescriptor(type);
+
+    return (string == NULL) ? '\0' : string[0];
+}
+
+/* (documented in header) */
+const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type) {
+    switch (type) {
+        case PRIM_VOID:    return "V";
+        case PRIM_BOOLEAN: return "Z";
+        case PRIM_BYTE:    return "B";
+        case PRIM_SHORT:   return "S";
+        case PRIM_CHAR:    return "C";
+        case PRIM_INT:     return "I";
+        case PRIM_LONG:    return "J";
+        case PRIM_FLOAT:   return "F";
+        case PRIM_DOUBLE:  return "D";
+        default:           return NULL;
+    }
+
+    return NULL;
+}
+
+const char* dexGetBoxedTypeDescriptor(PrimitiveType type) {
+    switch (type) {
+        case PRIM_VOID:    return NULL;
+        case PRIM_BOOLEAN: return "Ljava/lang/Boolean;";
+        case PRIM_BYTE:    return "Ljava/lang/Byte;";
+        case PRIM_SHORT:   return "Ljava/lang/Short;";
+        case PRIM_CHAR:    return "Ljava/lang/Character;";
+        case PRIM_INT:     return "Ljava/lang/Integer;";
+        case PRIM_LONG:    return "Ljava/lang/Long;";
+        case PRIM_FLOAT:   return "Ljava/lang/Float;";
+        case PRIM_DOUBLE:  return "Ljava/lang/Double;";
+        default:           return NULL;
+    }
+}
+
+/* (documented in header) */
+PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar) {
+    switch (descriptorChar) {
+        case 'V': return PRIM_VOID;
+        case 'Z': return PRIM_BOOLEAN;
+        case 'B': return PRIM_BYTE;
+        case 'S': return PRIM_SHORT;
+        case 'C': return PRIM_CHAR;
+        case 'I': return PRIM_INT;
+        case 'J': return PRIM_LONG;
+        case 'F': return PRIM_FLOAT;
+        case 'D': return PRIM_DOUBLE;
+        default:  return PRIM_NOT;
+    }
+}
+
 /* Return the UTF-8 encoded string with the specified string_id index,
  * also filling in the UTF-16 size (number of 16-bit code points).*/
 const char* dexStringAndSizeById(const DexFile* pDexFile, u4 idx,
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index 13eac87..4c6065f 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -71,6 +71,22 @@
 };
 
 /*
+ * Enumeration of all the primitive types.
+ */
+typedef enum PrimitiveType {
+    PRIM_NOT        = 0,       /* value is a reference type, not a primitive type */
+    PRIM_VOID       = 1,
+    PRIM_BOOLEAN    = 2,
+    PRIM_BYTE       = 3,
+    PRIM_SHORT      = 4,
+    PRIM_CHAR       = 5,
+    PRIM_INT        = 6,
+    PRIM_LONG       = 7,
+    PRIM_FLOAT      = 8,
+    PRIM_DOUBLE     = 9,
+} PrimitiveType;
+
+/*
  * access flags and masks; the "standard" ones are all <= 0x4000
  *
  * Note: There are related declarations in vm/oo/Object.h in the ClassFlags
@@ -917,4 +933,30 @@
         (pDexFile->baseAddr + dexGetAnnotationOff(pAnnoSet, idx));
 }
 
+/*
+ * Get the type descriptor character associated with a given primitive
+ * type. This returns '\0' if the type is invalid.
+ */
+char dexGetPrimitiveTypeDescriptorChar(PrimitiveType type);
+
+/*
+ * Get the type descriptor string associated with a given primitive
+ * type.
+ */
+const char* dexGetPrimitiveTypeDescriptor(PrimitiveType type);
+
+/*
+ * Get the boxed type descriptor string associated with a given
+ * primitive type. This returns NULL for an invalid type, including
+ * particularly for type "void".
+ */
+const char* dexGetBoxedTypeDescriptor(PrimitiveType type);
+
+/*
+ * Get the primitive type constant from the given descriptor character.
+ * This returns PRIM_NOT (note: this is a 0) if the character is invalid
+ * as a primitive type descriptor.
+ */
+PrimitiveType dexGetPrimitiveTypeFromDescriptorChar(char descriptorChar);
+
 #endif /*_LIBDEX_DEXFILE*/
diff --git a/vm/CheckJni.c b/vm/CheckJni.c
index 922646e..5b9ea12 100644
--- a/vm/CheckJni.c
+++ b/vm/CheckJni.c
@@ -403,6 +403,25 @@
 }
 
 /*
+ * 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 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 @@
                 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 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 28cd173..813373c 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -306,6 +306,17 @@
     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 @@
     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 7e44198..1961fc9 100644
--- a/vm/alloc/Visit.c
+++ b/vm/alloc/Visit.c
@@ -51,21 +51,6 @@
 }
 
 /*
- * 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 @@
     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 @@
 {
     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 1ddc713..42dcdd8 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -320,30 +320,21 @@
  */
 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 bc7e5ec..fe6647cd 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_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 @@
 
     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 2713d8c..eb5d4e2 100644
--- a/vm/native/java_lang_reflect_Field.c
+++ b/vm/native/java_lang_reflect_Field.c
@@ -515,26 +515,9 @@
 }
 
 /*
- * 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 @@
     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 @@
 /*
  * 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 @@
     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 @@
         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 99630ca..48602d1 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 @@
             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 @@
 }
 
 /*
- * 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 9cd7996..9a873e6 100644
--- a/vm/oo/Array.h
+++ b/vm/oo/Array.h
@@ -97,12 +97,6 @@
     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 45f1016..c2f666a 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -301,6 +301,89 @@
     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 @@
     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 @@
  */
 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 e27ef79..3ad44bd 100644
--- a/vm/oo/Class.h
+++ b/vm/oo/Class.h
@@ -69,6 +69,13 @@
 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 fd37da0..7f2fbf6 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -149,31 +149,6 @@
 } 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 dd87d44..ae165dc 100644
--- a/vm/reflect/Reflect.c
+++ b/vm/reflect/Reflect.c
@@ -885,72 +885,111 @@
  *  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];
+    enum Conversion conv;
 
-    //LOGV("+++ convprim: src=%d dst=%d result=%d\n", srcType, dstType, result);
+    assert((srcType != PRIM_VOID) && (srcType != PRIM_NOT));
+    assert((dstType != PRIM_VOID) && (dstType != PRIM_NOT));
 
-    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;
+    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 @@
         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 @@
  */
 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 @@
         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) {