tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 4c2e113134d42e178451726a11c1d789ac937813
parent c5c8110cd319bfa6da73e0b02de3c34588c2514a
Author: Jon Coppeard <jcoppeard@mozilla.com>
Date:   Mon,  6 Oct 2025 09:51:10 +0000

Bug 1978645 - Part 1: Use buffer allocator for wasm struct outline data r=jseward

Differential Revision: https://phabricator.services.mozilla.com/D265783

Diffstat:
Mjs/src/wasm/WasmGcObject-inl.h | 51++++++++++++++++++++++-----------------------------
Mjs/src/wasm/WasmGcObject.cpp | 47++++++++++++++++-------------------------------
2 files changed, 38 insertions(+), 60 deletions(-)

diff --git a/js/src/wasm/WasmGcObject-inl.h b/js/src/wasm/WasmGcObject-inl.h @@ -20,6 +20,19 @@ //========================================================================= // WasmStructObject inlineable allocation methods +// Maximum size of trailer block to allocate directly in the nursery. +// +// For objects that die in the nursery, direct nursery allocation is faster and +// is better for cache locality. For objects that survive, direct nursery +// allocation incurs the overhead of copying the data. This parameter should be +// chosen to balance these based on the expected allocation sizes and tenuring +// rates in workloads we care about. +// +// This is set to a lower value than the default (Nursery::MaxNurseryBufferSize) +// because we tend to get higher tenuring rates in Wasm GC benchmarks. +static constexpr size_t MaxNurseryTrailerSize = 256; +static_assert(MaxNurseryTrailerSize < js::gc::ChunkSize); + namespace js { /* static */ @@ -94,25 +107,19 @@ MOZ_ALWAYS_INLINE WasmStructObject* WasmStructObject::createStructOOL( MOZ_ASSERT(inlineBytes == WasmStructObject_MaxInlineBytes); MOZ_ASSERT(outlineBytes > 0); - // Allocate the outline data area before allocating the object so that we can - // infallibly initialize the outline data area. - Nursery& nursery = cx->nursery(); - PointerAndUint7 outlineData = - nursery.mallocedBlockCache().alloc(outlineBytes); - if (MOZ_UNLIKELY(!outlineData.pointer())) { - ReportOutOfMemory(cx); - return nullptr; - } - // See corresponding comment in WasmArrayObject::createArray. Rooted<WasmStructObject*> structObj(cx); structObj = (WasmStructObject*)cx->newCell<WasmGcObject>( typeDefData->allocKind, initialHeap, typeDefData->clasp, allocSite); if (MOZ_UNLIKELY(!structObj)) { ReportOutOfMemory(cx); - if (outlineData.pointer()) { - nursery.mallocedBlockCache().free(outlineData); - } + return nullptr; + } + + uint8_t* outlineData = AllocateCellBuffer<uint8_t>( + cx, structObj, outlineBytes, MaxNurseryTrailerSize); + if (MOZ_UNLIKELY(!outlineData)) { + structObj->outlineData_ = nullptr; return nullptr; } @@ -121,24 +128,10 @@ MOZ_ALWAYS_INLINE WasmStructObject* WasmStructObject::createStructOOL( structObj->superTypeVector_ = typeDefData->superTypeVector; // Initialize the outline data fields - structObj->outlineData_ = (uint8_t*)outlineData.pointer(); + structObj->outlineData_ = outlineData; if constexpr (ZeroFields) { memset(structObj->inlineData(), 0, inlineBytes); - memset(outlineData.pointer(), 0, outlineBytes); - } - - if (MOZ_LIKELY(js::gc::IsInsideNursery(structObj))) { - // See corresponding comment in WasmArrayObject::createArrayNonEmpty. - if (MOZ_UNLIKELY(!nursery.registerTrailer(outlineData, outlineBytes))) { - nursery.mallocedBlockCache().free(outlineData); - ReportOutOfMemory(cx); - return nullptr; - } - } else { - // See corresponding comment in WasmArrayObject::createArrayNonEmpty. - MOZ_ASSERT(structObj->isTenured()); - AddCellMemory(structObj, outlineBytes + wasm::TrailerBlockOverhead, - MemoryUse::WasmTrailerBlock); + memset(outlineData, 0, outlineBytes); } MOZ_ASSERT(typeDefData->clasp->shouldDelayMetadataBuilder()); diff --git a/js/src/wasm/WasmGcObject.cpp b/js/src/wasm/WasmGcObject.cpp @@ -554,29 +554,16 @@ void WasmStructObject::obj_trace(JSTracer* trc, JSObject* object) { reinterpret_cast<AnyRef*>(structObj.inlineData() + offset); TraceManuallyBarrieredEdge(trc, fieldPtr, "wasm-struct-field"); } - for (uint32_t offset : structType.outlineTraceOffsets_) { - AnyRef* fieldPtr = - reinterpret_cast<AnyRef*>(structObj.outlineData_ + offset); - TraceManuallyBarrieredEdge(trc, fieldPtr, "wasm-struct-field"); - } -} -/* static */ -void WasmStructObject::obj_finalize(JS::GCContext* gcx, JSObject* object) { - // See corresponding comments in WasmArrayObject::obj_finalize. - WasmStructObject& structObj = object->as<WasmStructObject>(); if (structObj.outlineData_) { - js_free(structObj.outlineData_); - const TypeDef& typeDef = structObj.typeDef(); - MOZ_ASSERT(typeDef.isStructType()); - uint32_t totalBytes = typeDef.structType().size_; - uint32_t inlineBytes, outlineBytes; - WasmStructObject::getDataByteSizes(totalBytes, &inlineBytes, &outlineBytes); - MOZ_ASSERT(inlineBytes == WasmStructObject_MaxInlineBytes); - MOZ_ASSERT(outlineBytes > 0); - gcx->removeCellMemory(&structObj, outlineBytes + TrailerBlockOverhead, - MemoryUse::WasmTrailerBlock); - structObj.outlineData_ = nullptr; + TraceBufferEdge(trc, &structObj, &structObj.outlineData_, + "WasmStructObject outline data"); + + for (uint32_t offset : structType.outlineTraceOffsets_) { + AnyRef* fieldPtr = + reinterpret_cast<AnyRef*>(structObj.outlineData_ + offset); + TraceManuallyBarrieredEdge(trc, fieldPtr, "wasm-struct-field"); + } } } @@ -593,9 +580,8 @@ size_t WasmStructObject::obj_moved(JSObject* obj, JSObject* old) { WasmStructObject::getDataByteSizes(totalBytes, &inlineBytes, &outlineBytes); MOZ_ASSERT(inlineBytes == WasmStructObject_MaxInlineBytes); MOZ_ASSERT(outlineBytes > 0); - nursery.trackTrailerOnPromotion(structObj.outlineData_, obj, outlineBytes, - TrailerBlockOverhead, - MemoryUse::WasmTrailerBlock); + nursery.maybeMoveBufferOnPromotion(&structObj.outlineData_, obj, + outlineBytes); } return 0; @@ -627,11 +613,11 @@ static const JSClassOps WasmStructObjectOutlineClassOps = { nullptr, /* delProperty */ nullptr, /* enumerate */ WasmGcObject::obj_newEnumerate, - nullptr, /* resolve */ - nullptr, /* mayResolve */ - WasmStructObject::obj_finalize, /* finalize */ - nullptr, /* call */ - nullptr, /* construct */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* construct */ WasmStructObject::obj_trace, }; static const ClassExtension WasmStructObjectOutlineClassExt = { @@ -639,8 +625,7 @@ static const ClassExtension WasmStructObjectOutlineClassExt = { }; const JSClass WasmStructObject::classOutline_ = { "WasmStructObject", - JSClass::NON_NATIVE | JSCLASS_DELAY_METADATA_BUILDER | - JSCLASS_BACKGROUND_FINALIZE | JSCLASS_SKIP_NURSERY_FINALIZE, + JSClass::NON_NATIVE | JSCLASS_DELAY_METADATA_BUILDER, &WasmStructObjectOutlineClassOps, JS_NULL_CLASS_SPEC, &WasmStructObjectOutlineClassExt,