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         Object** contents;
    250         int i;
    251 
    252         /* if we have X[][], find X[] */
    253         subArrayClass = dvmFindArrayClass(elemName, arrayClass->classLoader);
    254         if (subArrayClass == NULL) {
    255             /* not enough '['s on the initial class? */
    256             assert(dvmCheckException(dvmThreadSelf()));
    257             return NULL;
    258         }
    259         assert(dvmIsArrayClass(subArrayClass));
    260 
    261         /* allocate the array that holds the sub-arrays */
    262         newArray = dvmAllocArray(arrayClass, *dimensions, kObjectArrayRefWidth,
    263                         ALLOC_DEFAULT);
    264         if (newArray == NULL) {
    265             assert(dvmCheckException(dvmThreadSelf()));
    266             return NULL;
    267         }
    268 
    269         /*
    270          * Create a new sub-array in every element of the array.
    271          */
    272         contents = (Object**) newArray->contents;
    273         for (i = 0; i < *dimensions; i++) {
    274             ArrayObject* newSubArray;
    275 
    276             newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
    277                             dimensions+1);
    278             if (newSubArray == NULL) {
    279                 dvmReleaseTrackedAlloc((Object*) newArray, NULL);
    280                 assert(dvmCheckException(dvmThreadSelf()));
    281                 return NULL;
    282             }
    283 
    284             *contents++ = (Object*) newSubArray;
    285             dvmReleaseTrackedAlloc((Object*) newSubArray, NULL);
    286         }
    287     }
    288 
    289     /* caller must call dvmReleaseTrackedAlloc */
    290     return newArray;
    291 }
    292 
    293 
    294 /*
    295  * Find an array class, by name (e.g. "[I").
    296  *
    297  * If the array class doesn't exist, we generate it.
    298  *
    299  * If the element class doesn't exist, we return NULL (no exception raised).
    300  */
    301 ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader)
    302 {
    303     ClassObject* clazz;
    304 
    305     assert(descriptor[0] == '[');
    306     //LOGV("dvmFindArrayClass: '%s' %p\n", descriptor, loader);
    307 
    308     clazz = dvmLookupClass(descriptor, loader, false);
    309     if (clazz == NULL) {
    310         LOGV("Array class '%s' %p not found; creating\n", descriptor, loader);
    311         clazz = createArrayClass(descriptor, loader);
    312         if (clazz != NULL)
    313             dvmAddInitiatingLoader(clazz, loader);
    314     }
    315 
    316     return clazz;
    317 }
    318 
    319 /*
    320  * Create an array class (i.e. the class object for the array, not the
    321  * array itself).  "descriptor" looks like "[C" or "[Ljava/lang/String;".
    322  *
    323  * If "descriptor" refers to an array of primitives, look up the
    324  * primitive type's internally-generated class object.
    325  *
    326  * "loader" is the class loader of the class that's referring to us.  It's
    327  * used to ensure that we're looking for the element type in the right
    328  * context.  It does NOT become the class loader for the array class; that
    329  * always comes from the base element class.
    330  *
    331  * Returns NULL with an exception raised on failure.
    332  */
    333 static ClassObject* createArrayClass(const char* descriptor, Object* loader)
    334 {
    335     ClassObject* newClass = NULL;
    336     ClassObject* elementClass = NULL;
    337     int arrayDim;
    338     u4 extraFlags;
    339 
    340     assert(descriptor[0] == '[');
    341     assert(gDvm.classJavaLangClass != NULL);
    342     assert(gDvm.classJavaLangObject != NULL);
    343 
    344     /*
    345      * Identify the underlying element class and the array dimension depth.
    346      */
    347     extraFlags = CLASS_ISARRAY;
    348     if (descriptor[1] == '[') {
    349         /* array of arrays; keep descriptor and grab stuff from parent */
    350         ClassObject* outer;
    351 
    352         outer = dvmFindClassNoInit(&descriptor[1], loader);
    353         if (outer != NULL) {
    354             /* want the base class, not "outer", in our elementClass */
    355             elementClass = outer->elementClass;
    356             arrayDim = outer->arrayDim + 1;
    357             extraFlags |= CLASS_ISOBJECTARRAY;
    358         } else {
    359             assert(elementClass == NULL);     /* make sure we fail */
    360         }
    361     } else {
    362         arrayDim = 1;
    363         if (descriptor[1] == 'L') {
    364             /* array of objects; strip off "[" and look up descriptor. */
    365             const char* subDescriptor = &descriptor[1];
    366             LOGVV("searching for element class '%s'\n", subDescriptor);
    367             elementClass = dvmFindClassNoInit(subDescriptor, loader);
    368             extraFlags |= CLASS_ISOBJECTARRAY;
    369         } else {
    370             /* array of a primitive type */
    371             elementClass = dvmFindPrimitiveClass(descriptor[1]);
    372         }
    373     }
    374 
    375     if (elementClass == NULL) {
    376         /* failed */
    377         assert(dvmCheckException(dvmThreadSelf()));
    378         dvmFreeClassInnards(newClass);
    379         dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    380         return NULL;
    381     }
    382 
    383     /*
    384      * See if it's already loaded.  Array classes are always associated
    385      * with the class loader of their underlying element type -- an array
    386      * of Strings goes with the loader for java/lang/String -- so we need
    387      * to look for it there.  (The caller should have checked for the
    388      * existence of the class before calling here, but they did so with
    389      * *their* class loader, not the element class' loader.)
    390      *
    391      * If we find it, the caller adds "loader" to the class' initiating
    392      * loader list, which should prevent us from going through this again.
    393      *
    394      * This call is unnecessary if "loader" and "elementClass->classLoader"
    395      * are the same, because our caller (dvmFindArrayClass) just did the
    396      * lookup.  (Even if we get this wrong we still have correct behavior,
    397      * because we effectively do this lookup again when we add the new
    398      * class to the hash table -- necessary because of possible races with
    399      * other threads.)
    400      */
    401     if (loader != elementClass->classLoader) {
    402         LOGVV("--- checking for '%s' in %p vs. elem %p\n",
    403             descriptor, loader, elementClass->classLoader);
    404         newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
    405         if (newClass != NULL) {
    406             LOGV("--- we already have %s in %p, don't need in %p\n",
    407                 descriptor, elementClass->classLoader, loader);
    408             return newClass;
    409         }
    410     }
    411 
    412 
    413     /*
    414      * Fill out the fields in the ClassObject.
    415      *
    416      * It is possible to execute some methods against arrays, because all
    417      * arrays are instances of Object, so we need to set up a vtable.  We
    418      * can just point at the one in Object.
    419      *
    420      * Array classes are simple enough that we don't need to do a full
    421      * link step.
    422      */
    423     newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
    424     if (newClass == NULL)
    425         return NULL;
    426     DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass);
    427     dvmSetClassSerialNumber(newClass);
    428     newClass->descriptorAlloc = strdup(descriptor);
    429     newClass->descriptor = newClass->descriptorAlloc;
    430     newClass->super = gDvm.classJavaLangObject;
    431     newClass->vtableCount = gDvm.classJavaLangObject->vtableCount;
    432     newClass->vtable = gDvm.classJavaLangObject->vtable;
    433     newClass->primitiveType = PRIM_NOT;
    434     newClass->elementClass = elementClass;
    435     newClass->classLoader = elementClass->classLoader;
    436     newClass->arrayDim = arrayDim;
    437     newClass->status = CLASS_INITIALIZED;
    438 #if WITH_HPROF && WITH_HPROF_STACK
    439     hprofFillInStackTrace(newClass);
    440 #endif
    441 
    442     /* don't need to set newClass->objectSize */
    443 
    444     /*
    445      * All arrays have java/lang/Cloneable and java/io/Serializable as
    446      * interfaces.  We need to set that up here, so that stuff like
    447      * "instanceof" works right.
    448      *
    449      * Note: The GC could run during the call to dvmFindSystemClassNoInit(),
    450      * so we need to make sure the class object is GC-valid while we're in
    451      * there.  Do this by clearing the interface list so the GC will just
    452      * think that the entries are null.
    453      *
    454      * TODO?
    455      * We may want to cache these two classes to avoid the lookup, though
    456      * it's not vital -- we only do it when creating an array class, not
    457      * every time we create an array.  Better yet, create a single, global
    458      * copy of "interfaces" and "iftable" somewhere near the start and
    459      * just point to those (and remember not to free them for arrays).
    460      */
    461     newClass->interfaceCount = 2;
    462     newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader,
    463                                 sizeof(ClassObject*) * 2);
    464     memset(newClass->interfaces, 0, sizeof(ClassObject*) * 2);
    465     newClass->interfaces[0] =
    466         dvmFindSystemClassNoInit("Ljava/lang/Cloneable;");
    467     newClass->interfaces[1] =
    468         dvmFindSystemClassNoInit("Ljava/io/Serializable;");
    469     dvmLinearReadOnly(newClass->classLoader, newClass->interfaces);
    470     if (newClass->interfaces[0] == NULL || newClass->interfaces[1] == NULL) {
    471         LOGE("Unable to create array class '%s': missing interfaces\n",
    472             descriptor);
    473         dvmFreeClassInnards(newClass);
    474         dvmThrowException("Ljava/lang/InternalError;", "missing array ifaces");
    475         dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    476         return NULL;
    477     }
    478     /*
    479      * We assume that Cloneable/Serializable don't have superinterfaces --
    480      * normally we'd have to crawl up and explicitly list all of the
    481      * supers as well.  These interfaces don't have any methods, so we
    482      * don't have to worry about the ifviPool either.
    483      */
    484     newClass->iftableCount = 2;
    485     newClass->iftable = (InterfaceEntry*) dvmLinearAlloc(newClass->classLoader,
    486                                 sizeof(InterfaceEntry) * 2);
    487     memset(newClass->iftable, 0, sizeof(InterfaceEntry) * 2);
    488     newClass->iftable[0].clazz = newClass->interfaces[0];
    489     newClass->iftable[1].clazz = newClass->interfaces[1];
    490     dvmLinearReadOnly(newClass->classLoader, newClass->iftable);
    491 
    492     /*
    493      * Inherit access flags from the element.  Arrays can't be used as a
    494      * superclass or interface, so we want to add "final" and remove
    495      * "interface".
    496      *
    497      * Don't inherit any non-standard flags (e.g., CLASS_FINALIZABLE)
    498      * from elementClass.  We assume that the array class does not
    499      * override finalize().
    500      */
    501     newClass->accessFlags = ((newClass->elementClass->accessFlags &
    502                              ~ACC_INTERFACE) | ACC_FINAL) & JAVA_FLAGS_MASK;
    503 
    504     /* Set the flags we determined above.
    505      * This must happen after accessFlags is set.
    506      */
    507     SET_CLASS_FLAG(newClass, extraFlags);
    508 
    509     if (!dvmAddClassToHash(newClass)) {
    510         /*
    511          * Another thread must have loaded the class after we
    512          * started but before we finished.  Discard what we've
    513          * done and leave some hints for the GC.
    514          */
    515         LOGI("WOW: somebody generated %s simultaneously\n",
    516             newClass->descriptor);
    517 
    518         /* Clean up the class before letting the
    519          * GC get its hands on it.
    520          */
    521         assert(newClass->obj.clazz == gDvm.unlinkedJavaLangClass);
    522         dvmFreeClassInnards(newClass);
    523 
    524         /* Let the GC free the class.
    525          */
    526         dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    527 
    528         /* Grab the winning class.
    529          */
    530         newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
    531         assert(newClass != NULL);
    532         return newClass;
    533     }
    534 
    535     /* make it available to the GC */
    536     newClass->obj.clazz = gDvm.classJavaLangClass;
    537     dvmReleaseTrackedAlloc((Object*) newClass, NULL);
    538 
    539     LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n",
    540         descriptor, newClass->classLoader,
    541         newClass->accessFlags >> 16,
    542         newClass->accessFlags & JAVA_FLAGS_MASK);
    543 
    544     return newClass;
    545 }
    546 
    547 /*
    548  * Get a class we generated for the primitive types.
    549  *
    550  * These correspond to e.g. Integer.TYPE, and are used as the element
    551  * class in arrays of primitives.
    552  *
    553  * "type" should be 'I', 'J', 'Z', etc.
    554  *
    555  * Returns NULL if the type doesn't correspond to a known primitive type.
    556  */
    557 ClassObject* dvmFindPrimitiveClass(char type)
    558 {
    559     int idx;
    560 
    561     switch (type) {
    562     case 'Z':
    563         idx = PRIM_BOOLEAN;
    564         break;
    565     case 'C':
    566         idx = PRIM_CHAR;
    567         break;
    568     case 'F':
    569         idx = PRIM_FLOAT;
    570         break;
    571     case 'D':
    572         idx = PRIM_DOUBLE;
    573         break;
    574     case 'B':
    575         idx = PRIM_BYTE;
    576         break;
    577     case 'S':
    578         idx = PRIM_SHORT;
    579         break;
    580     case 'I':
    581         idx = PRIM_INT;
    582         break;
    583     case 'J':
    584         idx = PRIM_LONG;
    585         break;
    586     case 'V':
    587         idx = PRIM_VOID;
    588         break;
    589     default:
    590         LOGW("Unknown primitive type '%c'\n", type);
    591         return NULL;
    592     }
    593 
    594     /*
    595      * Create the primitive class if it hasn't already been, and add it
    596      * to the table.
    597      */
    598     if (gDvm.primitiveClass[idx] == NULL) {
    599         ClassObject* primClass = createPrimitiveClass(idx);
    600         dvmReleaseTrackedAlloc((Object*) primClass, NULL);
    601 
    602         if (!ATOMIC_CMP_SWAP((int*) &gDvm.primitiveClass[idx],
    603             0, (int) primClass))
    604         {
    605             /*
    606              * Looks like somebody beat us to it.  Free up the one we
    607              * just created and use the other one.
    608              */
    609             dvmFreeClassInnards(primClass);
    610         }
    611     }
    612 
    613     return gDvm.primitiveClass[idx];
    614 }
    615 
    616 /*
    617  * Synthesize a primitive class.
    618  *
    619  * The spec for java.lang.Class.isPrimitive describes the names to
    620  * be used for these classes.
    621  *
    622  * Just creates the class and returns it (does not add it to the class list).
    623  */
    624 static ClassObject* createPrimitiveClass(int idx)
    625 {
    626     ClassObject* newClass;
    627     static const char* kClassDescriptors[PRIM_MAX] = {
    628         "Z", "C", "F", "D", "B", "S", "I", "J", "V"
    629     };
    630 
    631     assert(gDvm.classJavaLangClass != NULL);
    632     assert(idx >= 0 && idx < PRIM_MAX);
    633 
    634     /*
    635      * Fill out a few fields in the ClassObject.
    636      *
    637      * Note that primitive classes do not sub-class java/lang/Object.  This
    638      * matters for "instanceof" checks.  Also, we assume that the primitive
    639      * class does not override finalize().
    640      */
    641     newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
    642     if (newClass == NULL)
    643         return NULL;
    644     DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
    645     dvmSetClassSerialNumber(newClass);
    646     newClass->accessFlags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
    647     newClass->primitiveType = idx;
    648     newClass->descriptorAlloc = NULL;
    649     newClass->descriptor = kClassDescriptors[idx];
    650     //newClass->super = gDvm.classJavaLangObject;
    651     newClass->status = CLASS_INITIALIZED;
    652 #if WITH_HPROF && WITH_HPROF_STACK
    653     hprofFillInStackTrace(newClass);
    654 #endif
    655 
    656     /* don't need to set newClass->objectSize */
    657 
    658     LOGVV("Created primitive class '%s'\n", kClassDescriptors[idx]);
    659 
    660     return newClass;
    661 }
    662 
    663 /*
    664  * Copy the entire contents of one array of objects to another.  If the copy
    665  * is impossible because of a type clash, we fail and return "false".
    666  */
    667 bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
    668     ClassObject* dstElemClass)
    669 {
    670     Object** src = (Object**)srcArray->contents;
    671     Object** dst = (Object**)dstArray->contents;
    672     u4 count = dstArray->length;
    673 
    674     assert(srcArray->length == dstArray->length);
    675     assert(dstArray->obj.clazz->elementClass == dstElemClass ||
    676         (dstArray->obj.clazz->elementClass == dstElemClass->elementClass &&
    677          dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1));
    678 
    679     while (count--) {
    680         if (!dvmInstanceof((*src)->clazz, dstElemClass)) {
    681             LOGW("dvmCopyObjectArray: can't store %s in %s\n",
    682                 (*src)->clazz->descriptor, dstElemClass->descriptor);
    683             return false;
    684         }
    685         *dst++ = *src++;
    686     }
    687 
    688     return true;
    689 }
    690 
    691 /*
    692  * Copy the entire contents of an array of boxed primitives into an
    693  * array of primitives.  The boxed value must fit in the primitive (i.e.
    694  * narrowing conversions are not allowed).
    695  */
    696 bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
    697     ClassObject* dstElemClass)
    698 {
    699     Object** src = (Object**)srcArray->contents;
    700     void* dst = (void*)dstArray->contents;
    701     u4 count = dstArray->length;
    702     PrimitiveType typeIndex = dstElemClass->primitiveType;
    703 
    704     assert(typeIndex != PRIM_NOT);
    705     assert(srcArray->length == dstArray->length);
    706 
    707     while (count--) {
    708         JValue result;
    709 
    710         /*
    711          * This will perform widening conversions as appropriate.  It
    712          * might make sense to be more restrictive and require that the
    713          * primitive type exactly matches the box class, but it's not
    714          * necessary for correctness.
    715          */
    716         if (!dvmUnwrapPrimitive(*src, dstElemClass, &result)) {
    717             LOGW("dvmCopyObjectArray: can't store %s in %s\n",
    718                 (*src)->clazz->descriptor, dstElemClass->descriptor);
    719             return false;
    720         }
    721 
    722         /* would be faster with 4 loops, but speed not crucial here */
    723         switch (typeIndex) {
    724         case PRIM_BOOLEAN:
    725         case PRIM_BYTE:
    726             {
    727                 u1* tmp = dst;
    728                 *tmp++ = result.b;
    729                 dst = tmp;
    730             }
    731             break;
    732         case PRIM_CHAR:
    733         case PRIM_SHORT:
    734             {
    735                 u2* tmp = dst;
    736                 *tmp++ = result.s;
    737                 dst = tmp;
    738             }
    739             break;
    740         case PRIM_FLOAT:
    741         case PRIM_INT:
    742             {
    743                 u4* tmp = dst;
    744                 *tmp++ = result.i;
    745                 dst = tmp;
    746             }
    747             break;
    748         case PRIM_DOUBLE:
    749         case PRIM_LONG:
    750             {
    751                 u8* tmp = dst;
    752                 *tmp++ = result.j;
    753                 dst = tmp;
    754             }
    755             break;
    756         default:
    757             /* should not be possible to get here */
    758             dvmAbort();
    759         }
    760 
    761         src++;
    762     }
    763 
    764     return true;
    765 }
    766 
    767 /*
    768  * Add all primitive classes to the root set of objects.
    769 TODO: do these belong to the root class loader?
    770  */
    771 void dvmGcScanPrimitiveClasses()
    772 {
    773     int i;
    774 
    775     for (i = 0; i < PRIM_MAX; i++) {
    776         dvmMarkObject((Object *)gDvm.primitiveClass[i]);    // may be NULL
    777     }
    778 }
    779