/*
 * This is a qsort() callback.  We sort Object* by class, allocation size,
 * and then by the Object* itself.
 */
static int compareObject(const void* vobj1, const void* vobj2)
{
    Object* obj1 = *((Object**) vobj1);
    Object* obj2 = *((Object**) vobj2);

    if (obj1 == NULL || obj2 == NULL)
        return (u1*)obj1 - (u1*)obj2;

    if (obj1->clazz != obj2->clazz) {
        return (u1*)obj1->clazz - (u1*)obj2->clazz;
    } else {
        int size1 = dvmObjectSizeInHeap(obj1);
        int size2 = dvmObjectSizeInHeap(obj2);
        if (size1 != size2) {
            return size1 - size2;
        } else {
            return (u1*)obj1 - (u1*)obj2;
        }
    }
}
Beispiel #2
0
/*
 * 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)
{
    Object* copy;
    int size;
    int flags;

    assert(dvmIsValidObject(obj));

    /* 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(obj->clazz != gDvm.classJavaLangClass);

    if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE))
        flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE;
    else
        flags = ALLOC_DEFAULT;

//TODO: use clazz->objectSize for non-arrays
    size = dvmObjectSizeInHeap(obj);

    copy = dvmMalloc(size, flags);
    if (copy == NULL)
        return NULL;
#if WITH_HPROF && WITH_HPROF_STACK
    hprofFillInStackTrace(copy);
    dvmTrackAllocation(obj->clazz, size);
#endif

    memcpy(copy, obj, size);

    DVM_LOCK_INIT(&copy->lock);

	Monitor* mon = NULL;//dvmCreateMonitor(copy);
	copy->lock = (u4)mon | LW_SHAPE_FAT;

    //LOGV("CloneObject: %p->%p %s (%d)\n", obj, copy, obj->clazz->name, size);

    // TODO: deal with reference classes

    /* don't call dvmReleaseTrackedAlloc -- the caller must do that */

    return copy;
}
/*
 * Dump a summary of an array of references to the log file.
 *
 * This is used to dump the contents of ReferenceTable and IndirectRefTable
 * structs.
 */
void dvmDumpReferenceTableContents(Object* const* refs, size_t count,
                                   const char* descr)
{
    LOGW("%s reference table (%p) dump:", descr, refs);

    if (count == 0) {
        LOGW("  (empty)");
        return;
    }

    // Dump the most recent N entries.
    const size_t kLast = 10;
    int first = count - kLast;
    if (first < 0) {
        first = 0;
    }
    LOGW("  Last %d entries (of %d):", (count - first), count);
    for (int idx = count - 1; idx >= first; --idx) {
        const Object* ref = refs[idx];
        if (ref == NULL) {
            continue;
        }
        if (ref == kClearedJniWeakGlobal) {
            LOGW("    %5d: cleared jweak", idx);
            continue;
        }
        if (ref->clazz == NULL) {
            // should only be possible right after a plain dvmMalloc().
            size_t size = dvmObjectSizeInHeap(ref);
            LOGW("    %5d: %p (raw) (%zd bytes)", idx, ref, size);
            continue;
        }

        std::string className(dvmHumanReadableType(ref));

        std::string extras;
        size_t elems = getElementCount(ref);
        if (elems != 0) {
            StringAppendF(&extras, " (%zd elements)", elems);
        } else if (ref->clazz == gDvm.classJavaLangString) {
            const StringObject* str =
                reinterpret_cast<const StringObject*>(ref);
            extras += " \"";
            size_t count = 0;
            char* s = dvmCreateCstrFromString(str);
            char* p = s;
            for (; *p && count < 16; ++p, ++count) {
                extras += *p;
            }
            if (*p == 0) {
                extras += "\"";
            } else {
                StringAppendF(&extras, "... (%d chars)", str->length());
            }
            free(s);
        }
        LOGW("    %5d: %p %s%s", idx, ref, className.c_str(), extras.c_str());
    }

    // Make a copy of the table, and sort it.
    Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
    if (tableCopy == NULL) {
        LOGE("Unable to copy table with %d elements", count);
        return;
    }
    memcpy(tableCopy, refs, sizeof(Object*) * count);
    qsort(tableCopy, count, sizeof(Object*), compareObject);
    refs = tableCopy;       // use sorted list

    // Remove any uninteresting stuff from the list. The sort moved them all to the end.
    while (count > 0 && refs[count-1] == NULL) {
        --count;
    }
    while (count > 0 && refs[count-1] == kClearedJniWeakGlobal) {
        --count;
    }
    if (count == 0) {
        return;
    }

    // Dump a summary of the whole table.
    LOGW("  Summary:");
    size_t equiv, identical;
    equiv = identical = 0;
    size_t idx;
    size_t elems;
    for (idx = 1; idx < count; idx++) {
        elems = getElementCount(refs[idx-1]);

        if (refs[idx] == refs[idx-1]) {
            // same reference, added more than once.
            identical++;
        } else if (refs[idx]->clazz == refs[idx-1]->clazz &&
                   getElementCount(refs[idx]) == elems)
        {
            // same class / element count, different object.
            equiv++;
        } else {
            // different class.
            logSummaryLine(refs[idx-1], elems, identical, equiv);
            equiv = identical = 0;
        }
    }

    // Handle the last entry (everything above outputs refs[i-1]).
    elems = getElementCount(refs[idx-1]);
    logSummaryLine(refs[count-1], elems, identical, equiv);

    free(tableCopy);
}
/*
 * Dump the contents of a ReferenceTable to the log.
 *
 * The caller should lock any external sync before calling.
 *
 * (This was originally written to be tolerant of null entries in the table.
 * I don't think that can happen anymore.)
 */
