diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index 352556e5c072..c5eb8d6a0041 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -192,6 +192,7 @@ struct ClassInfo { MACRO(Objects, NonHeap, objectsNonHeapElementsNormal) \ MACRO(Objects, NonHeap, objectsNonHeapElementsShared) \ MACRO(Objects, NonHeap, objectsNonHeapElementsWasm) \ + MACRO(Objects, NonHeap, objectsNonHeapElementsWasmShared) \ MACRO(Objects, NonHeap, objectsNonHeapCodeWasm) ClassInfo() = default; @@ -225,8 +226,6 @@ struct ClassInfo { FOR_EACH_SIZE(DECL_SIZE_ZERO); - size_t wasmGuardPages = 0; - #undef FOR_EACH_SIZE }; @@ -512,6 +511,7 @@ struct RuntimeSizes { MACRO(_, MallocHeap, scriptData) \ MACRO(_, MallocHeap, tracelogger) \ MACRO(_, MallocHeap, wasmRuntime) \ + MACRO(_, Ignore, wasmGuardPages) \ MACRO(_, MallocHeap, jitLazyLink) RuntimeSizes() { allScriptSources.emplace(); } diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 84ee573d0872..088e76996565 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -1537,7 +1537,8 @@ ArrayBufferObject::extractStructuredCloneContents( /* static */ void ArrayBufferObject::addSizeOfExcludingThis( - JSObject* obj, mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info) { + JSObject* obj, mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info, + JS::RuntimeSizes* runtimeSizes) { auto& buffer = obj->as(); switch (buffer.bufferKind()) { case INLINE_DATA: @@ -1568,9 +1569,14 @@ void ArrayBufferObject::addSizeOfExcludingThis( info->objectsNonHeapElementsNormal += buffer.byteLength(); break; case WASM: - info->objectsNonHeapElementsWasm += buffer.byteLength(); - MOZ_ASSERT(buffer.wasmMappedSize() >= buffer.byteLength()); - info->wasmGuardPages += buffer.wasmMappedSize() - buffer.byteLength(); + if (!buffer.isDetached()) { + info->objectsNonHeapElementsWasm += buffer.byteLength(); + if (runtimeSizes) { + MOZ_ASSERT(buffer.wasmMappedSize() >= buffer.byteLength()); + runtimeSizes->wasmGuardPages += + buffer.wasmMappedSize() - buffer.byteLength(); + } + } break; case BAD1: MOZ_CRASH("bad bufferKind()"); diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 935a914fcf03..cfb5bfee5247 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -384,7 +384,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared { static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf, - JS::ClassInfo* info); + JS::ClassInfo* info, + JS::RuntimeSizes* runtimeSizes); // ArrayBufferObjects (strongly) store the first view added to them, while // later views are (weakly) stored in the compartment's InnerViewTable diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp index cbf5001d3ed7..affa53727a80 100644 --- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -3522,7 +3522,8 @@ js::gc::AllocKind JSObject::allocKindForTenure( } void JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, - JS::ClassInfo* info) { + JS::ClassInfo* info, + JS::RuntimeSizes* runtimeSizes) { if (is() && as().hasDynamicSlots()) { info->objectsMallocHeapSlots += mallocSizeOf(as().getSlotsHeader()); @@ -3563,9 +3564,10 @@ void JSObject::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, info->objectsMallocHeapMisc += as().sizeOfMisc(mallocSizeOf); } else if (is()) { - ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info); + ArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info, + runtimeSizes); } else if (is()) { - SharedArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info); + SharedArrayBufferObject::addSizeOfExcludingThis(this, mallocSizeOf, info, runtimeSizes); } else if (is()) { as().addSizeOfData(mallocSizeOf, info); } else if (is()) { @@ -3617,7 +3619,7 @@ JS::ubi::Node::Size JS::ubi::Concrete::size( } JS::ClassInfo info; - obj.addSizeOfExcludingThis(mallocSizeOf, &info); + obj.addSizeOfExcludingThis(mallocSizeOf, &info, nullptr); return obj.tenuredSizeOfThis() + info.sizeOfAllThings(); } diff --git a/js/src/vm/JSObject.h b/js/src/vm/JSObject.h index 4a93d6c69c9d..9f8077ab910c 100644 --- a/js/src/vm/JSObject.h +++ b/js/src/vm/JSObject.h @@ -299,7 +299,8 @@ class JSObject } void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, - JS::ClassInfo* info); + JS::ClassInfo* info, + JS::RuntimeSizes* runtimeSizes); // We can only use addSizeOfExcludingThis on tenured objects: it assumes it // can apply mallocSizeOf to bits and pieces of the object, whereas objects diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index a0b4f70fd5fd..941f5d60fe37 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -340,7 +340,8 @@ static void StatsCellCallback(JSRuntime* rt, void* data, JS::GCCellPtr cellptr, info.objectsGCHeap += Nursery::nurseryCellHeaderSize(); } - obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info); + obj->addSizeOfExcludingThis(rtStats->mallocSizeOf_, &info, + &rtStats->runtime); // These classes require special handling due to shared resources which // we must be careful not to report twice. diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index 2b4e91ea6a63..d46f4e576621 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -347,7 +347,8 @@ void SharedArrayBufferObject::Finalize(JSFreeOp* fop, JSObject* obj) { /* static */ void SharedArrayBufferObject::addSizeOfExcludingThis( - JSObject* obj, mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info) { + JSObject* obj, mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info, + JS::RuntimeSizes* runtimeSizes) { // Divide the buffer size by the refcount to get the fraction of the buffer // owned by this thread. It's conceivable that the refcount might change in // the middle of memory reporting, in which case the amount reported for @@ -355,8 +356,17 @@ void SharedArrayBufferObject::addSizeOfExcludingThis( // the refcount goes down). But that's unlikely and hard to avoid, so we // just live with the risk. const SharedArrayBufferObject& buf = obj->as(); - info->objectsNonHeapElementsShared += - buf.byteLength() / buf.rawBufferObject()->refcount(); + size_t owned = buf.byteLength() / buf.rawBufferObject()->refcount(); + if (buf.isWasm()) { + info->objectsNonHeapElementsWasmShared += owned; + if (runtimeSizes) { + size_t ownedGuardPages = (buf.wasmMappedSize() - buf.byteLength()) / + buf.rawBufferObject()->refcount(); + runtimeSizes->wasmGuardPages += ownedGuardPages; + } + } else { + info->objectsNonHeapElementsShared += owned; + } } /* static */ diff --git a/js/src/vm/SharedArrayObject.h b/js/src/vm/SharedArrayObject.h index b1889f154f42..483d63e67b22 100644 --- a/js/src/vm/SharedArrayObject.h +++ b/js/src/vm/SharedArrayObject.h @@ -227,7 +227,8 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared { static void addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSizeOf mallocSizeOf, - JS::ClassInfo* info); + JS::ClassInfo* info, + JS::RuntimeSizes* runtimeSizes); static void copyData(Handle toBuffer, size_t toIndex, diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index f6594e68ea23..63529d2fbf92 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -1732,22 +1732,21 @@ static void ReportClassStats(const ClassInfo& classInfo, const nsACString& path, "wasm/asm.js array buffer elements allocated outside both the " "malloc heap and the GC heap."); } + if (classInfo.objectsNonHeapElementsWasmShared > 0) { + REPORT_BYTES( + path + "objects/non-heap/elements/wasm-shared"_ns, KIND_NONHEAP, + classInfo.objectsNonHeapElementsWasmShared, + "wasm/asm.js array buffer elements allocated outside both the " + "malloc heap and the GC heap. These elements are shared between " + "one or more runtimes; the reported size is divided by the " + "buffer's refcount."); + } if (classInfo.objectsNonHeapCodeWasm > 0) { REPORT_BYTES(path + "objects/non-heap/code/wasm"_ns, KIND_NONHEAP, classInfo.objectsNonHeapCodeWasm, "AOT-compiled wasm/asm.js code."); } - - // Although wasm guard pages aren't committed in memory they can be very - // large and contribute greatly to vsize and so are worth reporting. - if (classInfo.wasmGuardPages > 0) { - REPORT_BYTES( - "wasm-guard-pages"_ns, KIND_OTHER, classInfo.wasmGuardPages, - "Guard pages mapped after the end of wasm memories, reserved for " - "optimization tricks, but not committed and thus never contributing" - " to RSS, only vsize."); - } } static void ReportRealmStats(const JS::RealmStats& realmStats, @@ -2330,6 +2329,16 @@ void JSReporter::CollectReports(WindowPaths* windowPaths, REPORT_BYTES("wasm-runtime"_ns, KIND_OTHER, rtStats.runtime.wasmRuntime, "The memory used for wasm runtime bookkeeping."); + // Although wasm guard pages aren't committed in memory they can be very + // large and contribute greatly to vsize and so are worth reporting. + if (rtStats.runtime.wasmGuardPages > 0) { + REPORT_BYTES( + "wasm-guard-pages"_ns, KIND_OTHER, rtStats.runtime.wasmGuardPages, + "Guard pages mapped after the end of wasm memories, reserved for " + "optimization tricks, but not committed and thus never contributing" + " to RSS, only vsize."); + } + // Report the numbers for memory outside of realms. REPORT_BYTES("js-main-runtime/gc-heap/unused-chunks"_ns, KIND_OTHER,