Home | History | Annotate | Download | only in oo
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /*
     17  * Array objects.
     18  */
     19 #include "Dalvik.h"
     20 
     21 #include <stdlib.h>
     22 #include <stddef.h>
     23 
     24 #if WITH_HPROF && WITH_HPROF_STACK
     25 #include "hprof/Hprof.h"
     26 #endif
     27 
     28 static ClassObject* createArrayClass(const char* descriptor, Object* loader);
     29 static ClassObject* createPrimitiveClass(int idx);
     30 
     31 static const char gPrimLetter[] = PRIM_TYPE_TO_LETTER;
     32 
     33 /*
     34  * Allocate space for a new array object.  This is the lowest-level array
     35  * allocation function.
     36  *
     37  * Pass in the array class and the width of each element.
     38  *
     39  * On failure, returns NULL with an exception raised.
     40  */
     41 ArrayObject* dvmAllocArray(ClassObject* arrayClass, size_t length,
     42     size_t elemWidth, int allocFlags)
     43 {
     44     ArrayObject* newArray;
     45     size_t size;
     46 
     47     assert(arrayClass->descriptor[0] == '[');
     48 
     49     if (length > 0x0fffffff) {
     50         /* too large and (length * elemWidth) will overflow 32 bits */
     51         LOGE("Rejecting allocation of %u-element array\n", length);
     52         dvmThrowBadAllocException("array size too large");
     53         return NULL;
     54     }
     55 
     56     size = offsetof(ArrayObject, contents);
     57     size += length * elemWidth;
     58 
     59     /* Note that we assume that the Array class does not
     60      * override finalize().
     61      */
     62     newArray = dvmMalloc(size, allocFlags);
     63     if (newArray != NULL) {
     64         DVM_OBJECT_INIT(&newArray->obj, arrayClass);
     65         newArray->length = length;
     66         LOGVV("AllocArray: %s [%d] (%d)\n",
     67             arrayClass->descriptor, (int) length, (int) size);
     68 #if WITH_HPROF && WITH_HPROF_STACK
     69         hprofFillInStackTrace(&newArray->obj);
     70 #endif
     71         dvmTrackAllocation(arrayClass, size);
     72     }
     73     /* the caller must call dvmReleaseTrackedAlloc */
     74     return newArray;
     75 }
     76 
     77 /*
     78  * Create a new array, given an array class.  The class may represent an
     79  * array of references or primitives.
     80  */
     81 ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass,
     82     size_t length, int allocFlags)
     83 {
     84     const char* descriptor = arrayClass->descriptor;
     85 
     86     assert(descriptor[0] == '[');       /* must be array class */
     87     if (descriptor[1] != '[' && descriptor[1] != 'L') {
     88         /* primitive array */
     89         assert(descriptor[2] == '\0');
     90         return dvmAllocPrimitiveArray(descriptor[1], length, allocFlags);
     91     } else {
     92         return dvmAllocArray(arrayClass, length, kObjectArrayRefWidth,
     93             allocFlags);
     94     }
     95 }
     96 
     97 /*
     98  * Find the array class for "elemClassObj", which could itself be an
     99  * array class.
    100  */
    101 ClassObject* dvmFindArrayClassForElement(ClassObject* elemClassObj)
    102 {
    103     ClassObject* arrayClass;
    104 
    105     assert(elemClassObj != NULL);
    106 
    107     /* Simply prepend "[" to the descriptor. */
    108     int nameLen = strlen(elemClassObj->descriptor);
    109     char className[nameLen + 2];
    110 
    111     className[0] = '[';
    112     memcpy(className+1, elemClassObj->descriptor, nameLen+1);
    113     arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader);
    114 
    115     return arrayClass;
    116 }
    117 
    118 /*
    119  * Create a new array that holds references to members of the specified class.
    120  *
    121  * "elemClassObj" is the element type, and may itself be an array class.  It
    122  * may not be a primitive class.
    123  *
    124  * "allocFlags" determines whether the new object will be added to the
    125  * "tracked alloc" table.
    126  *
    127  * This is less efficient than dvmAllocArray(), but occasionally convenient.
    128  */
    129 ArrayObject* dvmAllocObjectArray(ClassObject* elemClassObj, size_t length,
    130     int allocFlags)
    131 {
    132     ClassObject* arrayClass;
    133     ArrayObject* newArray = NULL;
    134 
    135     LOGVV("dvmAllocObjectArray: '%s' len=%d\n",
    136         elemClassObj->descriptor, (int)length);
    137 
    138     arrayClass = dvmFindArrayClassForElement(elemClassObj);
    139     if (arrayClass != NULL) {
    140         newArray = dvmAllocArray(arrayClass, length, kObjectArrayRefWidth,
    141             allocFlags);
    142     }
    143 
    144     /* the caller must call dvmReleaseTrackedAlloc */
    145     return newArray;
    146 }
    147 
    148 /*
    149  * Create a new array that holds primitive types.
    150  *
    151  * "type" is the primitive type letter, e.g. 'I' for int or 'J' for long.
    152  * If the array class doesn't exist, it will be created.
    153  */
    154 ArrayObject* dvmAllocPrimitiveArray(char type, size_t length, int allocFlags)
    155 {
    156     ArrayObject* newArray;
    157     ClassObject** pTypeClass;
    158     int width;
    159 
    160     switch (type) {
    161     case 'I':
    162         pTypeClass = &gDvm.classArrayInt;
    163         width = 4;
    164         break;
    165     case 'C':
    166         pTypeClass = &gDvm.classArrayChar;
    167         width = 2;
    168         break;
    169     case 'B':
    170         pTypeClass = &gDvm.classArrayByte;
    171         width = 1;
    172         break;
    173     case 'Z':
    174         pTypeClass = &gDvm.classArrayBoolean;
    175         width = 1; /* special-case this? */
    176         break;
    177     case 'F':
    178         pTypeClass = &gDvm.classArrayFloat;
    179         width = 4;
    180         break;
    181     case 'D':
    182         pTypeClass = &gDvm.classArrayDouble;
    183         width = 8;
    184         break;
    185     case 'S':
    186         pTypeClass = &gDvm.classArrayShort;
    187         width = 2;
    188         break;
    189     case 'J':
    190         pTypeClass = &gDvm.classArrayLong;
    191         width = 8;
    192         break;
    193     default:
    194         LOGE("Unknown type '%c'\n", type);
    195         assert(false);
    196         return NULL;
    197     }
    198 
    199     if (*pTypeClass == NULL) {
    200         char typeClassName[3] = "[x";
    201 
    202         typeClassName[1] = type;
    203 
    204         *pTypeClass = dvmFindArrayClass(typeClassName, NULL);
    205         if (*pTypeClass == NULL) {
    206             LOGE("ERROR: failed to generate array class for '%s'\n",
    207                 typeClassName);
    208             return NULL;
    209         }
    210     }
    211 
    212     newArray = dvmAllocArray(*pTypeClass, length, width, allocFlags);
    213 
    214     /* the caller must dvmReleaseTrackedAlloc if allocFlags==ALLOC_DEFAULT */
    215     return newArray;
    216 }
    217 
    218 /*
    219  * Recursively create an array with multiple dimensions.  Elements may be
    220  * Objects or primitive types.
    221  *
    222  * The dimension we're creating is in dimensions[0], so when we recurse
    223  * we advance the pointer.
    224  */
    225 ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim,
    226     const int* dimensions)
    227 {
    228     ArrayObject* newArray;
    229     const char* elemName = arrayClass->descriptor + 1; // Advance past one '['.
    230 
    231     LOGVV("dvmAllocMultiArray: class='%s' curDim=%d *dimensions=%d\n",
    232         arrayClass->descriptor, curDim, *dimensions);
    233 
    234     if (curDim == 0) {
    235         if (*elemName == 'L' || *elemName == '[') {
    236             LOGVV("  end: array class (obj) is '%s'\n",
    237                 arrayClass->descriptor);
    238             newArray = dvmAllocArray(arrayClass, *dimensions,
    239                         kObjectArrayRefWidth, ALLOC_DEFAULT);
    240         } else {
    241             LOGVV("  end: array class (prim) is '%s'\n",
    242                 arrayClass->descriptor);
    243             newArray = dvmAllocPrimitiveArray(
    244                     gPrimLetter[arrayClass->elementClass->primitiveType],
    245                     *dimensions, ALLOC_DEFAULT);
    246         }
    247     } else {
    248         ClassObject* subArrayClass;
    249         int i;
    250 
    251         /* if we have X[][], find X[] */
    252         subArrayClass = dvmFindArrayClass(elemName, arrayClass->classLoader);
    253         if (subArrayClass == NULL) {
    254             /* not enough '['s on the initial class? */
    255             assert(dvmCheckException(dvmThreadSelf()));
    256             return NULL;
    257         }
    258         assert(dvmIsArrayClass(subArrayClass));
    259 
    260         /* allocate the array that holds the sub-arrays */
    261         newArray = dvmAllocArray(arrayClass, *dimensions, kObjectArrayRefWidth,
    262                         ALLOC_DEFAULT);
    263         if (newArray == NULL) {
    264             assert(dvmCheckException(dvmThreadSelf()));
    265             return NULL;
    266         }
    267 
    268         /*
    269          * Create a new sub-array in every element of the array.
    270          */
    271         for (i = 0; i < *dimensions; i++) {
    272           ArrayObject* newSubArray;
    273           newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
    274                           dimensions+1);
    275             if (newSubArray == NULL) {
    276                 dvmReleaseTrackedAlloc((Object*) newArray, NULL);
    277                 assert(dvmCheckException(dvmThreadSelf()));
    278                 return NULL;
    279             }
    280             dvmSetObjectArrayElement(newArray, i, (Object *)newSubArray);
    281             dvmReleaseTrackedAlloc((Object*) newSubArray, NULL);
    282         }
    283     }
    284 
    285     /* caller must call dvmReleaseTrackedAlloc */
    286     return newArray;
    287 }
    288 
    289 
    290 /*
    291  * Find an array class, by name (e.g. "[I").
    292  *
    293  * If the array class doesn't exist, we generate it.
    294  *
    295  * If the element class doesn't exist, we return NULL (no exception raised).
    296  */
    297 ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader)
    298 {
    299     ClassObject* clazz;
    300 
    301     assert(descriptor[0] == '[');
    302     //LOGV("dvmFindArrayClass: '%s' %p\n", descriptor, loader);
    303 
    304     clazz = dvmLookupClass(descriptor, loader, false);
    305     if (clazz == NULL) {
    306         LOGV("Array class '%s' %p not found; creating\n", descriptor, loader);
    307         clazz = createArrayClass(descriptor, loader);
    308         if (clazz != NULL)
    309             dvmAddInitiatingLoader(clazz, loader);
    310     }
    311 
    312     return clazz;
    313 }
    314 
    315 /*
    316  * Create an array class (i.e. the class object for the array, not the
    317  * array itself).  "descriptor" looks like "[C" or "[Ljava/lang/String;".
    318  *
    319  * If "descriptor" refers to an array of primitives, look up the
    320  * primitive type's internally-generated class object.
    321  *
    322  * "loader" is the class loader of the class that's referring to us.  It's
    323  * used to ensure that we're looking for the element type in the right
    324  * context.  It does NOT become the class loader for the array class; that
    325  * always comes from the base element class.
    326  *
    327  * Returns NULL with an exception raised on failure.
    328  */
    329 static ClassObject* createArrayClass(const char* descriptor, Object* loader)
    330 {
    331     ClassObject* newClass = NULL;
    332     ClassObject* elementClass = NULL;
    333     int arrayDim;
    334     u4 extraFlags;
    335 
    336     assert(descriptor[0] == '[');
    337     assert(gDvm.classJavaLangClass != NULL);
    338     assert(gDvm.classJavaLangObject != NULL);
    339 
    340     /*
    341      * Identify the underlying element class and the array dimension depth.
    342      */
    343     extraFlags = CLASS_ISARRAY;
    344     if (descriptor[1] == '[') {
    345         /* array of arrays; keep descriptor and grab stuff from parent */
    346         ClassObject* outer;
    347 
    348         outer = dvmFindClassNoInit(&descriptor[1], loader);
    349         if (outer != NULL) {
    350             /* want the base class, not "outer", in our elementClass */
    351             elementClass = outer->elementClass;
    352             arrayDim = outer->arrayDim + 1;
    353             extraFlags |= CLASS_ISOBJECTARRAY;
    354         } else {
    355             assert(elementClass == NULL);     /* make sure we fail */
    356         }
    357     } else {
    358         arrayDim = 1;
    359         if (descriptor[1] == 'L') {
    360             /* array of objects; strip off "[" and look up descriptor. */
    361             const char* subDescriptor = &descriptor[1];
    362             LOGVV("searching for element class '%s'\n", subDescriptor);
    363             elementClass = dvmFindClassNoInit(subDescriptor, loader);
    364             extraFlags |= CLASS_ISOBJECTARRAY;
    365         } else {
    366             /* array of a primitive type */
    367             elementClass = dvmFindPrimitiveClass(descriptor[1]);
    368         }
    369     }
    370 
    371     if (elementClass == NULL) {
    372         /* failed */
    373         assert(dvmCheckException(dvmThreadSelf()));
    374         dvmFreeClassInnards(newClass);
    375         dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    376         return NULL;
    377     }
    378 
    379     /*
    380      * See if it's already loaded.  Array classes are always associated
    381      * with the class loader of their underlying element type -- an array
    382      * of Strings goes with the loader for java/lang/String -- so we need
    383      * to look for it there.  (The caller should have checked for the
    384      * existence of the class before calling here, but they did so with
    385      * *their* class loader, not the element class' loader.)
    386      *
    387      * If we find it, the caller adds "loader" to the class' initiating
    388      * loader list, which should prevent us from going through this again.
    389      *
    390      * This call is unnecessary if "loader" and "elementClass->classLoader"
    391      * are the same, because our caller (dvmFindArrayClass) just did the
    392      * lookup.  (Even if we get this wrong we still have correct behavior,
    393      * because we effectively do this lookup again when we add the new
    394      * class to the hash table -- necessary because of possible races with
    395      * other threads.)
    396      */
    397     if (loader != elementClass->classLoader) {
    398         LOGVV("--- checking for '%s' in %p vs. elem %p\n",
    399             descriptor, loader, elementClass->classLoader);
    400         newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
    401         if (newClass != NULL) {
    402             LOGV("--- we already have %s in %p, don't need in %p\n",
    403                 descriptor, elementClass->classLoader, loader);
    404             return newClass;
    405         }
    406     }
    407 
    408 
    409     /*
    410      * Fill out the fields in the ClassObject.
    411      *
    412      * It is possible to execute some methods against arrays, because all
    413      * arrays are instances of Object, so we need to set up a vtable.  We
    414      * can just point at the one in Object.
    415      *
    416      * Array classes are simple enough that we don't need to do a full
    417      * link step.
    418      */
    419     newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
    420     if (newClass == NULL)
    421         return NULL;
    422     DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
    423     dvmSetClassSerialNumber(newClass);
    424     newClass->descriptorAlloc = strdup(descriptor);
    425     newClass->descriptor = newClass->descriptorAlloc;
    426     dvmSetFieldObject((Object *)newClass,
    427                       offsetof(ClassObject, super),
    428                       (Object *)gDvm.classJavaLangObject);
    429     newClass->vtableCount = gDvm.classJavaLangObject->vtableCount;
    430     newClass->vtable = gDvm.classJavaLangObject->vtable;
    431     newClass->primitiveType = PRIM_NOT;
    432     dvmSetFieldObject((Object *)newClass,
    433                       offsetof(ClassObject, elementClass),
    434                       (Object *)elementClass);
    435     dvmSetFieldObject((Object *)newClass,
    436                       offsetof(ClassObject, classLoader),
    437                       (Object *)elementClass->classLoader);
    438     newClass->arrayDim = arrayDim;
    439     newClass->status = CLASS_INITIALIZED;
    440 #if WITH_HPROF && WITH_HPROF_STACK
    441     hprofFillInStackTrace(newClass);
    442 #endif
    443 
    444     /* don't need to set newClass->objectSize */
    445 
    446     /*
    447      * All arrays have java/lang/Cloneable and java/io/Serializable as
    448      * interfaces.  We need to set that up here, so that stuff like
    449      * "instanceof" works right.
    450      *
    451      * Note: The GC could run during the call to dvmFindSystemClassNoInit(),
    452      * so we need to make sure the class object is GC-valid while we're in
    453      * there.  Do this by clearing the interface list so the GC will just
    454      * think that the entries are null.
    455      *
    456      * TODO?
    457      * We may want to cache these two classes to avoid the lookup, though
    458      * it's not vital -- we only do it when creating an array class, not
    459      * every time we create an array.  Better yet, create a single, global
    460      * copy of "interfaces" and "iftable" somewhere near the start and
    461      * just point to those (and remember not to free them for arrays).
    462      */
    463     newClass->interfaceCount = 2;
    464     newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader,
    465                                 sizeof(ClassObject*) * 2);
    466     memset(newClass->interfaces, 0, sizeof(ClassObject*) * 2);
    467     newClass->interfaces[0] =
    468         dvmFindSystemClassNoInit("Ljava/lang/Cloneable;");
    469     newClass->interfaces[1] =
    470         dvmFindSystemClassNoInit("Ljava/io/Serializable;");
    471     dvmLinearReadOnly(newClass->classLoader, newClass->interfaces);
    472     if (newClass->interfaces[0] == NULL || newClass->interfaces[1] == NULL) {
    473         LOGE("Unable to create array class '%s': missing interfaces\n",
    474             descriptor);
    475         dvmFreeClassInnards(newClass);
    476         dvmThrowException("Ljava/lang/InternalError;", "missing array ifaces");
    477         dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    478         return NULL;
    479     }
    480     /*
    481      * We assume that Cloneable/Serializable don't have superinterfaces --
    482      * normally we'd have to crawl up and explicitly list all of the
    483      * supers as well.  These interfaces don't have any methods, so we
    484      * don't have to worry about the ifviPool either.
    485      */
    486     newClass->iftableCount = 2;
    487     newClass->iftable = (InterfaceEntry*) dvmLinearAlloc(newClass->classLoader,
    488                                 sizeof(InterfaceEntry) * 2);
    489     memset(newClass->iftable, 0, sizeof(InterfaceEntry) * 2);
    490     newClass->iftable[0].clazz = newClass->interfaces[0];
    491     newClass->iftable[1].clazz = newClass->interfaces[1];
    492     dvmLinearReadOnly(newClass->classLoader, newClass->iftable);
    493 
    494     /*
    495      * Inherit access flags from the element.  Arrays can't be used as a
    496      * superclass or interface, so we want to add "final" and remove
    497      * "interface".
    498      *
    499      * Don't inherit any non-standard flags (e.g., CLASS_FINALIZABLE)
    500      * from elementClass.  We assume that the array class does not
    501      * override finalize().
    502      */
    503     newClass->accessFlags = ((newClass->elementClass->accessFlags &
    504                              ~ACC_INTERFACE) | ACC_FINAL) & JAVA_FLAGS_MASK;
    505 
    506     /* Set the flags we determined above.
    507      * This must happen after accessFlags is set.
    508      */
    509     SET_CLASS_FLAG(newClass, extraFlags);
    510 
    511     if (!dvmAddClassToHash(newClass)) {
    512         /*
    513          * Another thread must have loaded the class after we
    514          * started but before we finished.  Discard what we've
    515          * done and leave some hints for the GC.
    516          */
    517         LOGI("WOW: somebody generated %s simultaneously\n",
    518             newClass->descriptor);
    519 
    520         /* Clean up the class before letting the
    521          * GC get its hands on it.
    522          */
    523         dvmFreeClassInnards(newClass);
    524 
    525         /* Let the GC free the class.
    526          */
    527         dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    528 
    529         /* Grab the winning class.
    530          */
    531         newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
    532         assert(newClass != NULL);
    533         return newClass;
    534     }
    535     dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    536 
    537     LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n",
    538         descriptor, newClass->classLoader,
    539         newClass->accessFlags >> 16,
    540         newClass->accessFlags & JAVA_FLAGS_MASK);
    541 
    542     return newClass;
    543 }
    544 
    545 /*
    546  * Get a class we generated for the primitive types.
    547  *
    548  * These correspond to e.g. Integer.TYPE, and are used as the element
    549  * class in arrays of primitives.
    550  *
    551  * "type" should be 'I', 'J', 'Z', etc.
    552  *
    553  * Returns NULL if the type doesn't correspond to a known primitive type.
    554  */
    555 ClassObject* dvmFindPrimitiveClass(char type)
    556 {
    557     int idx;
    558 
    559     switch (type) {
    560     case 'Z':
    561         idx = PRIM_BOOLEAN;
    562         break;
    563     case 'C':
    564         idx = PRIM_CHAR;
    565         break;
    566     case 'F':
    567         idx = PRIM_FLOAT;
    568         break;
    569     case 'D':
    570         idx = PRIM_DOUBLE;
    571         break;
    572     case 'B':
    573         idx = PRIM_BYTE;
    574         break;
    575     case 'S':
    576         idx = PRIM_SHORT;
    577         break;
    578     case 'I':
    579         idx = PRIM_INT;
    580         break;
    581     case 'J':
    582         idx = PRIM_LONG;
    583         break;
    584     case 'V':
    585         idx = PRIM_VOID;
    586         break;
    587     default:
    588         LOGW("Unknown primitive type '%c'\n", type);
    589         return NULL;
    590     }
    591 
    592     /*
    593      * Create the primitive class if it hasn't already been, and add it
    594      * to the table.
    595      */
    596     if (gDvm.primitiveClass[idx] == NULL) {
    597         ClassObject* primClass = createPrimitiveClass(idx);
    598         dvmReleaseTrackedAlloc((Object*) primClass, NULL);
    599 
    600         if (android_atomic_release_cas(0, (int) primClass,
    601                 (int*) &gDvm.primitiveClass[idx]) != 0)
    602         {
    603             /*
    604              * Looks like somebody beat us to it.  Free up the one we
    605              * just created and use the other one.
    606              */
    607             dvmFreeClassInnards(primClass);
    608         }
    609     }
    610 
    611     return gDvm.primitiveClass[idx];
    612 }
    613 
    614 /*
    615  * Synthesize a primitive class.
    616  *
    617  * Just creates the class and returns it (does not add it to the class list).
    618  */
    619 static ClassObject* createPrimitiveClass(int idx)
    620 {
    621     ClassObject* newClass;
    622     static const char* kClassDescriptors[PRIM_MAX] = {
    623         "Z", "C", "F", "D", "B", "S", "I", "J", "V"
    624     };
    625 
    626     assert(gDvm.classJavaLangClass != NULL);
    627     assert(idx >= 0 && idx < PRIM_MAX);
    628 
    629     /*
    630      * Fill out a few fields in the ClassObject.
    631      *
    632      * Note that primitive classes do not sub-class java/lang/Object.  This
    633      * matters for "instanceof" checks.  Also, we assume that the primitive
    634      * class does not override finalize().
    635      */
    636     newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
    637     if (newClass == NULL)
    638         return NULL;
    639     DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
    640     dvmSetClassSerialNumber(newClass);
    641     newClass->accessFlags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
    642     newClass->primitiveType = idx;
    643     newClass->descriptorAlloc = NULL;
    644     newClass->descriptor = kClassDescriptors[idx];
    645     //newClass->super = gDvm.classJavaLangObject;
    646     newClass->status = CLASS_INITIALIZED;
    647 #if WITH_HPROF && WITH_HPROF_STACK
    648     hprofFillInStackTrace(newClass);
    649 #endif
    650 
    651     /* don't need to set newClass->objectSize */
    652 
    653     LOGVV("Created primitive class '%s'\n", kClassDescriptors[idx]);
    654 
    655     return newClass;
    656 }
    657 
    658 /*
    659  * Copy the entire contents of one array of objects to another.  If the copy
    660  * is impossible because of a type clash, we fail and return "false".
    661  */
    662 bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
    663     ClassObject* dstElemClass)
    664 {
    665     Object** src = (Object**)srcArray->contents;
    666     u4 length, count;
    667 
    668     assert(srcArray->length == dstArray->length);
    669     assert(dstArray->obj.clazz->elementClass == dstElemClass ||
    670         (dstArray->obj.clazz->elementClass == dstElemClass->elementClass &&
    671          dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1));
    672 
    673     length = dstArray->length;
    674     for (count = 0; count < length; count++) {
    675         if (!dvmInstanceof(src[count]->clazz, dstElemClass)) {
    676             LOGW("dvmCopyObjectArray: can't store %s in %s\n",
    677                 src[count]->clazz->descriptor, dstElemClass->descriptor);
    678             return false;
    679         }
    680         dvmSetObjectArrayElement(dstArray, count, src[count]);
    681     }
    682 
    683     return true;
    684 }
    685 
    686 /*
    687  * Copy the entire contents of an array of boxed primitives into an
    688  * array of primitives.  The boxed value must fit in the primitive (i.e.
    689  * narrowing conversions are not allowed).
    690  */
    691 bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
    692     ClassObject* dstElemClass)
    693 {
    694     Object** src = (Object**)srcArray->contents;
    695     void* dst = (void*)dstArray->contents;
    696     u4 count = dstArray->length;
    697     PrimitiveType typeIndex = dstElemClass->primitiveType;
    698 
    699     assert(typeIndex != PRIM_NOT);
    700     assert(srcArray->length == dstArray->length);
    701 
    702     while (count--) {
    703         JValue result;
    704 
    705         /*
    706          * This will perform widening conversions as appropriate.  It
    707          * might make sense to be more restrictive and require that the
    708          * primitive type exactly matches the box class, but it's not
    709          * necessary for correctness.
    710          */
    711         if (!dvmUnwrapPrimitive(*src, dstElemClass, &result)) {
    712             LOGW("dvmCopyObjectArray: can't store %s in %s\n",
    713                 (*src)->clazz->descriptor, dstElemClass->descriptor);
    714             return false;
    715         }
    716 
    717         /* would be faster with 4 loops, but speed not crucial here */
    718         switch (typeIndex) {
    719         case PRIM_BOOLEAN:
    720         case PRIM_BYTE:
    721             {
    722                 u1* tmp = dst;
    723                 *tmp++ = result.b;
    724                 dst = tmp;
    725             }
    726             break;
    727         case PRIM_CHAR:
    728         case PRIM_SHORT:
    729             {
    730                 u2* tmp = dst;
    731                 *tmp++ = result.s;
    732                 dst = tmp;
    733             }
    734             break;
    735         case PRIM_FLOAT:
    736         case PRIM_INT:
    737             {
    738                 u4* tmp = dst;
    739                 *tmp++ = result.i;
    740                 dst = tmp;
    741             }
    742             break;
    743         case PRIM_DOUBLE:
    744         case PRIM_LONG:
    745             {
    746                 u8* tmp = dst;
    747                 *tmp++ = result.j;
    748                 dst = tmp;
    749             }
    750             break;
    751         default:
    752             /* should not be possible to get here */
    753             dvmAbort();
    754         }
    755 
    756         src++;
    757     }
    758 
    759     return true;
    760 }
    761 
    762 /*
    763  * Returns the width, in bytes, required by elements in instances of
    764  * the array class.
    765  */
    766 size_t dvmArrayClassElementWidth(const ClassObject* arrayClass)
    767 {
    768     const char *descriptor;
    769 
    770     assert(dvmIsArrayClass(arrayClass));
    771 
    772     if (dvmIsObjectArrayClass(arrayClass)) {
    773         return sizeof(Object *);
    774     } else {
    775         descriptor = arrayClass->descriptor;
    776         switch (descriptor[1]) {
    777         case 'B': return 1;  /* byte */
    778         case 'C': return 2;  /* char */
    779         case 'D': return 8;  /* double */
    780         case 'F': return 4;  /* float */
    781         case 'I': return 4;  /* int */
    782         case 'J': return 8;  /* long */
    783         case 'S': return 2;  /* short */
    784         case 'Z': return 1;  /* boolean */
    785         }
    786     }
    787     LOGE("class %p has an unhandled descriptor '%s'", arrayClass, descriptor);
    788     dvmDumpThread(dvmThreadSelf(), false);
    789     dvmAbort();
    790     return 0;  /* Quiet the compiler. */
    791 }
    792 
    793 size_t dvmArrayObjectSize(const ArrayObject *array)
    794 {
    795     size_t size;
    796 
    797     assert(array != NULL);
    798     size = offsetof(ArrayObject, contents);
    799     size += array->length * dvmArrayClassElementWidth(array->obj.clazz);
    800     return size;
    801 }
    802 
    803 /*
    804  * Add all primitive classes to the root set of objects.
    805 TODO: do these belong to the root class loader?
    806  */
    807 void dvmGcScanPrimitiveClasses()
    808 {
    809     int i;
    810 
    811     for (i = 0; i < PRIM_MAX; i++) {
    812         dvmMarkObject((Object *)gDvm.primitiveClass[i]);    // may be NULL
    813     }
    814 }
    815