void dvmDumpReferenceTable(const ReferenceTable* pRef, const char* descr)
{
    const int kLast = 10;
    int count = dvmReferenceTableEntries(pRef);
    Object** refs;
    int i;

    if (count == 0) {
        LOGW("%s reference table has no entries\n", descr);
        return;
    }
    assert(count > 0);

    /*
     * Dump the most recent N entries.
     */
    LOGW("Last %d entries in %s reference table:\n", kLast, descr);
    refs = pRef->table;         // use unsorted list
    int size;
    int start = count - kLast;
    if (start < 0)
        start = 0;

    for (i = start; i < count; i++) {
        size = (refs[i] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i]);
        Object* ref = refs[i];
        if (ref->clazz == gDvm.classJavaLangClass) {
            ClassObject* clazz = (ClassObject*) ref;
            LOGW("%5d: %p cls=%s '%s' (%d bytes)\n", i, ref,
                (refs[i] == NULL) ? "-" : ref->clazz->descriptor,
                clazz->descriptor, size);
        } else if (ref->clazz == NULL) {
            /* should only be possible right after a plain dvmMalloc() */
            LOGW("%5d: %p cls=(raw) (%d bytes)\n", i, ref, size);
        } else {
            LOGW("%5d: %p cls=%s (%d bytes)\n", i, ref,
                (refs[i] == NULL) ? "-" : ref->clazz->descriptor, size);
        }
    }

    /*
     * Make a copy of the table, and sort it.
     */
    Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
    memcpy(tableCopy, pRef->table, sizeof(Object*) * count);
    qsort(tableCopy, count, sizeof(Object*), compareObject);
    refs = tableCopy;       // use sorted list

    /*
     * Dump uniquified table summary.  While we're at it, generate a
     * cumulative total amount of pinned memory based on the unique entries.
     */
    LOGW("%s reference table summary (%d entries):\n", descr, count);
    int equiv, identical, total;
    total = equiv = identical = 0;
    for (i = 1; i < count; i++) {
        size = (refs[i-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[i-1]);

        if (refs[i] == refs[i-1]) {
            /* same reference, added more than once */
            identical++;
        } else if (refs[i]->clazz == refs[i-1]->clazz &&
            (int) dvmObjectSizeInHeap(refs[i]) == size)
        {
            /* same class / size, different object */
            total += size;
            equiv++;
        } else {
            /* different class */
            total += size;
            logObject(refs[i-1], size, identical, equiv);
            equiv = identical = 0;
        }
    }

    /* handle the last entry (everything above outputs refs[i-1]) */
    size = (refs[count-1] == NULL) ? 0 : dvmObjectSizeInHeap(refs[count-1]);
    total += size;
    logObject(refs[count-1], size, identical, equiv);

    LOGW("Memory held directly by tracked refs is %d bytes\n", total);
    free(tableCopy);
}