diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index 78a83301d7f..eaa77d36b37 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -101,6 +101,7 @@ struct CompartmentStats int64_t gcHeapXML; int64_t objectSlots; + int64_t objectElements; int64_t stringChars; int64_t shapesExtraTreeTables; int64_t shapesExtraDictTables; diff --git a/js/src/MemoryMetrics.cpp b/js/src/MemoryMetrics.cpp index 1881ca13072..001078b3668 100644 --- a/js/src/MemoryMetrics.cpp +++ b/js/src/MemoryMetrics.cpp @@ -130,7 +130,10 @@ CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind, } else { curr->gcHeapObjectsNonFunction += thingSize; } - curr->objectSlots += obj->dynamicSlotSize(data->mallocSizeOf); + size_t slotsSize, elementsSize; + obj->sizeOfExcludingThis(data->mallocSizeOf, &slotsSize, &elementsSize); + curr->objectSlots += slotsSize; + curr->objectElements += elementsSize; break; } case JSTRACE_STRING: @@ -272,7 +275,8 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data) data->gcHeapArenaUnused += stats.gcHeapArenaUnused; data->totalObjects += stats.gcHeapObjectsNonFunction + stats.gcHeapObjectsFunction + - stats.objectSlots; + stats.objectSlots + + stats.objectElements; data->totalShapes += stats.gcHeapShapesTree + stats.gcHeapShapesDict + stats.gcHeapShapesBase + diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 9d55351ec83..48e8d81fbce 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -979,7 +979,7 @@ JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure) JS_PUBLIC_API(size_t) JS_GetObjectTotalSize(JSContext *cx, JSObject *obj) { - return obj->slotsAndStructSize(); + return obj->computedSizeOfIncludingThis(); } static size_t diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index d1212713c62..350d1d87431 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3419,7 +3419,7 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b, * swaps can be performed infallibly. */ - if (a->structSize() == b->structSize()) + if (a->sizeOfThis() == b->sizeOfThis()) return true; /* @@ -3512,7 +3512,7 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved & JS_ASSERT(a->isFunction() == b->isFunction()); /* Don't try to swap a JSFunction for a plain function JSObject. */ - JS_ASSERT_IF(a->isFunction(), a->structSize() == b->structSize()); + JS_ASSERT_IF(a->isFunction(), a->sizeOfThis() == b->sizeOfThis()); /* * Regexp guts are more complicated -- we would need to migrate the @@ -3542,8 +3542,8 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved & #endif /* Trade the guts of the objects. */ - const size_t size = a->structSize(); - if (size == b->structSize()) { + const size_t size = a->sizeOfThis(); + if (size == b->sizeOfThis()) { /* * If the objects are the same size, then we make no assumptions about * whether they have dynamically allocated slots and instead just copy @@ -4098,7 +4098,7 @@ JSObject::growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount) */ JS_ASSERT(newCount < NELEMENTS_LIMIT); - size_t oldSize = Probes::objectResizeActive() ? slotsAndStructSize() : 0; + size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0; size_t newSize = oldSize + (newCount - oldCount) * sizeof(Value); /* @@ -4167,7 +4167,7 @@ JSObject::shrinkSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount) if (isCall()) return; - size_t oldSize = Probes::objectResizeActive() ? slotsAndStructSize() : 0; + size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0; size_t newSize = oldSize - (oldCount - newCount) * sizeof(Value); if (newCount == 0) { @@ -4213,7 +4213,7 @@ JSObject::growElements(JSContext *cx, uintN newcap) uint32_t oldcap = getDenseArrayCapacity(); JS_ASSERT(oldcap <= newcap); - size_t oldSize = Probes::objectResizeActive() ? slotsAndStructSize() : 0; + size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0; uint32_t nextsize = (oldcap <= CAPACITY_DOUBLING_MAX) ? oldcap * 2 @@ -4256,7 +4256,7 @@ JSObject::growElements(JSContext *cx, uintN newcap) Debug_SetValueRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen); if (Probes::objectResizeActive()) - Probes::resizeObject(cx, this, oldSize, slotsAndStructSize()); + Probes::resizeObject(cx, this, oldSize, computedSizeOfIncludingThis()); return true; } @@ -4269,7 +4269,7 @@ JSObject::shrinkElements(JSContext *cx, uintN newcap) uint32_t oldcap = getDenseArrayCapacity(); JS_ASSERT(newcap <= oldcap); - size_t oldSize = Probes::objectResizeActive() ? slotsAndStructSize() : 0; + size_t oldSize = Probes::objectResizeActive() ? computedSizeOfIncludingThis() : 0; /* Don't shrink elements below the minimum capacity. */ if (oldcap <= SLOT_CAPACITY_MIN || !hasDynamicElements()) @@ -4288,7 +4288,7 @@ JSObject::shrinkElements(JSContext *cx, uintN newcap) elements = newheader->elements(); if (Probes::objectResizeActive()) - Probes::resizeObject(cx, this, oldSize, slotsAndStructSize()); + Probes::resizeObject(cx, this, oldSize, computedSizeOfIncludingThis()); } #ifdef DEBUG diff --git a/js/src/jsobj.h b/js/src/jsobj.h index eff9daceb4b..0052fceceed 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -669,9 +669,12 @@ struct JSObject : js::gc::Cell inline bool hasPropertyTable() const; - inline size_t structSize() const; - inline size_t slotsAndStructSize() const; - inline size_t dynamicSlotSize(JSMallocSizeOfFun mallocSizeOf) const; + inline size_t sizeOfThis() const; + inline size_t computedSizeOfIncludingThis() const; + + /* mallocSizeOf can be NULL, in which case we compute the sizes analytically */ + inline void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, + size_t *slotsSize, size_t *elementsSize) const; inline size_t numFixedSlots() const; diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index f329af4c471..e36f1f6d1fa 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1199,32 +1199,38 @@ JSObject::hasPropertyTable() const } inline size_t -JSObject::structSize() const +JSObject::sizeOfThis() const { return arenaHeader()->getThingSize(); } inline size_t -JSObject::slotsAndStructSize() const +JSObject::computedSizeOfIncludingThis() const { - return structSize() + dynamicSlotSize(NULL); + size_t slotsSize, elementsSize; + sizeOfExcludingThis(NULL, &slotsSize, &elementsSize); + return sizeOfThis() + slotsSize + elementsSize; } -inline size_t -JSObject::dynamicSlotSize(JSMallocSizeOfFun mallocSizeOf) const +inline void +JSObject::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, + size_t *slotsSize, size_t *elementsSize) const { - size_t size = 0; if (hasDynamicSlots()) { - size_t bytes = numDynamicSlots() * sizeof(js::Value); - size += mallocSizeOf ? mallocSizeOf(slots, bytes) : bytes; + size_t computedSize = numDynamicSlots() * sizeof(js::Value); + *slotsSize = mallocSizeOf ? mallocSizeOf(slots, computedSize) : computedSize; + } else { + *slotsSize = 0; } if (hasDynamicElements()) { - size_t bytes = + size_t computedSize = (js::ObjectElements::VALUES_PER_HEADER + getElementsHeader()->capacity) * sizeof(js::Value); - size += mallocSizeOf ? mallocSizeOf(getElementsHeader(), bytes) : bytes; + *elementsSize = + mallocSizeOf ? mallocSizeOf(getElementsHeader(), computedSize) : computedSize; + } else { + *elementsSize = 0; } - return size; } inline JSBool @@ -1564,7 +1570,7 @@ NewObjectCache::fill(EntryIndex entry_, Class *clasp, gc::Cell *key, gc::AllocKi entry->key = key; entry->kind = kind; - entry->nbytes = obj->structSize(); + entry->nbytes = obj->sizeOfThis(); js_memcpy(&entry->templateObject, obj, entry->nbytes); } diff --git a/js/src/jsprobes.cpp b/js/src/jsprobes.cpp index c994ff6e1af..b2629f0290f 100644 --- a/js/src/jsprobes.cpp +++ b/js/src/jsprobes.cpp @@ -444,7 +444,7 @@ Probes::ETWCreateObject(JSContext *cx, JSObject *obj) return EventWriteEvtObjectCreate(script_filename, lineno, ObjectClassname(obj), reinterpret_cast(obj), - obj ? obj->slotsAndStructSize() : 0) == ERROR_SUCCESS; + obj ? obj->computedSizeOfIncludingThis() : 0) == ERROR_SUCCESS; } bool diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 7121f2929f6..692462de1f5 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1513,6 +1513,13 @@ ReportCompartmentStats(const JS::CompartmentStats &stats, "'gc-heap/objects' instead." SLOP_BYTES_STRING, callback, closure); + ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats, + "object-elements"), + nsIMemoryReporter::KIND_HEAP, stats.objectElements, + "Memory allocated for the compartment's object element arrays, " + "which are used to represent indexed object properties." SLOP_BYTES_STRING, + callback, closure); + ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats, "string-chars"), nsIMemoryReporter::KIND_HEAP, stats.stringChars,