auto import from //depot/cupcake/@135843
diff --git a/vm/oo/Array.c b/vm/oo/Array.c
new file mode 100644
index 0000000..19a0f96
--- /dev/null
+++ b/vm/oo/Array.c
@@ -0,0 +1,711 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Array objects.
+ */
+#include "Dalvik.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#if WITH_HPROF && WITH_HPROF_STACK
+#include "hprof/Hprof.h"
+#endif
+
+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
+ * allocation function.
+ *
+ * Pass in the array class and the width of each element.
+ *
+ * On failure, returns NULL with an exception raised.
+ */
+ArrayObject* dvmAllocArray(ClassObject* arrayClass, size_t length,
+ size_t elemWidth, int allocFlags)
+{
+ ArrayObject* newArray;
+ size_t size;
+
+ assert(arrayClass->descriptor[0] == '[');
+
+ if (length > 0x0fffffff) {
+ /* too large and (length * elemWidth) will overflow 32 bits */
+ LOGE("Rejecting allocation of %u-element array\n", length);
+ dvmThrowBadAllocException("array size too large");
+ return NULL;
+ }
+
+ size = offsetof(ArrayObject, contents);
+ size += length * elemWidth;
+
+ /* Note that we assume that the Array class does not
+ * override finalize().
+ */
+ newArray = dvmMalloc(size, allocFlags);
+ if (newArray != NULL) {
+ DVM_OBJECT_INIT(&newArray->obj, arrayClass);
+ newArray->length = length;
+ LOGVV("AllocArray: %s [%d] (%d)\n",
+ arrayClass->descriptor, (int) length, (int) size);
+#if WITH_HPROF && WITH_HPROF_STACK
+ hprofFillInStackTrace(&newArray->obj);
+#endif
+ dvmTrackAllocation(arrayClass, size);
+ }
+ /* the caller must call dvmReleaseTrackedAlloc */
+ return newArray;
+}
+
+/*
+ * Create a new array, given an array class. The class may represent an
+ * array of references or primitives.
+ */
+ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass,
+ size_t length, int allocFlags)
+{
+ const char* descriptor = arrayClass->descriptor;
+
+ assert(descriptor[0] == '['); /* must be array class */
+ if (descriptor[1] != '[' && descriptor[1] != 'L') {
+ /* primitive array */
+ assert(descriptor[2] == '\0');
+ return dvmAllocPrimitiveArray(descriptor[1], length, allocFlags);
+ } else {
+ return dvmAllocArray(arrayClass, length, kObjectArrayRefWidth,
+ allocFlags);
+ }
+}
+
+/*
+ * Find the array class for "elemClassObj", which could itself be an
+ * array class.
+ */
+ClassObject* dvmFindArrayClassForElement(ClassObject* elemClassObj)
+{
+ ClassObject* arrayClass;
+
+ assert(elemClassObj != NULL);
+
+ if (elemClassObj->arrayClass != NULL) {
+ arrayClass = elemClassObj->arrayClass;
+ LOGVV("using cached '%s' class for '%s'\n",
+ arrayClass->descriptor, elemClassObj->descriptor);
+ } else {
+ /* Simply prepend "[" to the descriptor. */
+ int nameLen = strlen(elemClassObj->descriptor);
+ char className[nameLen + 2];
+
+ className[0] = '[';
+ memcpy(className+1, elemClassObj->descriptor, nameLen+1);
+ arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader);
+ if (arrayClass != NULL)
+ elemClassObj->arrayClass = arrayClass;
+ }
+
+ return arrayClass;
+}
+
+/*
+ * Create a new array that holds references to members of the specified class.
+ *
+ * "elemClassObj" is the element type, and may itself be an array class. It
+ * may not be a primitive class.
+ *
+ * "allocFlags" determines whether the new object will be added to the
+ * "tracked alloc" table.
+ *
+ * This is less efficient than dvmAllocArray(), but occasionally convenient.
+ */
+ArrayObject* dvmAllocObjectArray(ClassObject* elemClassObj, size_t length,
+ int allocFlags)
+{
+ ClassObject* arrayClass;
+ ArrayObject* newArray = NULL;
+
+ LOGVV("dvmAllocObjectArray: '%s' len=%d\n",
+ elemClassObj->descriptor, (int)length);
+
+ arrayClass = dvmFindArrayClassForElement(elemClassObj);
+ if (arrayClass != NULL) {
+ newArray = dvmAllocArray(arrayClass, length, kObjectArrayRefWidth,
+ allocFlags);
+ }
+
+ /* the caller must call dvmReleaseTrackedAlloc */
+ return newArray;
+}
+
+/*
+ * Create a new array that holds primitive types.
+ *
+ * "type" is the primitive type letter, e.g. 'I' for int or 'J' for long.
+ * If the array class doesn't exist, it will be created.
+ */
+ArrayObject* dvmAllocPrimitiveArray(char type, size_t length, int allocFlags)
+{
+ ArrayObject* newArray;
+ ClassObject** pTypeClass;
+ int width;
+
+ switch (type) {
+ case 'I':
+ pTypeClass = &gDvm.classArrayInt;
+ width = 4;
+ break;
+ case 'C':
+ pTypeClass = &gDvm.classArrayChar;
+ width = 2;
+ break;
+ case 'B':
+ pTypeClass = &gDvm.classArrayByte;
+ width = 1;
+ break;
+ case 'Z':
+ pTypeClass = &gDvm.classArrayBoolean;
+ width = 1; /* special-case this? */
+ break;
+ case 'F':
+ pTypeClass = &gDvm.classArrayFloat;
+ width = 4;
+ break;
+ case 'D':
+ pTypeClass = &gDvm.classArrayDouble;
+ width = 8;
+ break;
+ case 'S':
+ pTypeClass = &gDvm.classArrayShort;
+ width = 2;
+ break;
+ case 'J':
+ pTypeClass = &gDvm.classArrayLong;
+ width = 8;
+ break;
+ default:
+ LOGE("Unknown type '%c'\n", type);
+ assert(false);
+ return NULL;
+ }
+
+ if (*pTypeClass == NULL) {
+ char typeClassName[3] = "[x";
+
+ typeClassName[1] = type;
+
+ *pTypeClass = dvmFindArrayClass(typeClassName, NULL);
+ if (*pTypeClass == NULL) {
+ LOGE("ERROR: failed to generate array class for '%s'\n",
+ typeClassName);
+ return NULL;
+ }
+ }
+
+ newArray = dvmAllocArray(*pTypeClass, length, width, allocFlags);
+
+ /* the caller must dvmReleaseTrackedAlloc if allocFlags==ALLOC_DEFAULT */
+ return newArray;
+}
+
+/*
+ * Recursively create an array with multiple dimensions. Elements may be
+ * Objects or primitive types.
+ *
+ * The dimension we're creating is in dimensions[0], so when we recurse
+ * we advance the pointer.
+ */
+ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim,
+ const int* dimensions)
+{
+ ArrayObject* newArray;
+ const char* elemName = arrayClass->descriptor + 1; // Advance past one '['.
+
+ LOGVV("dvmAllocMultiArray: class='%s' curDim=%d *dimensions=%d\n",
+ arrayClass->descriptor, curDim, *dimensions);
+
+ if (curDim == 0) {
+ if (*elemName == 'L' || *elemName == '[') {
+ LOGVV(" end: array class (obj) is '%s'\n",
+ arrayClass->descriptor);
+ newArray = dvmAllocArray(arrayClass, *dimensions,
+ kObjectArrayRefWidth, ALLOC_DEFAULT);
+ } else {
+ LOGVV(" end: array class (prim) is '%s'\n",
+ arrayClass->descriptor);
+ newArray = dvmAllocPrimitiveArray(
+ gPrimLetter[arrayClass->elementClass->primitiveType],
+ *dimensions, ALLOC_DEFAULT);
+ }
+ } else {
+ ClassObject* subArrayClass;
+ Object** contents;
+ int i;
+
+ /* if we have X[][], find X[] */
+ subArrayClass = dvmFindArrayClass(elemName, arrayClass->classLoader);
+ if (subArrayClass == NULL) {
+ /* not enough '['s on the initial class? */
+ assert(dvmCheckException(dvmThreadSelf()));
+ return NULL;
+ }
+ assert(dvmIsArrayClass(subArrayClass));
+
+ /* allocate the array that holds the sub-arrays */
+ newArray = dvmAllocArray(arrayClass, *dimensions, kObjectArrayRefWidth,
+ ALLOC_DEFAULT);
+ if (newArray == NULL) {
+ assert(dvmCheckException(dvmThreadSelf()));
+ return NULL;
+ }
+
+ /*
+ * Create a new sub-array in every element of the array.
+ */
+ contents = (Object**) newArray->contents;
+ for (i = 0; i < *dimensions; i++) {
+ ArrayObject* newSubArray;
+
+ newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
+ dimensions+1);
+ if (newSubArray == NULL) {
+ dvmReleaseTrackedAlloc((Object*) newArray, NULL);
+ assert(dvmCheckException(dvmThreadSelf()));
+ return NULL;
+ }
+
+ *contents++ = (Object*) newSubArray;
+ dvmReleaseTrackedAlloc((Object*) newSubArray, NULL);
+ }
+ }
+
+ /* caller must call dvmReleaseTrackedAlloc */
+ return newArray;
+}
+
+
+/*
+ * Find an array class, by name (e.g. "[I").
+ *
+ * If the array class doesn't exist, we generate it.
+ *
+ * If the element class doesn't exist, we return NULL (no exception raised).
+ */
+ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader)
+{
+ ClassObject* clazz;
+
+ assert(descriptor[0] == '[');
+ //LOGV("dvmFindArrayClass: '%s' %p\n", descriptor, loader);
+
+ clazz = dvmLookupClass(descriptor, loader, false);
+ if (clazz == NULL) {
+ LOGV("Array class '%s' %p not found; creating\n", descriptor, loader);
+ clazz = createArrayClass(descriptor, loader);
+ if (clazz != NULL)
+ dvmAddInitiatingLoader(clazz, loader);
+ }
+
+ return clazz;
+}
+
+/*
+ * Create an array class (i.e. the class object for the array, not the
+ * array itself). "descriptor" looks like "[C" or "[Ljava/lang/String;".
+ *
+ * If "descriptor" refers to an array of primitives, look up the
+ * primitive type's internally-generated class object.
+ *
+ * "loader" is the class loader of the class that's referring to us. It's
+ * used to ensure that we're looking for the element type in the right
+ * context. It does NOT become the class loader for the array class; that
+ * always comes from the base element class.
+ *
+ * Returns NULL with an exception raised on failure.
+ */
+static ClassObject* createArrayClass(const char* descriptor, Object* loader)
+{
+ ClassObject* newClass = NULL;
+ ClassObject* elementClass = NULL;
+ int arrayDim;
+ u4 extraFlags;
+
+ assert(descriptor[0] == '[');
+ assert(gDvm.classJavaLangClass != NULL);
+ assert(gDvm.classJavaLangObject != NULL);
+
+ /*
+ * Identify the underlying element class and the array dimension depth.
+ */
+ extraFlags = CLASS_ISARRAY;
+ if (descriptor[1] == '[') {
+ /* array of arrays; keep descriptor and grab stuff from parent */
+ ClassObject* outer;
+
+ outer = dvmFindClassNoInit(&descriptor[1], loader);
+ if (outer != NULL) {
+ /* want the base class, not "outer", in our elementClass */
+ elementClass = outer->elementClass;
+ arrayDim = outer->arrayDim + 1;
+ extraFlags |= CLASS_ISOBJECTARRAY;
+ } else {
+ assert(elementClass == NULL); /* make sure we fail */
+ }
+ } else {
+ arrayDim = 1;
+ if (descriptor[1] == 'L') {
+ /* array of objects; strip off "[" and look up descriptor. */
+ const char* subDescriptor = &descriptor[1];
+ LOGVV("searching for element class '%s'\n", subDescriptor);
+ elementClass = dvmFindClassNoInit(subDescriptor, loader);
+ extraFlags |= CLASS_ISOBJECTARRAY;
+ } else {
+ /* array of a primitive type */
+ elementClass = dvmFindPrimitiveClass(descriptor[1]);
+ }
+ }
+
+ if (elementClass == NULL) {
+ /* failed */
+ assert(dvmCheckException(dvmThreadSelf()));
+ dvmFreeClassInnards(newClass);
+ dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+ return NULL;
+ }
+
+ /*
+ * See if it's already loaded. Array classes are always associated
+ * with the class loader of their underlying element type -- an array
+ * of Strings goes with the loader for java/lang/String -- so we need
+ * to look for it there. (The caller should have checked for the
+ * existence of the class before calling here, but they did so with
+ * *their* class loader, not the element class' loader.)
+ *
+ * If we find it, the caller adds "loader" to the class' initiating
+ * loader list, which should prevent us from going through this again.
+ *
+ * This call is unnecessary if "loader" and "elementClass->classLoader"
+ * are the same, because our caller (dvmFindArrayClass) just did the
+ * lookup. (Even if we get this wrong we still have correct behavior,
+ * because we effectively do this lookup again when we add the new
+ * class to the hash table -- necessary because of possible races with
+ * other threads.)
+ */
+ if (loader != elementClass->classLoader) {
+ LOGVV("--- checking for '%s' in %p vs. elem %p\n",
+ descriptor, loader, elementClass->classLoader);
+ newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
+ if (newClass != NULL) {
+ LOGV("--- we already have %s in %p, don't need in %p\n",
+ descriptor, elementClass->classLoader, loader);
+ return newClass;
+ }
+ }
+
+
+ /*
+ * Fill out the fields in the ClassObject.
+ *
+ * It is possible to execute some methods against arrays, because all
+ * arrays are instances of Object, so we need to set up a vtable. We
+ * can just point at the one in Object.
+ *
+ * Array classes are simple enough that we don't need to do a full
+ * link step.
+ */
+ newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
+ if (newClass == NULL)
+ return NULL;
+ DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass);
+ dvmSetClassSerialNumber(newClass);
+ newClass->descriptorAlloc = strdup(descriptor);
+ newClass->descriptor = newClass->descriptorAlloc;
+ newClass->super = gDvm.classJavaLangObject;
+ newClass->vtableCount = gDvm.classJavaLangObject->vtableCount;
+ newClass->vtable = gDvm.classJavaLangObject->vtable;
+ newClass->primitiveType = PRIM_NOT;
+ newClass->elementClass = elementClass;
+ newClass->classLoader = elementClass->classLoader;
+ newClass->arrayDim = arrayDim;
+ newClass->status = CLASS_INITIALIZED;
+#if WITH_HPROF && WITH_HPROF_STACK
+ hprofFillInStackTrace(newClass);
+#endif
+
+ /* don't need to set newClass->objectSize */
+
+ /*
+ * All arrays have java/lang/Cloneable and java/io/Serializable as
+ * interfaces. We need to set that up here, so that stuff like
+ * "instanceof" works right.
+ *
+ * Note: The GC could run during the call to dvmFindSystemClassNoInit(),
+ * so we need to make sure the class object is GC-valid while we're in
+ * there. Do this by clearing the interface list so the GC will just
+ * think that the entries are null.
+ *
+ * TODO?
+ * We may want to cache these two classes to avoid the lookup, though
+ * it's not vital -- we only do it when creating an array class, not
+ * every time we create an array. Better yet, create a single, global
+ * copy of "interfaces" and "iftable" somewhere near the start and
+ * just point to those (and remember not to free them for arrays).
+ */
+ newClass->interfaceCount = 2;
+ newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader,
+ sizeof(ClassObject*) * 2);
+ memset(newClass->interfaces, 0, sizeof(ClassObject*) * 2);
+ newClass->interfaces[0] =
+ dvmFindSystemClassNoInit("Ljava/lang/Cloneable;");
+ newClass->interfaces[1] =
+ dvmFindSystemClassNoInit("Ljava/io/Serializable;");
+ dvmLinearReadOnly(newClass->classLoader, newClass->interfaces);
+ if (newClass->interfaces[0] == NULL || newClass->interfaces[1] == NULL) {
+ LOGE("Unable to create array class '%s': missing interfaces\n",
+ descriptor);
+ dvmFreeClassInnards(newClass);
+ dvmThrowException("Ljava/lang/InternalError;", "missing array ifaces");
+ dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+ return NULL;
+ }
+ /*
+ * We assume that Cloneable/Serializable don't have superinterfaces --
+ * normally we'd have to crawl up and explicitly list all of the
+ * supers as well. These interfaces don't have any methods, so we
+ * don't have to worry about the ifviPool either.
+ */
+ newClass->iftableCount = 2;
+ newClass->iftable = (InterfaceEntry*) dvmLinearAlloc(newClass->classLoader,
+ sizeof(InterfaceEntry) * 2);
+ memset(newClass->iftable, 0, sizeof(InterfaceEntry) * 2);
+ newClass->iftable[0].clazz = newClass->interfaces[0];
+ newClass->iftable[1].clazz = newClass->interfaces[1];
+ dvmLinearReadOnly(newClass->classLoader, newClass->iftable);
+
+ /*
+ * Inherit access flags from the element. Arrays can't be used as a
+ * superclass or interface, so we want to add "final" and remove
+ * "interface".
+ *
+ * Don't inherit any non-standard flags (e.g., CLASS_FINALIZABLE)
+ * from elementClass. We assume that the array class does not
+ * override finalize().
+ */
+ newClass->accessFlags = ((newClass->elementClass->accessFlags &
+ ~ACC_INTERFACE) | ACC_FINAL) & JAVA_FLAGS_MASK;
+
+ /* Set the flags we determined above.
+ * This must happen after accessFlags is set.
+ */
+ SET_CLASS_FLAG(newClass, extraFlags);
+
+ if (!dvmAddClassToHash(newClass)) {
+ /*
+ * Another thread must have loaded the class after we
+ * started but before we finished. Discard what we've
+ * done and leave some hints for the GC.
+ */
+ LOGI("WOW: somebody generated %s simultaneously\n",
+ newClass->descriptor);
+
+ /* Clean up the class before letting the
+ * GC get its hands on it.
+ */
+ assert(newClass->obj.clazz == gDvm.unlinkedJavaLangClass);
+ dvmFreeClassInnards(newClass);
+
+ /* Let the GC free the class.
+ */
+ dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+
+ /* Grab the winning class.
+ */
+ newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
+ assert(newClass != NULL);
+ return newClass;
+ }
+
+ /* make it available to the GC */
+ newClass->obj.clazz = gDvm.classJavaLangClass;
+ dvmReleaseTrackedAlloc((Object*) newClass, NULL);
+
+ LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n",
+ descriptor, newClass->classLoader,
+ newClass->accessFlags >> 16,
+ newClass->accessFlags & JAVA_FLAGS_MASK);
+
+ return newClass;
+}
+
+/*
+ * 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 (!ATOMIC_CMP_SWAP((int*) &gDvm.primitiveClass[idx],
+ 0, (int) primClass))
+ {
+ /*
+ * 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.
+ *
+ * The spec for java.lang.Class.isPrimitive describes the names to
+ * be used for these classes.
+ *
+ * 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;
+#if WITH_HPROF && WITH_HPROF_STACK
+ hprofFillInStackTrace(newClass);
+#endif
+
+ /* 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".
+ */
+bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
+ ClassObject* dstElemClass)
+{
+ Object** src = (Object**)srcArray->contents;
+ Object** dst = (Object**)dstArray->contents;
+ u4 count = dstArray->length;
+
+ assert(srcArray->length == dstArray->length);
+ assert(dstArray->obj.clazz->elementClass == dstElemClass ||
+ (dstArray->obj.clazz->elementClass == dstElemClass->elementClass &&
+ dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1));
+
+ while (count--) {
+ if (!dvmInstanceof((*src)->clazz, dstElemClass)) {
+ LOGW("dvmCopyObjectArray: can't store %s in %s\n",
+ (*src)->clazz->descriptor, dstElemClass->descriptor);
+ return false;
+ }
+ *dst++ = *src++;
+ }
+
+ return true;
+}
+
+/*
+ * Add all primitive classes to the root set of objects.
+TODO: do these belong to the root class loader?
+ */
+void dvmGcScanPrimitiveClasses()
+{
+ int i;
+
+ for (i = 0; i < PRIM_MAX; i++) {
+ dvmMarkObject((Object *)gDvm.primitiveClass[i]); // may be NULL
+ }
+}
+