--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -54,16 +54,18 @@
#include "nsITimer.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsIXPConnect.h"
#include "jscntxt.h"
#include "jsdbgapi.h"
#include "jsprf.h"
+#include "js/MemoryMetrics.h"
+
#include "nsAlgorithm.h"
#include "nsContentUtils.h"
#include "nsDOMClassInfo.h"
#include "nsDOMJSUtils.h"
#include "nsGUIEvent.h"
#include "nsJSEnvironment.h"
#include "nsJSUtils.h"
#include "nsNetUtil.h"
@@ -88,17 +90,17 @@
#if 0 // Define to run GC more often.
#define EXTRA_GC
#endif
using mozilla::MutexAutoLock;
using mozilla::TimeDuration;
using mozilla::TimeStamp;
using mozilla::dom::workers::exceptions::ThrowDOMExceptionForCode;
-using mozilla::xpconnect::memory::IterateData;
+using mozilla::xpconnect::memory::ReportJSRuntimeStats;
USING_WORKERS_NAMESPACE
namespace {
const char gErrorChars[] = "error";
const char gMessageChars[] = "message";
@@ -218,17 +220,18 @@ public:
}
NS_IMETHOD
CollectReports(nsIMemoryMultiReporterCallback* aCallback,
nsISupports* aClosure)
{
AssertIsOnMainThread();
- IterateData data;
+ JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+ xpc::DestroyCompartmentName);
nsresult rv = CollectForRuntime(/* isQuick = */false, &data);
if (NS_FAILED(rv)) {
return rv;
}
// Always report, even if we're disabled, so that we at least get an entry
// in about::memory.
ReportJSRuntimeStats(data, mPathPrefix, aCallback, aClosure);
@@ -1470,19 +1473,19 @@ public:
return true;
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
JSAutoSuspendRequest asr(aCx);
- *mSucceeded = mIsQuick ?
- mozilla::xpconnect::memory::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), mData) :
- mozilla::xpconnect::memory::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), mData);
+ *mSucceeded = mIsQuick
+ ? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), xpc::JsMallocSizeOf)
+ : JS::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), static_cast<JS::IterateData*>(mData));
{
MutexAutoLock lock(mMutex);
mDone = true;
mCondVar.Notify();
}
return true;
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -64,26 +64,16 @@ class JSAutoStructuredCloneBuffer;
class nsIDocument;
class nsIPrincipal;
class nsIMemoryMultiReporter;
class nsIScriptContext;
class nsIURI;
class nsPIDOMWindow;
class nsITimer;
-namespace mozilla {
-namespace xpconnect {
-namespace memory {
-
-struct IterateData;
-
-} // namespace memory
-} // namespace xpconnect
-} // namespace mozilla
-
BEGIN_WORKERS_NAMESPACE
class WorkerPrivate;
class WorkerRunnable : public nsIRunnable
{
public:
enum Target { ParentThread, WorkerThread };
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -39,31 +39,34 @@
/*
* These declarations are not within jsapi.h because they are highly likely
* to change in the future. Depend on them at your own risk.
*/
#include <string.h>
+#include "jsalloc.h"
#include "jspubtd.h"
#include "js/Utility.h"
+#include "js/Vector.h"
namespace JS {
/* Data for tracking analysis/inference memory usage. */
struct TypeInferenceMemoryStats
{
int64_t scripts;
int64_t objects;
int64_t tables;
int64_t temporary;
};
+typedef void* (* GetNameCallback)(JSContext *cx, JSCompartment *c);
typedef void (* DestroyNameCallback)(void *string);
struct CompartmentStats
{
CompartmentStats()
{
memset(this, 0, sizeof(*this));
}
@@ -107,53 +110,105 @@ struct CompartmentStats
#ifdef JS_METHODJIT
int64_t mjitCode;
int64_t mjitData;
#endif
TypeInferenceMemoryStats typeInferenceMemory;
};
+struct IterateData
+{
+ IterateData(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
+ DestroyNameCallback destroyNameCb)
+ : runtimeObject(0)
+ , runtimeAtomsTable(0)
+ , runtimeContexts(0)
+ , runtimeThreadsNormal(0)
+ , runtimeThreadsTemporary(0)
+ , runtimeThreadsRegexpCode(0)
+ , runtimeThreadsStackCommitted(0)
+ , gcHeapChunkTotal(0)
+ , gcHeapChunkCleanUnused(0)
+ , gcHeapChunkDirtyUnused(0)
+ , gcHeapChunkCleanDecommitted(0)
+ , gcHeapChunkDirtyDecommitted(0)
+ , gcHeapArenaUnused(0)
+ , gcHeapChunkAdmin(0)
+ , gcHeapUnusedPercentage(0)
+ , totalObjects(0)
+ , totalShapes(0)
+ , totalScripts(0)
+ , totalStrings(0)
+#ifdef JS_METHODJIT
+ , totalMjit(0)
+#endif
+ , totalTypeInference(0)
+ , totalAnalysisTemp(0)
+ , compartmentStatsVector()
+ , currCompartmentStats(NULL)
+ , mallocSizeOf(mallocSizeOf)
+ , getNameCb(getNameCb)
+ , destroyNameCb(destroyNameCb)
+ {}
+
+ int64_t runtimeObject;
+ int64_t runtimeAtomsTable;
+ int64_t runtimeContexts;
+ int64_t runtimeThreadsNormal;
+ int64_t runtimeThreadsTemporary;
+ int64_t runtimeThreadsRegexpCode;
+ int64_t runtimeThreadsStackCommitted;
+ int64_t gcHeapChunkTotal;
+ int64_t gcHeapChunkCleanUnused;
+ int64_t gcHeapChunkDirtyUnused;
+ int64_t gcHeapChunkCleanDecommitted;
+ int64_t gcHeapChunkDirtyDecommitted;
+ int64_t gcHeapArenaUnused;
+ int64_t gcHeapChunkAdmin;
+ int64_t gcHeapUnusedPercentage;
+ int64_t totalObjects;
+ int64_t totalShapes;
+ int64_t totalScripts;
+ int64_t totalStrings;
+#ifdef JS_METHODJIT
+ int64_t totalMjit;
+#endif
+ int64_t totalTypeInference;
+ int64_t totalAnalysisTemp;
+
+ js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
+ CompartmentStats *currCompartmentStats;
+
+ JSMallocSizeOfFun mallocSizeOf;
+ GetNameCallback getNameCb;
+ DestroyNameCallback destroyNameCb;
+};
+
+extern JS_PUBLIC_API(bool)
+CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
+
+extern JS_PUBLIC_API(bool)
+GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
+ JSMallocSizeOfFun mallocSizeOf);
+
extern JS_PUBLIC_API(void)
SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
TypeInferenceMemoryStats *stats,
JSMallocSizeOfFun mallocSizeOf);
extern JS_PUBLIC_API(void)
SizeOfObjectTypeInferenceData(/*TypeObject*/ void *object,
TypeInferenceMemoryStats *stats,
JSMallocSizeOfFun mallocSizeOf);
extern JS_PUBLIC_API(size_t)
-SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_PUBLIC_API(size_t)
SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
extern JS_PUBLIC_API(size_t)
-SizeOfCompartmentMjitCode(const JSCompartment *c);
-
-extern JS_PUBLIC_API(bool)
-IsShapeInDictionary(const void *shape);
-
-extern JS_PUBLIC_API(size_t)
-SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_PUBLIC_API(size_t)
-SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf);
-
-extern JS_PUBLIC_API(size_t)
-SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
-
-#ifdef JS_METHODJIT
-extern JS_PUBLIC_API(size_t)
-SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf);
-#endif
-
-extern JS_PUBLIC_API(size_t)
SystemCompartmentCount(const JSRuntime *rt);
extern JS_PUBLIC_API(size_t)
UserCompartmentCount(const JSRuntime *rt);
} // namespace JS
#endif // js_MemoryMetrics_h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -166,16 +166,17 @@ CPPSRCS = \
BytecodeEmitter.cpp \
FoldConstants.cpp \
ParseMaps.cpp \
ParseNode.cpp \
Parser.cpp \
SemanticAnalysis.cpp \
TokenStream.cpp \
LifoAlloc.cpp \
+ MemoryMetrics.cpp \
RegExpObject.cpp \
RegExpStatics.cpp \
RegExp.cpp \
Statistics.cpp \
Unicode.cpp \
$(NULL)
# Changes to internal header files, used externally, massively slow down
new file mode 100644
--- /dev/null
+++ b/js/src/MemoryMetrics.cpp
@@ -0,0 +1,382 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is about:memory glue.
+ *
+ * The Initial Developer of the Original Code is
+ * Ms2ger <ms2ger@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "js/MemoryMetrics.h"
+
+#include "mozilla/Assertions.h"
+
+#include "jsapi.h"
+#include "jscntxt.h"
+#include "jscompartment.h"
+#include "jsgc.h"
+#include "jsobj.h"
+#include "jsscope.h"
+#include "jsscript.h"
+
+#include "jsobjinlines.h"
+
+namespace JS {
+
+using namespace js;
+
+static void
+CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
+{
+ // Append a new CompartmentStats to the vector.
+ IterateData *data = static_cast<IterateData *>(vdata);
+
+ // CollectCompartmentStatsForRuntime reserves enough space.
+ MOZ_ALWAYS_TRUE(data->compartmentStatsVector.growBy(1));
+ CompartmentStats &curr = data->compartmentStatsVector.back();
+ curr.init(data->getNameCb(cx, compartment), data->destroyNameCb);
+ data->currCompartmentStats = &curr;
+
+ // Get the compartment-level numbers.
+#ifdef JS_METHODJIT
+ curr.mjitCode = compartment->sizeOfMjitCode();
+#endif
+ SizeOfCompartmentTypeInferenceData(cx, compartment,
+ &curr.typeInferenceMemory,
+ data->mallocSizeOf);
+ curr.shapesCompartmentTables =
+ SizeOfCompartmentShapeTable(compartment, data->mallocSizeOf);
+}
+
+static void
+ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
+{
+#ifdef JS_METHODJIT
+ size_t *n = static_cast<size_t *>(data);
+ *n += compartment->sizeOfMjitCode();
+#endif
+}
+
+static void
+ChunkCallback(JSContext *cx, void *vdata, gc::Chunk *chunk)
+{
+ // Nb: This function is only called for dirty chunks, which is why we
+ // increment gcHeapChunkDirtyDecommitted.
+ IterateData *data = static_cast<IterateData *>(vdata);
+ for (size_t i = 0; i < gc::ArenasPerChunk; i++)
+ if (chunk->decommittedArenas.get(i))
+ data->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
+}
+
+static void
+ArenaCallback(JSContext *cx, void *vdata, gc::Arena *arena,
+ JSGCTraceKind traceKind, size_t thingSize)
+{
+ IterateData *data = static_cast<IterateData *>(vdata);
+
+ data->currCompartmentStats->gcHeapArenaHeaders +=
+ sizeof(gc::ArenaHeader);
+ size_t allocationSpace = arena->thingsSpan(thingSize);
+ data->currCompartmentStats->gcHeapArenaPadding +=
+ gc::ArenaSize - allocationSpace - sizeof(gc::ArenaHeader);
+ // We don't call the callback on unused things. So we compute the
+ // unused space like this: arenaUnused = maxArenaUnused - arenaUsed.
+ // We do this by setting arenaUnused to maxArenaUnused here, and then
+ // subtracting thingSize for every used cell, in CellCallback().
+ data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
+}
+
+static void
+CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
+ size_t thingSize)
+{
+ IterateData *data = static_cast<IterateData *>(vdata);
+ CompartmentStats *curr = data->currCompartmentStats;
+ switch (traceKind) {
+ case JSTRACE_OBJECT:
+ {
+ JSObject *obj = static_cast<JSObject *>(thing);
+ if (obj->isFunction()) {
+ curr->gcHeapObjectsFunction += thingSize;
+ } else {
+ curr->gcHeapObjectsNonFunction += thingSize;
+ }
+ curr->objectSlots += obj->dynamicSlotSize(data->mallocSizeOf);
+ break;
+ }
+ case JSTRACE_STRING:
+ {
+ JSString *str = static_cast<JSString *>(thing);
+ curr->gcHeapStrings += thingSize;
+ curr->stringChars += str->charsHeapSize(data->mallocSizeOf);
+ break;
+ }
+ case JSTRACE_SHAPE:
+ {
+ Shape *shape = static_cast<Shape*>(thing);
+ if (shape->inDictionary()) {
+ curr->gcHeapShapesDict += thingSize;
+ curr->shapesExtraDictTables +=
+ shape->sizeOfPropertyTable(data->mallocSizeOf);
+ } else {
+ curr->gcHeapShapesTree += thingSize;
+ curr->shapesExtraTreeTables +=
+ shape->sizeOfPropertyTable(data->mallocSizeOf);
+ curr->shapesExtraTreeShapeKids +=
+ shape->sizeOfKids(data->mallocSizeOf);
+ }
+ break;
+ }
+ case JSTRACE_BASE_SHAPE:
+ {
+ curr->gcHeapShapesBase += thingSize;
+ break;
+ }
+ case JSTRACE_SCRIPT:
+ {
+ JSScript *script = static_cast<JSScript *>(thing);
+ curr->gcHeapScripts += thingSize;
+ curr->scriptData += script->dataSize(data->mallocSizeOf);
+#ifdef JS_METHODJIT
+ curr->mjitData += script->jitDataSize(data->mallocSizeOf);
+#endif
+ break;
+ }
+ case JSTRACE_TYPE_OBJECT:
+ {
+ types::TypeObject *obj = static_cast<types::TypeObject *>(thing);
+ curr->gcHeapTypeObjects += thingSize;
+ SizeOfObjectTypeInferenceData(obj, &curr->typeInferenceMemory,
+ data->mallocSizeOf);
+ break;
+ }
+ case JSTRACE_XML:
+ {
+ curr->gcHeapXML += thingSize;
+ break;
+ }
+ }
+ // Yes, this is a subtraction: see ArenaCallback() for details.
+ curr->gcHeapArenaUnused -= thingSize;
+}
+
+JS_PUBLIC_API(bool)
+CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
+{
+ JSContext *cx = JS_NewContext(rt, 0);
+ if (!cx)
+ return false;
+
+ {
+ JSAutoRequest ar(cx);
+
+ if (!data->compartmentStatsVector.reserve(rt->compartments.length()))
+ return false;
+
+ data->gcHeapChunkCleanDecommitted =
+ rt->gcChunkPool.countCleanDecommittedArenas(rt) *
+ gc::ArenaSize;
+ data->gcHeapChunkCleanUnused =
+ int64_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
+ gc::ChunkSize -
+ data->gcHeapChunkCleanDecommitted;
+ data->gcHeapChunkTotal =
+ int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
+ gc::ChunkSize;
+
+ IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
+ ArenaCallback, CellCallback);
+ IterateChunks(cx, data, ChunkCallback);
+
+ data->runtimeObject = data->mallocSizeOf(rt, sizeof(JSRuntime));
+
+ // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
+ // JSRuntime, and so counted when JSRuntime is counted.
+ data->runtimeAtomsTable =
+ rt->atomState.atoms.sizeOfExcludingThis(data->mallocSizeOf);
+
+ {
+#ifndef JS_THREADSAFE
+#error "This code assumes JS_THREADSAFE is defined"
+#endif
+
+ // Need the GC lock to call JS_ContextIteratorUnlocked() and to
+ // access rt->threads.
+ AutoLockGC lock(rt);
+
+ JSContext *acx, *iter = NULL;
+ while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL) {
+ data->runtimeContexts +=
+ acx->sizeOfIncludingThis(data->mallocSizeOf);
+ }
+
+ for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
+ JSThread *thread = r.front().value;
+ size_t normal, temporary, regexpCode, stackCommitted;
+ thread->sizeOfIncludingThis(data->mallocSizeOf,
+ &normal,
+ &temporary,
+ ®expCode,
+ &stackCommitted);
+
+ data->runtimeThreadsNormal += normal;
+ data->runtimeThreadsTemporary += temporary;
+ data->runtimeThreadsRegexpCode += regexpCode;
+ data->runtimeThreadsStackCommitted += stackCommitted;
+ }
+ }
+ }
+
+ JS_DestroyContextNoGC(cx);
+
+ // This is initialized to all bytes stored in used chunks, and then we
+ // subtract used space from it each time around the loop.
+ data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
+ data->gcHeapChunkCleanUnused -
+ data->gcHeapChunkCleanDecommitted -
+ data->gcHeapChunkDirtyDecommitted;
+
+ for (size_t index = 0;
+ index < data->compartmentStatsVector.length();
+ index++) {
+ CompartmentStats &stats = data->compartmentStatsVector[index];
+
+ int64_t used = stats.gcHeapArenaHeaders +
+ stats.gcHeapArenaPadding +
+ stats.gcHeapArenaUnused +
+ stats.gcHeapObjectsNonFunction +
+ stats.gcHeapObjectsFunction +
+ stats.gcHeapStrings +
+ stats.gcHeapShapesTree +
+ stats.gcHeapShapesDict +
+ stats.gcHeapShapesBase +
+ stats.gcHeapScripts +
+ stats.gcHeapTypeObjects +
+ stats.gcHeapXML;
+
+ data->gcHeapChunkDirtyUnused -= used;
+ data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
+ data->totalObjects += stats.gcHeapObjectsNonFunction +
+ stats.gcHeapObjectsFunction +
+ stats.objectSlots;
+ data->totalShapes += stats.gcHeapShapesTree +
+ stats.gcHeapShapesDict +
+ stats.gcHeapShapesBase +
+ stats.shapesExtraTreeTables +
+ stats.shapesExtraDictTables +
+ stats.shapesCompartmentTables;
+ data->totalScripts += stats.gcHeapScripts +
+ stats.scriptData;
+ data->totalStrings += stats.gcHeapStrings +
+ stats.stringChars;
+#ifdef JS_METHODJIT
+ data->totalMjit += stats.mjitCode +
+ stats.mjitData;
+#endif
+ data->totalTypeInference += stats.gcHeapTypeObjects +
+ stats.typeInferenceMemory.objects +
+ stats.typeInferenceMemory.scripts +
+ stats.typeInferenceMemory.tables;
+ data->totalAnalysisTemp += stats.typeInferenceMemory.temporary;
+ }
+
+ size_t numDirtyChunks = (data->gcHeapChunkTotal -
+ data->gcHeapChunkCleanUnused) /
+ gc::ChunkSize;
+ int64_t perChunkAdmin =
+ sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
+ data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
+ data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
+
+ // Why 10000x? 100x because it's a percentage, and another 100x
+ // because nsIMemoryReporter requires that for percentage amounts so
+ // they can be fractional.
+ data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
+ data->gcHeapChunkDirtyUnused +
+ data->gcHeapChunkCleanDecommitted +
+ data->gcHeapChunkDirtyDecommitted +
+ data->gcHeapArenaUnused) * 10000 /
+ data->gcHeapChunkTotal;
+
+ return true;
+}
+
+JS_PUBLIC_API(bool)
+GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
+ JSMallocSizeOfFun mallocSizeOf)
+{
+ JSContext *cx = JS_NewContext(rt, 0);
+ if (!cx)
+ return false;
+
+ // explicit/<compartment>/gc-heap/*
+ *amount = int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
+ gc::ChunkSize;
+
+ {
+ JSAutoRequest ar(cx);
+
+ // explicit/<compartment>/mjit-code
+ size_t n = 0;
+ IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
+ *amount += n;
+
+ {
+#ifndef JS_THREADSAFE
+#error "This code assumes JS_THREADSAFE is defined"
+#endif
+
+ // Need the GC lock to call JS_ContextIteratorUnlocked() and to
+ // access rt->threads.
+ AutoLockGC lock(rt);
+
+ // explicit/runtime/threads/regexp-code
+ // explicit/runtime/threads/stack-committed
+ for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
+ JSThread *thread = r.front().value;
+ size_t regexpCode, stackCommitted;
+ thread->sizeOfIncludingThis(mallocSizeOf,
+ NULL,
+ NULL,
+ ®expCode,
+ &stackCommitted);
+
+ *amount += regexpCode;
+ *amount += stackCommitted;
+ }
+ }
+ }
+
+ JS_DestroyContextNoGC(cx);
+
+ return true;
+}
+
+} // namespace JS
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -151,22 +151,16 @@ JSCompartment::sizeOfMjitCode() const
return 0;
size_t method, regexp, unused;
jaegerCompartment_->execAlloc()->sizeOfCode(&method, ®exp, &unused);
JS_ASSERT(regexp == 0);
return method + unused;
}
-JS_PUBLIC_API(size_t)
-JS::SizeOfCompartmentMjitCode(const JSCompartment *c)
-{
- return c->sizeOfMjitCode();
-}
-
#endif
bool
JSCompartment::wrap(JSContext *cx, Value *vp)
{
JS_ASSERT(cx->compartment == this);
uintN flags = 0;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -6594,22 +6594,16 @@ js::HandleNonGenericMethodClassMismatch(
if (thisObj.isProxy())
return Proxy::nativeCall(cx, &thisObj, clasp, native, args);
}
ReportIncompatibleMethod(cx, args, clasp);
return false;
}
-JS_PUBLIC_API(size_t)
-JS::SizeOfObjectDynamicSlots(JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
-{
- return obj->dynamicSlotSize(mallocSizeOf);
-}
-
#ifdef DEBUG
/*
* Routines to print out values during debugging. These are FRIEND_API to help
* the debugger find them and to support temporarily hacking js_Dump* calls
* into other code.
*/
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -1517,26 +1517,8 @@ JSCompartment::sweepInitialShapeTable(JS
if (initialShapes.initialized()) {
for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
const InitialShapeEntry &entry = e.front();
if (!entry.shape->isMarked() || (entry.proto && !entry.proto->isMarked()))
e.removeFront();
}
}
}
-
-JS_PUBLIC_API(bool)
-JS::IsShapeInDictionary(const void *shape)
-{
- return static_cast<const Shape*>(shape)->inDictionary();
-}
-
-JS_PUBLIC_API(size_t)
-JS::SizeOfShapePropertyTable(const void *shape, JSMallocSizeOfFun mallocSizeOf)
-{
- return static_cast<const Shape*>(shape)->sizeOfPropertyTable(mallocSizeOf);
-}
-
-JS_PUBLIC_API(size_t)
-JS::SizeOfShapeKids(const void *shape, JSMallocSizeOfFun mallocSizeOf)
-{
- return static_cast<const Shape*>(shape)->sizeOfKids(mallocSizeOf);
-}
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1309,22 +1309,16 @@ JSScript::dataSize(JSMallocSizeOfFun mal
#if JS_SCRIPT_INLINE_DATA_LIMIT
if (data == inlineData)
return 0;
#endif
return mallocSizeOf(data, dataSize());
}
-JS_PUBLIC_API(size_t)
-JS::SizeOfScriptData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
-{
- return script->dataSize(mallocSizeOf);
-}
-
/*
* Nb: srcnotes are variable-length. This function computes the number of
* srcnote *slots*, which may be greater than the number of srcnotes.
*/
uint32_t
JSScript::numNotes()
{
jssrcnote *sn;
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -1292,22 +1292,16 @@ JSScript::jitDataSize(JSMallocSizeOfFun
size_t n = 0;
if (jitNormal)
n += jitNormal->scriptDataSize(mallocSizeOf);
if (jitCtor)
n += jitCtor->scriptDataSize(mallocSizeOf);
return n;
}
-JS_PUBLIC_API(size_t)
-JS::SizeOfScriptJitData(JSScript *script, JSMallocSizeOfFun mallocSizeOf)
-{
- return script->jitDataSize(mallocSizeOf);
-}
-
/* Please keep in sync with Compiler::finishThisUp! */
size_t
mjit::JITScript::scriptDataSize(JSMallocSizeOfFun mallocSizeOf)
{
size_t computedSize =
sizeof(JITScript) +
sizeof(NativeMapEntry) * nNmapPairs +
sizeof(InlineFrame) * nInlineFrames +
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -72,18 +72,16 @@
while ((acx = JS_ContextIterator(cx->runtime, &iter))) {
if (!acx->hasRunOption(JSOPTION_UNROOTED_GLOBAL))
JS_ToggleOptions(acx, JSOPTION_UNROOTED_GLOBAL);
JS_LOCK_GC, JS_UNLOCK_GC
js_NextActiveContext, js::TriggerOperationCallback
-JSString::charsHeapSize
-CollectCompartmentStatsForRuntime
mWatchdogWakeup = JS_NEW_CONDVAR(mJSRuntime->gcLock);
mJSRuntime->setActivityCallback(ActivityCallback, this);
#endif
using namespace mozilla;
using namespace mozilla::xpconnect::memory;
/***************************************************************************/
@@ -1249,17 +1247,19 @@ XPCJSRuntime::~XPCJSRuntime()
#ifdef DEBUG_shaver_off
fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
#endif
}
XPCPerThreadData::ShutDown();
}
-static void*
+namespace xpc {
+
+void*
GetCompartmentName(JSContext *cx, JSCompartment *c)
{
nsCString* name = new nsCString();
if (js::IsAtomsCompartmentFor(cx, c)) {
name->AssignLiteral("atoms");
} else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
if (principals->codebase) {
name->Assign(principals->codebase);
@@ -1290,157 +1290,27 @@ GetCompartmentName(JSContext *cx, JSComp
name->AssignLiteral("null-codebase");
}
} else {
name->AssignLiteral("null-principal");
}
return name;
}
-static void
+void
DestroyCompartmentName(void *string)
{
delete static_cast<nsCString*>(string);
}
-namespace {
-
NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsMallocSizeOf, "js")
-void
-CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
-{
- // Append a new CompartmentStats to the vector.
- IterateData *data = static_cast<IterateData *>(vdata);
- JS::CompartmentStats *curr =
- data->compartmentStatsVector.AppendElement();
- curr->init(GetCompartmentName(cx, compartment), DestroyCompartmentName);
- data->currCompartmentStats = curr;
-
- // Get the compartment-level numbers.
-#ifdef JS_METHODJIT
- curr->mjitCode = JS::SizeOfCompartmentMjitCode(compartment);
-#endif
- JS::SizeOfCompartmentTypeInferenceData(cx, compartment,
- &curr->typeInferenceMemory,
- JsMallocSizeOf);
- curr->shapesCompartmentTables =
- JS::SizeOfCompartmentShapeTable(compartment, JsMallocSizeOf);
-}
-
-void
-ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
-{
- size_t *n = static_cast<size_t *>(data);
-#ifdef JS_METHODJIT
- *n += JS::SizeOfCompartmentMjitCode(compartment);
-#endif
-}
-
-void
-ChunkCallback(JSContext *cx, void *vdata, js::gc::Chunk *chunk)
-{
- // Nb: This function is only called for dirty chunks, which is why we
- // increment gcHeapChunkDirtyDecommitted.
- IterateData *data = static_cast<IterateData *>(vdata);
- for (uint32_t i = 0; i < js::gc::ArenasPerChunk; i++)
- if (chunk->decommittedArenas.get(i))
- data->gcHeapChunkDirtyDecommitted += js::gc::ArenaSize;
-}
-
-void
-ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
- JSGCTraceKind traceKind, size_t thingSize)
-{
- IterateData *data = static_cast<IterateData *>(vdata);
-
- data->currCompartmentStats->gcHeapArenaHeaders +=
- sizeof(js::gc::ArenaHeader);
- size_t allocationSpace = arena->thingsSpan(thingSize);
- data->currCompartmentStats->gcHeapArenaPadding +=
- js::gc::ArenaSize - allocationSpace - sizeof(js::gc::ArenaHeader);
- // We don't call the callback on unused things. So we compute the
- // unused space like this: arenaUnused = maxArenaUnused - arenaUsed.
- // We do this by setting arenaUnused to maxArenaUnused here, and then
- // subtracting thingSize for every used cell, in CellCallback().
- data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
-}
+} // namespace xpc
-void
-CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
- size_t thingSize)
-{
- IterateData *data = static_cast<IterateData *>(vdata);
- JS::CompartmentStats *curr = data->currCompartmentStats;
- switch (traceKind) {
- case JSTRACE_OBJECT:
- {
- JSObject *obj = static_cast<JSObject *>(thing);
- if (JS_ObjectIsFunction(cx, obj)) {
- curr->gcHeapObjectsFunction += thingSize;
- } else {
- curr->gcHeapObjectsNonFunction += thingSize;
- }
- curr->objectSlots += JS::SizeOfObjectDynamicSlots(obj, JsMallocSizeOf);
- break;
- }
- case JSTRACE_STRING:
- {
- JSString *str = static_cast<JSString *>(thing);
- curr->gcHeapStrings += thingSize;
- curr->stringChars += str->charsHeapSize(JsMallocSizeOf);
- break;
- }
- case JSTRACE_SHAPE:
- {
- if (JS::IsShapeInDictionary(thing)) {
- curr->gcHeapShapesDict += thingSize;
- curr->shapesExtraDictTables +=
- JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
- } else {
- curr->gcHeapShapesTree += thingSize;
- curr->shapesExtraTreeTables +=
- JS::SizeOfShapePropertyTable(thing, JsMallocSizeOf);
- curr->shapesExtraTreeShapeKids +=
- JS::SizeOfShapeKids(thing, JsMallocSizeOf);
- }
- break;
- }
- case JSTRACE_BASE_SHAPE:
- {
- curr->gcHeapShapesBase += thingSize;
- break;
- }
- case JSTRACE_SCRIPT:
- {
- JSScript *script = static_cast<JSScript *>(thing);
- curr->gcHeapScripts += thingSize;
- curr->scriptData += JS::SizeOfScriptData(script, JsMallocSizeOf);
-#ifdef JS_METHODJIT
- curr->mjitData += JS::SizeOfScriptJitData(script, JsMallocSizeOf);
-#endif
- break;
- }
- case JSTRACE_TYPE_OBJECT:
- {
- js::types::TypeObject *obj = static_cast<js::types::TypeObject *>(thing);
- curr->gcHeapTypeObjects += thingSize;
- JS::SizeOfObjectTypeInferenceData(obj, &curr->typeInferenceMemory,
- JsMallocSizeOf);
- break;
- }
- case JSTRACE_XML:
- {
- curr->gcHeapXML += thingSize;
- break;
- }
- }
- // Yes, this is a subtraction: see ArenaCallback() for details.
- curr->gcHeapArenaUnused -= thingSize;
-}
+namespace {
template <int N>
inline void
ReportMemory(const nsACString &path, PRInt32 kind, PRInt32 units,
PRInt64 amount, const char (&desc)[N],
nsIMemoryMultiReporterCallback *callback, nsISupports *closure)
{
callback->Callback(NS_LITERAL_CSTRING(""), path, kind, units, amount,
@@ -1572,219 +1442,16 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJS
"and 'js-compartments-system' might not match the number of "
"compartments listed under 'js' if a garbage collection occurs at an "
"inopportune time, but such cases should be rare.")
namespace mozilla {
namespace xpconnect {
namespace memory {
-JSBool
-CollectCompartmentStatsForRuntime(JSRuntime *rt, void *vdata)
-{
- IterateData *data = (IterateData *)vdata;
- JSContext *cx = JS_NewContext(rt, 0);
- if (!cx) {
- NS_ERROR("couldn't create context for memory tracing");
- return false;
- }
-
- {
- JSAutoRequest ar(cx);
-
- data->compartmentStatsVector.SetCapacity(rt->compartments.length());
-
- data->gcHeapChunkCleanDecommitted =
- rt->gcChunkPool.countCleanDecommittedArenas(rt) *
- js::gc::ArenaSize;
- data->gcHeapChunkCleanUnused =
- PRInt64(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
- js::gc::ChunkSize -
- data->gcHeapChunkCleanDecommitted;
- data->gcHeapChunkTotal =
- PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
- js::gc::ChunkSize;
-
- js::IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
- ArenaCallback, CellCallback);
- js::IterateChunks(cx, data, ChunkCallback);
-
- data->runtimeObject = JsMallocSizeOf(rt, sizeof(JSRuntime));
-
- // Nb: we use sizeOfExcludingThis() because atomState.atoms is within
- // JSRuntime, and so counted when JSRuntime is counted.
- data->runtimeAtomsTable =
- rt->atomState.atoms.sizeOfExcludingThis(JsMallocSizeOf);
-
- {
- #ifndef JS_THREADSAFE
- #error "This code assumes JS_THREADSAFE is defined"
- #endif
-
- // Need the GC lock to call JS_ContextIteratorUnlocked() and to
- // access rt->threads.
- js::AutoLockGC lock(rt);
-
- JSContext *acx, *iter = NULL;
- while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL) {
- data->runtimeContexts +=
- acx->sizeOfIncludingThis(JsMallocSizeOf);
- }
-
- for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
- JSThread *thread = r.front().value;
- size_t normal, temporary, regexpCode, stackCommitted;
- thread->sizeOfIncludingThis(JsMallocSizeOf,
- &normal,
- &temporary,
- ®expCode,
- &stackCommitted);
-
- data->runtimeThreadsNormal += normal;
- data->runtimeThreadsTemporary += temporary;
- data->runtimeThreadsRegexpCode += regexpCode;
- data->runtimeThreadsStackCommitted += stackCommitted;
- }
- }
-
- XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
- data->xpconnect +=
- xpcrt->SizeOfIncludingThis(JsMallocSizeOf);
- data->xpconnect +=
- XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
- }
-
- JS_DestroyContextNoGC(cx);
-
- // This is initialized to all bytes stored in used chunks, and then we
- // subtract used space from it each time around the loop.
- data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
- data->gcHeapChunkCleanUnused -
- data->gcHeapChunkCleanDecommitted -
- data->gcHeapChunkDirtyDecommitted;
-
- for (PRUint32 index = 0;
- index < data->compartmentStatsVector.Length();
- index++) {
- JS::CompartmentStats &stats = data->compartmentStatsVector[index];
-
- PRInt64 used = stats.gcHeapArenaHeaders +
- stats.gcHeapArenaPadding +
- stats.gcHeapArenaUnused +
- stats.gcHeapObjectsNonFunction +
- stats.gcHeapObjectsFunction +
- stats.gcHeapStrings +
- stats.gcHeapShapesTree +
- stats.gcHeapShapesDict +
- stats.gcHeapShapesBase +
- stats.gcHeapScripts +
- stats.gcHeapTypeObjects +
- stats.gcHeapXML;
-
- data->gcHeapChunkDirtyUnused -= used;
- data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
- data->totalObjects += stats.gcHeapObjectsNonFunction +
- stats.gcHeapObjectsFunction +
- stats.objectSlots;
- data->totalShapes += stats.gcHeapShapesTree +
- stats.gcHeapShapesDict +
- stats.gcHeapShapesBase +
- stats.shapesExtraTreeTables +
- stats.shapesExtraDictTables +
- stats.shapesCompartmentTables;
- data->totalScripts += stats.gcHeapScripts +
- stats.scriptData;
- data->totalStrings += stats.gcHeapStrings +
- stats.stringChars;
-#ifdef JS_METHODJIT
- data->totalMjit += stats.mjitCode +
- stats.mjitData;
-#endif
- data->totalTypeInference += stats.gcHeapTypeObjects +
- stats.typeInferenceMemory.objects +
- stats.typeInferenceMemory.scripts +
- stats.typeInferenceMemory.tables;
- data->totalAnalysisTemp += stats.typeInferenceMemory.temporary;
- }
-
- size_t numDirtyChunks = (data->gcHeapChunkTotal -
- data->gcHeapChunkCleanUnused) /
- js::gc::ChunkSize;
- PRInt64 perChunkAdmin =
- sizeof(js::gc::Chunk) - (sizeof(js::gc::Arena) * js::gc::ArenasPerChunk);
- data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
- data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
-
- // Why 10000x? 100x because it's a percentage, and another 100x
- // because nsIMemoryReporter requires that for percentage amounts so
- // they can be fractional.
- data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
- data->gcHeapChunkDirtyUnused +
- data->gcHeapChunkCleanDecommitted +
- data->gcHeapChunkDirtyDecommitted +
- data->gcHeapArenaUnused) * 10000 /
- data->gcHeapChunkTotal;
-
- return true;
-}
-
-JSBool
-GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data)
-{
- PRInt64 *amount = (PRInt64 *)data;
-
- JSContext *cx = JS_NewContext(rt, 0);
- if (!cx) {
- NS_ERROR("couldn't create context for memory tracing");
- return NS_ERROR_ABORT;
- }
-
- // explicit/<compartment>/gc-heap/*
- *amount = PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
- js::gc::ChunkSize;
-
- {
- JSAutoRequest ar(cx);
-
- // explicit/<compartment>/mjit-code
- size_t n = 0;
- js::IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
- *amount += n;
-
- {
- #ifndef JS_THREADSAFE
- #error "This code assumes JS_THREADSAFE is defined"
- #endif
-
- // Need the GC lock to call JS_ContextIteratorUnlocked() and to
- // access rt->threads.
- js::AutoLockGC lock(rt);
-
- // explicit/runtime/threads/regexp-code
- // explicit/runtime/threads/stack-committed
- for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
- JSThread *thread = r.front().value;
- size_t regexpCode, stackCommitted;
- thread->sizeOfIncludingThis(JsMallocSizeOf,
- NULL,
- NULL,
- ®expCode,
- &stackCommitted);
-
- *amount += regexpCode;
- *amount += stackCommitted;
- }
- }
- }
-
- JS_DestroyContextNoGC(cx);
-
- return true;
-}
-
#define SLOP_BYTES_STRING \
" The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
static PRInt64
ReportCompartmentStats(const JS::CompartmentStats &stats,
const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
@@ -1980,23 +1647,23 @@ ReportCompartmentStats(const JS::Compart
"Memory used during type inference and compilation to hold transient "
"analysis information. Cleared on GC.",
callback, closure);
return gcTotal;
}
void
-ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
+ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
PRInt64 gcTotal = 0;
- for (PRUint32 index = 0;
- index < data.compartmentStatsVector.Length();
+ for (size_t index = 0;
+ index < data.compartmentStatsVector.length();
index++) {
gcTotal += ReportCompartmentStats(data.compartmentStatsVector[index], pathPrefix,
callback, closure);
}
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
nsIMemoryReporter::KIND_HEAP, data.runtimeObject,
"Memory used by the JSRuntime object." SLOP_BYTES_STRING,
@@ -2034,21 +1701,16 @@ ReportJSRuntimeStats(const IterateData &
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/threads/stack-committed"),
nsIMemoryReporter::KIND_NONHEAP, data.runtimeThreadsStackCommitted,
"Memory used for the thread stacks. This is the committed portions "
"of the stacks; any uncommitted portions are not measured because they "
"hardly cost anything.",
callback, closure);
- ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
- nsIMemoryReporter::KIND_HEAP, data.xpconnect,
- "Memory used by XPConnect." SLOP_BYTES_STRING,
- callback, closure);
-
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
&gcTotal, data.gcHeapChunkDirtyUnused,
"Memory on the garbage-collected JavaScript heap, within chunks with at "
"least one allocated GC thing, that could be holding useful data but "
"currently isn't. Memory here is mutually exclusive with memory reported"
"under 'explicit/js/gc-heap-decommitted'.",
callback, closure);
@@ -2089,32 +1751,45 @@ ReportJSRuntimeStats(const IterateData &
class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
{
public:
NS_DECL_ISUPPORTS
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
- JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
+ XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
// In the first step we get all the stats and stash them in a local
// data structure. In the second step we pass all the stashed stats to
// the callback. Separating these steps is important because the
// callback may be a JS function, and executing JS while getting these
// stats seems like a bad idea.
- IterateData data;
- if (!CollectCompartmentStatsForRuntime(rt, &data))
+ JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
+ xpc::DestroyCompartmentName);
+ if (!JS::CollectCompartmentStatsForRuntime(xpcrt->GetJSRuntime(), &data))
return NS_ERROR_FAILURE;
+ uint64_t xpconnect;
+ {
+ xpconnect =
+ xpcrt->SizeOfIncludingThis(xpc::JsMallocSizeOf) +
+ XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(xpc::JsMallocSizeOf);
+ }
+
NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
// This is the second step (see above).
ReportJSRuntimeStats(data, pathPrefix, callback, closure);
+ ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
+ nsIMemoryReporter::KIND_HEAP, xpconnect,
+ "Memory used by XPConnect." SLOP_BYTES_STRING,
+ callback, closure);
+
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-dirty-unused"),
nsIMemoryReporter::KIND_OTHER,
data.gcHeapChunkDirtyUnused,
"The same as 'explicit/js/gc-heap-chunk-dirty-unused'. Shown here for "
"easy comparison with other 'js-gc' reporters.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-clean-unused"),
@@ -2198,17 +1873,17 @@ public:
return NS_OK;
}
NS_IMETHOD
GetExplicitNonHeap(PRInt64 *n)
{
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
- if (!GetExplicitNonHeapForRuntime(rt, n))
+ if (!JS::GetExplicitNonHeapForRuntime(rt, n, xpc::JsMallocSizeOf))
return NS_ERROR_FAILURE;
return NS_OK;
}
};
NS_IMPL_THREADSAFE_ISUPPORTS1(XPConnectJSCompartmentsMultiReporter
, nsIMemoryMultiReporter
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -202,92 +202,30 @@ bool Base64Decode(JSContext *cx, JS::Val
/**
* Convert an nsString to jsval, returning true on success.
* Note, the ownership of the string buffer may be moved from str to rval.
* If that happens, str will point to an empty string after this call.
*/
bool StringToJsval(JSContext *cx, nsString &str, JS::Value *rval);
+void *GetCompartmentName(JSContext *cx, JSCompartment *c);
+void DestroyCompartmentName(void *string);
+size_t JsMallocSizeOf(const void *ptr, size_t computedSize);
+
} // namespace xpc
class nsIMemoryMultiReporterCallback;
namespace mozilla {
namespace xpconnect {
namespace memory {
-struct IterateData
-{
- IterateData()
- : runtimeObject(0),
- runtimeAtomsTable(0),
- runtimeContexts(0),
- runtimeThreadsNormal(0),
- runtimeThreadsTemporary(0),
- runtimeThreadsRegexpCode(0),
- runtimeThreadsStackCommitted(0),
- xpconnect(0),
- gcHeapChunkTotal(0),
- gcHeapChunkCleanUnused(0),
- gcHeapChunkDirtyUnused(0),
- gcHeapChunkCleanDecommitted(0),
- gcHeapChunkDirtyDecommitted(0),
- gcHeapArenaUnused(0),
- gcHeapChunkAdmin(0),
- gcHeapUnusedPercentage(0),
- totalObjects(0),
- totalShapes(0),
- totalScripts(0),
- totalStrings(0),
-#ifdef JS_METHODJIT
- totalMjit(0),
-#endif
- totalTypeInference(0),
- totalAnalysisTemp(0),
- compartmentStatsVector(),
- currCompartmentStats(NULL) { }
-
- PRInt64 runtimeObject;
- PRInt64 runtimeAtomsTable;
- PRInt64 runtimeContexts;
- PRInt64 runtimeThreadsNormal;
- PRInt64 runtimeThreadsTemporary;
- PRInt64 runtimeThreadsRegexpCode;
- PRInt64 runtimeThreadsStackCommitted;
- PRInt64 xpconnect;
- PRInt64 gcHeapChunkTotal;
- PRInt64 gcHeapChunkCleanUnused;
- PRInt64 gcHeapChunkDirtyUnused;
- PRInt64 gcHeapChunkCleanDecommitted;
- PRInt64 gcHeapChunkDirtyDecommitted;
- PRInt64 gcHeapArenaUnused;
- PRInt64 gcHeapChunkAdmin;
- PRInt64 gcHeapUnusedPercentage;
- PRInt64 totalObjects;
- PRInt64 totalShapes;
- PRInt64 totalScripts;
- PRInt64 totalStrings;
-#ifdef JS_METHODJIT
- PRInt64 totalMjit;
-#endif
- PRInt64 totalTypeInference;
- PRInt64 totalAnalysisTemp;
-
- nsTArray<JS::CompartmentStats> compartmentStatsVector;
- JS::CompartmentStats *currCompartmentStats;
-};
-
-JSBool
-CollectCompartmentStatsForRuntime(JSRuntime *rt, void *data);
-JSBool
-GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data);
-
void
-ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
+ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure);
} // namespace memory
} // namespace xpconnect
namespace dom {
namespace binding {