/* * public static void arraycopy(Object src, int srcPos, Object dest, * int destPos, int length) * * The description of this function is long, and describes a multitude * of checks and exceptions. */ static void Dalvik_java_lang_System_arraycopy(const u4* args, JValue* pResult) { void* (*copyFunc)(void *dest, const void *src, size_t n); ArrayObject* srcArray; ArrayObject* dstArray; ClassObject* srcClass; ClassObject* dstClass; int srcPos, dstPos, length; char srcType, dstType; bool srcPrim, dstPrim; srcArray = (ArrayObject*) args[0]; srcPos = args[1]; dstArray = (ArrayObject*) args[2]; dstPos = args[3]; length = args[4]; if (srcArray == dstArray) copyFunc = memmove; /* might overlap */ else copyFunc = memcpy; /* can't overlap, use faster func */ /* check for null or bad pointer */ if (!dvmValidateObject((Object*)srcArray) || !dvmValidateObject((Object*)dstArray)) { assert(dvmCheckException(dvmThreadSelf())); RETURN_VOID(); } /* make sure it's an array */ if (!dvmIsArray(srcArray) || !dvmIsArray(dstArray)) { dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;", "source and destination must be arrays, but were %s and %s", ((Object*)srcArray)->clazz->descriptor, ((Object*)dstArray)->clazz->descriptor); RETURN_VOID(); } // avoid int overflow if (srcPos < 0 || dstPos < 0 || length < 0 || srcPos > (int) srcArray->length - length || dstPos > (int) dstArray->length - length) { dvmThrowExceptionFmt("Ljava/lang/ArrayIndexOutOfBoundsException;", "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d", srcArray->length, srcPos, dstArray->length, dstPos, length); RETURN_VOID(); } srcClass = srcArray->obj.clazz; dstClass = dstArray->obj.clazz; srcType = srcClass->descriptor[1]; dstType = dstClass->descriptor[1]; /* * If one of the arrays holds a primitive type, the other array must * hold the same type. */ srcPrim = (srcType != '[' && srcType != 'L'); dstPrim = (dstType != '[' && dstType != 'L'); if (srcPrim || dstPrim) { int width; if (srcPrim != dstPrim || srcType != dstType) { dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;", "source and destination arrays are incompatible: %s and %s", srcClass->descriptor, dstClass->descriptor); RETURN_VOID(); } switch (srcClass->descriptor[1]) { case 'B': case 'Z': width = 1; break; case 'C': case 'S': width = 2; break; case 'F': case 'I': width = 4; break; case 'D': case 'J': width = 8; break; default: /* 'V' or something weird */ LOGE("Weird array type '%s'\n", srcClass->descriptor); assert(false); width = 0; break; } if (false) LOGVV("arraycopy prim dst=%p %d src=%p %d len=%d\n", dstArray->contents, dstPos * width, srcArray->contents, srcPos * width, length * width); (*copyFunc)((u1*)dstArray->contents + dstPos * width, (const u1*)srcArray->contents + srcPos * width, length * width); } else { /* * Neither class is primitive. See if elements in "src" are instances * of elements in "dst" (e.g. copy String to String or String to * Object). */ int width = sizeof(Object*); if (srcClass->arrayDim == dstClass->arrayDim && dvmInstanceof(srcClass, dstClass)) { /* * "dst" can hold "src"; copy the whole thing. */ if (false) LOGVV("arraycopy ref dst=%p %d src=%p %d len=%d\n", dstArray->contents, dstPos * width, srcArray->contents, srcPos * width, length * width); (*copyFunc)((u1*)dstArray->contents + dstPos * width, (const u1*)srcArray->contents + srcPos * width, length * width); dvmWriteBarrierArray(dstArray, dstPos, dstPos+length); } else { /* * The arrays are not fundamentally compatible. However, we may * still be able to do this if the destination object is compatible * (e.g. copy Object to String, but the Object being copied is * actually a String). We need to copy elements one by one until * something goes wrong. * * Because of overlapping moves, what we really want to do is * compare the types and count up how many we can move, then call * memmove() to shift the actual data. If we just start from the * front we could do a smear rather than a move. */ Object** srcObj; Object** dstObj; int copyCount; ClassObject* clazz = NULL; srcObj = ((Object**) srcArray->contents) + srcPos; dstObj = ((Object**) dstArray->contents) + dstPos; if (length > 0 && srcObj[0] != NULL) { clazz = srcObj[0]->clazz; if (!dvmCanPutArrayElement(clazz, dstClass)) clazz = NULL; } for (copyCount = 0; copyCount < length; copyCount++) { if (srcObj[copyCount] != NULL && srcObj[copyCount]->clazz != clazz && !dvmCanPutArrayElement(srcObj[copyCount]->clazz, dstClass)) { /* can't put this element into the array */ break; } } if (false) LOGVV("arraycopy iref dst=%p %d src=%p %d count=%d of %d\n", dstArray->contents, dstPos * width, srcArray->contents, srcPos * width, copyCount, length); (*copyFunc)((u1*)dstArray->contents + dstPos * width, (const u1*)srcArray->contents + srcPos * width, copyCount * width); dvmWriteBarrierArray(dstArray, 0, copyCount); if (copyCount != length) { dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;", "source[%d] of type %s cannot be stored in destination array of type %s", copyCount, srcObj[copyCount]->clazz->descriptor, dstClass->descriptor); RETURN_VOID(); } } } RETURN_VOID(); }
void fastiva_Dalvik_java_lang_System_arraycopy(java_lang_Object_p arg0, jint srcPos, java_lang_Object_p arg2, jint dstPos, jint length) { ArrayObject* srcArray = (ArrayObject*) arg0; ArrayObject* dstArray = (ArrayObject*) arg2; #endif /* Check for null pointers. */ if (srcArray == NULL) { dvmThrowNullPointerException("src == null"); THROW_VOID(); } if (dstArray == NULL) { dvmThrowNullPointerException("dst == null"); THROW_VOID(); } /* Make sure source and destination are arrays. */ if (!dvmIsArray(srcArray)) { dvmThrowArrayStoreExceptionNotArray(((Object*)srcArray)->clazz, "source"); THROW_VOID(); } if (!dvmIsArray(dstArray)) { dvmThrowArrayStoreExceptionNotArray(((Object*)dstArray)->clazz, "destination"); THROW_VOID(); } /* avoid int overflow */ if (srcPos < 0 || dstPos < 0 || length < 0 || srcPos > (int) srcArray->length - length || dstPos > (int) dstArray->length - length) { dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException, "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d", srcArray->length, srcPos, dstArray->length, dstPos, length); THROW_VOID(); } ClassObject* srcClass = srcArray->clazz; ClassObject* dstClass = dstArray->clazz; char srcType = srcClass->descriptor[1]; char dstType = dstClass->descriptor[1]; /* * If one of the arrays holds a primitive type, the other array must * hold the same type. */ bool srcPrim = (srcType != '[' && srcType != 'L'); bool dstPrim = (dstType != '[' && dstType != 'L'); if (srcPrim || dstPrim) { if (srcPrim != dstPrim || srcType != dstType) { dvmThrowArrayStoreExceptionIncompatibleArrays(srcClass, dstClass); THROW_VOID(); } if (false) ALOGD("arraycopy prim[%c] dst=%p %d src=%p %d len=%d", srcType, dstArray->contents, dstPos, srcArray->contents, srcPos, length); switch (srcType) { case 'B': case 'Z': /* 1 byte per element */ memmove((u1*) dstArray->contents + dstPos, (const u1*) srcArray->contents + srcPos, length); break; case 'C': case 'S': /* 2 bytes per element */ move16((u1*) dstArray->contents + dstPos * 2, (const u1*) srcArray->contents + srcPos * 2, length * 2); break; case 'F': case 'I': /* 4 bytes per element */ move32((u1*) dstArray->contents + dstPos * 4, (const u1*) srcArray->contents + srcPos * 4, length * 4); break; case 'D': case 'J': /* * 8 bytes per element. We don't need to guarantee atomicity * of the entire 64-bit word, so we can use the 32-bit copier. */ move32((u1*) dstArray->contents + dstPos * 8, (const u1*) srcArray->contents + srcPos * 8, length * 8); break; default: /* illegal array type */ ALOGE("Weird array type '%s'", srcClass->descriptor); dvmAbort(); } } else { /* * Neither class is primitive. See if elements in "src" are instances * of elements in "dst" (e.g. copy String to String or String to * Object). */ const int width = sizeof(Object*); if (srcClass->arrayDim == dstClass->arrayDim && dvmInstanceof(srcClass, dstClass)) { /* * "dst" can hold "src"; copy the whole thing. */ if (false) ALOGD("arraycopy ref dst=%p %d src=%p %d len=%d", dstArray->contents, dstPos * width, srcArray->contents, srcPos * width, length * width); move32((u1*)dstArray->contents + dstPos * width, (const u1*)srcArray->contents + srcPos * width, length * width); dvmWriteBarrierArray(dstArray, dstPos, dstPos+length); } else { /* * The arrays are not fundamentally compatible. However, we * may still be able to do this if the destination object is * compatible (e.g. copy Object[] to String[], but the Object * being copied is actually a String). We need to copy elements * one by one until something goes wrong. * * Because of overlapping moves, what we really want to do * is compare the types and count up how many we can move, * then call move32() to shift the actual data. If we just * start from the front we could do a smear rather than a move. */ Object** srcObj; int copyCount; ClassObject* clazz = NULL; srcObj = ((Object**)(void*)srcArray->contents) + srcPos; if (length > 0 && srcObj[0] != NULL) { clazz = srcObj[0]->clazz; if (!dvmCanPutArrayElement(clazz, dstClass)) clazz = NULL; } for (copyCount = 0; copyCount < length; copyCount++) { if (srcObj[copyCount] != NULL && srcObj[copyCount]->clazz != clazz && !dvmCanPutArrayElement(srcObj[copyCount]->clazz, dstClass)) { /* can't put this element into the array */ break; } } if (false) ALOGD("arraycopy iref dst=%p %d src=%p %d count=%d of %d", dstArray->contents, dstPos * width, srcArray->contents, srcPos * width, copyCount, length); move32((u1*)dstArray->contents + dstPos * width, (const u1*)srcArray->contents + srcPos * width, copyCount * width); dvmWriteBarrierArray(dstArray, 0, copyCount); if (copyCount != length) { dvmThrowArrayStoreExceptionIncompatibleArrayElement(srcPos + copyCount, srcObj[copyCount]->clazz, dstClass); THROW_VOID(); } } } RETURN_VOID(); }