/* * Get all interfaces a class implements. If this is unable to allocate * the result array, this raises an OutOfMemoryError and returns NULL. */ ArrayObject* dvmGetInterfaces(ClassObject* clazz) { if (!dvmIsClassInitialized(gDvm.classJavaLangReflectMethod)) dvmInitClass(gDvm.classJavaLangReflectMethod); /* * Create an array of Class objects. */ size_t count = clazz->interfaceCount; ArrayObject* interfaceArray = dvmAllocArrayByClass(gDvm.classJavaLangClassArray, count, ALLOC_DEFAULT); if (interfaceArray == NULL) return NULL; /* * Fill out the array. */ memcpy(interfaceArray->contents, clazz->interfaces, count * sizeof(Object *)); dvmWriteBarrierArray(interfaceArray, 0, count); /* caller must call dvmReleaseTrackedAlloc */ return interfaceArray; }
/* * 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(); }
static inline void xposedSetObjectArrayElement(const ArrayObject* obj, int index, Object* val) { uintptr_t arrayContents = (uintptr_t) obj + arrayContentsOffset; ((Object **) arrayContents)[index] = val; dvmWriteBarrierArray(obj, index, index + 1); }
GOTO_TARGET(filledNewArray, bool methodCallRange, bool) { ClassObject* arrayClass; ArrayObject* newArray; u4* contents; char typeCh; int i; u4 arg5; EXPORT_PC(); ref = FETCH(1); /* class ref */ vdst = FETCH(2); /* first 4 regs -or- range base */ if (methodCallRange) { vsrc1 = INST_AA(inst); /* #of elements */ arg5 = -1; /* silence compiler warning */ ILOGV("|filled-new-array-range args=%d @0x%04x {regs=v%d-v%d}", vsrc1, ref, vdst, vdst+vsrc1-1); } else { arg5 = INST_A(inst); vsrc1 = INST_B(inst); /* #of elements */ ILOGV("|filled-new-array args=%d @0x%04x {regs=0x%04x %x}", vsrc1, ref, vdst, arg5); } /* * Resolve the array class. */ arrayClass = dvmDexGetResolvedClass(methodClassDex, ref); if (arrayClass == NULL) { arrayClass = dvmResolveClass(curMethod->clazz, ref, false); if (arrayClass == NULL) GOTO_exceptionThrown(); } /* if (!dvmIsArrayClass(arrayClass)) { dvmThrowRuntimeException( "filled-new-array needs array class"); GOTO_exceptionThrown(); } */ /* verifier guarantees this is an array class */ assert(dvmIsArrayClass(arrayClass)); assert(dvmIsClassInitialized(arrayClass)); /* * Create an array of the specified type. */ LOGVV("+++ filled-new-array type is '%s'", arrayClass->descriptor); typeCh = arrayClass->descriptor[1]; if (typeCh == 'D' || typeCh == 'J') { /* category 2 primitives not allowed */ dvmThrowRuntimeException("bad filled array req"); GOTO_exceptionThrown(); } else if (typeCh != 'L' && typeCh != '[' && typeCh != 'I') { /* TODO: requires multiple "fill in" loops with different widths */ ALOGE("non-int primitives not implemented"); dvmThrowInternalError( "filled-new-array not implemented for anything but 'int'"); GOTO_exceptionThrown(); } newArray = dvmAllocArrayByClass(arrayClass, vsrc1, ALLOC_DONT_TRACK); if (newArray == NULL) GOTO_exceptionThrown(); /* * Fill in the elements. It's legal for vsrc1 to be zero. */ contents = (u4*)(void*)newArray->contents; if (methodCallRange) { for (i = 0; i < vsrc1; i++) contents[i] = GET_REGISTER(vdst+i); } else { assert(vsrc1 <= 5); if (vsrc1 == 5) { contents[4] = GET_REGISTER(arg5); vsrc1--; } for (i = 0; i < vsrc1; i++) { contents[i] = GET_REGISTER(vdst & 0x0f); vdst >>= 4; } } if (typeCh == 'L' || typeCh == '[') { dvmWriteBarrierArray(newArray, 0, newArray->length); } retval.l = (Object*)newArray; }
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(); }