/* * Create a copy of an object, for Object.clone(). * * We use the size actually allocated, rather than obj->clazz->objectSize, * because the latter doesn't work for array objects. */ Object* dvmCloneObject(Object* obj, int flags) { assert(dvmIsValidObject(obj)); ClassObject* clazz = obj->clazz; /* Class.java shouldn't let us get here (java.lang.Class is final * and does not implement Clonable), but make extra sure. * A memcpy() clone will wreak havoc on a ClassObject's "innards". */ assert(!dvmIsTheClassClass(clazz)); size_t size; if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) { size = dvmArrayObjectSize((ArrayObject *)obj); } else { size = clazz->objectSize; } Object* copy = (Object*)dvmMalloc(size, flags); copy->tag = 0; if (copy == NULL) return NULL; DVM_OBJECT_INIT(copy, clazz); size_t offset = sizeof(Object); /* Copy instance data. We assume memcpy copies by words. */ memcpy((char*)copy + offset, (char*)obj + offset, size - offset); /* Mark the clone as finalizable if appropriate. */ if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) { dvmSetFinalizable(copy); } dvmTrackAllocation(clazz, size); /* notify DDMS */ pthread_mutex_lock(&gDvm.s_mtx); if(gDvm.newObjHook){ gDvm.newObjHook(copy); } pthread_mutex_unlock(&gDvm.s_mtx); return copy; }
/* * Called by dlmalloc_inspect_all. If used_bytes != 0 then start is * the start of a malloc-ed piece of memory of size used_bytes. If * start is 0 then start is the beginning of any free space not * including dlmalloc's book keeping and end the start of the next * dlmalloc chunk. Regions purely containing book keeping don't * callback. */ static void heap_chunk_callback(void* start, void* end, size_t used_bytes, void* arg) { u1 state; HeapChunkContext *ctx = (HeapChunkContext *)arg; UNUSED_PARAMETER(end); if (used_bytes == 0) { if (start == NULL) { // Reset for start of new heap. ctx->startOfNextMemoryChunk = NULL; flush_hpsg_chunk(ctx); } // Only process in use memory so that free region information // also includes dlmalloc book keeping. return; } /* If we're looking at the native heap, we'll just return * (SOLIDITY_HARD, KIND_NATIVE) for all allocated chunks */ bool native = ctx->type == CHUNK_TYPE("NHSG"); if (ctx->startOfNextMemoryChunk != NULL) { // Transmit any pending free memory. Native free memory of // over kMaxFreeLen could be because of the use of mmaps, so // don't report. If not free memory then start a new segment. bool flush = true; if (start > ctx->startOfNextMemoryChunk) { const size_t kMaxFreeLen = 2 * SYSTEM_PAGE_SIZE; void* freeStart = ctx->startOfNextMemoryChunk; void* freeEnd = start; size_t freeLen = (char*)freeEnd - (char*)freeStart; if (!native || freeLen < kMaxFreeLen) { append_chunk(ctx, HPSG_STATE(SOLIDITY_FREE, 0), freeStart, freeLen); flush = false; } } if (flush) { ctx->startOfNextMemoryChunk = NULL; flush_hpsg_chunk(ctx); } } const Object *obj = (const Object *)start; /* It's an allocated chunk. Figure out what it is. */ //TODO: if ctx.merge, see if this chunk is different from the last chunk. // If it's the same, we should combine them. if (!native && dvmIsValidObject(obj)) { ClassObject *clazz = obj->clazz; if (clazz == NULL) { /* The object was probably just created * but hasn't been initialized yet. */ state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT); } else if (dvmIsTheClassClass(clazz)) { state = HPSG_STATE(SOLIDITY_HARD, KIND_CLASS_OBJECT); } else if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) { if (IS_CLASS_FLAG_SET(clazz, CLASS_ISOBJECTARRAY)) { state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4); } else { switch (clazz->elementClass->primitiveType) { case PRIM_BOOLEAN: case PRIM_BYTE: state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_1); break; case PRIM_CHAR: case PRIM_SHORT: state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_2); break; case PRIM_INT: case PRIM_FLOAT: state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_4); break; case PRIM_DOUBLE: case PRIM_LONG: state = HPSG_STATE(SOLIDITY_HARD, KIND_ARRAY_8); break; default: assert(!"Unknown GC heap object type"); state = HPSG_STATE(SOLIDITY_HARD, KIND_UNKNOWN); break; } } } else { state = HPSG_STATE(SOLIDITY_HARD, KIND_OBJECT); } } else { obj = NULL; // it's not actually an object state = HPSG_STATE(SOLIDITY_HARD, KIND_NATIVE); } append_chunk(ctx, state, start, used_bytes + HEAP_SOURCE_CHUNK_OVERHEAD); ctx->startOfNextMemoryChunk = (char*)start + used_bytes + HEAP_SOURCE_CHUNK_OVERHEAD; }