Skip to content

Commit c5c8110

Browse files
committed
Bug 1978645 - Part 0: Add argument for max nursery size to buffer allocation APIs r=sfink
Wasm GC allocations tend to get tenured more often than regular JS objects which means minor GCs can spend a lot of time moving these directly allocated buffers. This increases minor GC time which also means we keep the nursery size smaller, affecting performance. This adds an option to set the maximum size of buffer allocations made directly in the nursery. For Wasm GC allocations we'll make this smaller than the regular size. Differential Revision: https://phabricator.services.mozilla.com/D267390
1 parent f7162eb commit c5c8110

File tree

3 files changed

+51
-41
lines changed

3 files changed

+51
-41
lines changed

js/src/gc/Nursery-inl.h

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,28 @@ inline void js::Nursery::unregisterTrailer(void* block) {
301301
fromSpace.trailersRemovedUsed_++;
302302
}
303303

304+
inline void* js::Nursery::allocateBuffer(Zone* zone, js::gc::Cell* owner,
305+
size_t nbytes, size_t maxNurserySize) {
306+
MOZ_ASSERT(owner);
307+
MOZ_ASSERT(zone == owner->zone());
308+
MOZ_ASSERT(nbytes > 0);
309+
MOZ_ASSERT(nbytes <= SIZE_MAX - gc::CellAlignBytes);
310+
nbytes = RoundUp(nbytes, gc::CellAlignBytes);
311+
312+
if (!IsInsideNursery(owner)) {
313+
return gc::AllocBuffer(zone, nbytes, false);
314+
}
315+
316+
if (nbytes <= maxNurserySize) {
317+
void* buffer = allocateInternalBuffer(zone, nbytes);
318+
if (buffer) {
319+
return buffer;
320+
}
321+
}
322+
323+
return gc::AllocBuffer(zone, nbytes, true);
324+
}
325+
304326
namespace js {
305327

306328
// The allocation methods below will not run the garbage collector. If the
@@ -328,18 +350,22 @@ static inline T* AllocNurseryOrMallocBuffer(JSContext* cx, gc::Cell* cell,
328350
}
329351

330352
template <typename T>
331-
static inline T* AllocateCellBuffer(Nursery& nursery, JS::Zone* zone,
332-
gc::Cell* cell, uint32_t count) {
353+
static inline T* AllocateCellBuffer(
354+
Nursery& nursery, JS::Zone* zone, gc::Cell* cell, uint32_t count,
355+
size_t maxNurserySize = Nursery::MaxNurseryBufferSize) {
333356
MOZ_ASSERT(zone == cell->zone());
334357

335358
size_t nbytes = RoundUp(count * sizeof(T), sizeof(Value));
336-
return static_cast<T*>(nursery.allocateBuffer(zone, cell, nbytes));
359+
return static_cast<T*>(
360+
nursery.allocateBuffer(zone, cell, nbytes, maxNurserySize));
337361
}
338362

339363
template <typename T>
340-
static inline T* AllocateCellBuffer(JSContext* cx, gc::Cell* cell,
341-
uint32_t count) {
342-
T* buffer = AllocateCellBuffer<T>(cx->nursery(), cx->zone(), cell, count);
364+
static inline T* AllocateCellBuffer(
365+
JSContext* cx, gc::Cell* cell, uint32_t count,
366+
size_t maxNurserySize = Nursery::MaxNurseryBufferSize) {
367+
T* buffer = AllocateCellBuffer<T>(cx->nursery(), cx->zone(), cell, count,
368+
maxNurserySize);
343369
if (!buffer) {
344370
ReportOutOfMemory(cx);
345371
return nullptr;
@@ -368,25 +394,27 @@ static inline T* ReallocNurseryOrMallocBuffer(JSContext* cx, gc::Cell* cell,
368394

369395
// If this returns null then the old buffer will be left alone.
370396
template <typename T>
371-
static inline T* ReallocateCellBuffer(Nursery& nursery, JS::Zone* zone,
372-
gc::Cell* cell, T* oldBuffer,
373-
uint32_t oldCount, uint32_t newCount) {
397+
static inline T* ReallocateCellBuffer(
398+
Nursery& nursery, JS::Zone* zone, gc::Cell* cell, T* oldBuffer,
399+
uint32_t oldCount, uint32_t newCount,
400+
size_t maxNurserySize = Nursery::MaxNurseryBufferSize) {
374401
MOZ_ASSERT(zone == cell->zone());
375402

376403
size_t oldBytes = RoundUp(oldCount * sizeof(T), sizeof(Value));
377404
size_t newBytes = RoundUp(newCount * sizeof(T), sizeof(Value));
378405

379-
return static_cast<T*>(
380-
nursery.reallocateBuffer(zone, cell, oldBuffer, oldBytes, newBytes));
406+
return static_cast<T*>(nursery.reallocateBuffer(
407+
zone, cell, oldBuffer, oldBytes, newBytes, maxNurserySize));
381408
}
382409

383410
// If this returns null then the old buffer will be left alone.
384411
template <typename T>
385-
static inline T* ReallocateCellBuffer(JSContext* cx, gc::Cell* cell,
386-
T* oldBuffer, uint32_t oldCount,
387-
uint32_t newCount) {
388-
T* buffer = ReallocateCellBuffer<T>(cx->nursery(), cx->zone(), cell,
389-
oldBuffer, oldCount, newCount);
412+
static inline T* ReallocateCellBuffer(
413+
JSContext* cx, gc::Cell* cell, T* oldBuffer, uint32_t oldCount,
414+
uint32_t newCount, size_t maxNurserySize = Nursery::MaxNurseryBufferSize) {
415+
T* buffer =
416+
ReallocateCellBuffer<T>(cx->nursery(), cx->zone(), cell, oldBuffer,
417+
oldCount, newCount, maxNurserySize);
390418
if (!buffer) {
391419
ReportOutOfMemory(cx);
392420
}

js/src/gc/Nursery.cpp

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -826,27 +826,6 @@ void* js::Nursery::allocNurseryOrMallocBuffer(Zone* zone, Cell* owner,
826826
return buffer;
827827
}
828828

829-
void* js::Nursery::allocateBuffer(Zone* zone, Cell* owner, size_t nbytes) {
830-
MOZ_ASSERT(owner);
831-
MOZ_ASSERT(zone == owner->zone());
832-
MOZ_ASSERT(nbytes > 0);
833-
MOZ_ASSERT(nbytes <= SIZE_MAX - gc::CellAlignBytes);
834-
nbytes = RoundUp(nbytes, gc::CellAlignBytes);
835-
836-
if (!IsInsideNursery(owner)) {
837-
return AllocBuffer(zone, nbytes, false);
838-
}
839-
840-
if (nbytes <= MaxNurseryBufferSize) {
841-
void* buffer = allocateInternalBuffer(zone, nbytes);
842-
if (buffer) {
843-
return buffer;
844-
}
845-
}
846-
847-
return AllocBuffer(zone, nbytes, true);
848-
}
849-
850829
std::tuple<void*, bool> js::Nursery::allocateZeroedBuffer(Zone* zone,
851830
size_t nbytes,
852831
arena_id_t arena) {
@@ -920,7 +899,8 @@ void* js::Nursery::reallocNurseryOrMallocBuffer(Zone* zone, Cell* cell,
920899
}
921900

922901
void* js::Nursery::reallocateBuffer(Zone* zone, Cell* cell, void* oldBuffer,
923-
size_t oldBytes, size_t newBytes) {
902+
size_t oldBytes, size_t newBytes,
903+
size_t maxNurserySize) {
924904
if (!IsInsideNursery(cell)) {
925905
MOZ_ASSERT(IsBufferAlloc(oldBuffer));
926906
MOZ_ASSERT(!IsNurseryOwned(zone, oldBuffer));
@@ -937,7 +917,7 @@ void* js::Nursery::reallocateBuffer(Zone* zone, Cell* cell, void* oldBuffer,
937917
return oldBuffer;
938918
}
939919

940-
auto newBuffer = allocateBuffer(zone, cell, newBytes);
920+
auto newBuffer = allocateBuffer(zone, cell, newBytes, maxNurserySize);
941921
if (newBuffer) {
942922
PodCopy((uint8_t*)newBuffer, (uint8_t*)oldBuffer, oldBytes);
943923
}

js/src/gc/Nursery.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ class Nursery {
157157
// owner is in the nursery.
158158
void* allocNurseryOrMallocBuffer(JS::Zone* zone, gc::Cell* owner,
159159
size_t nbytes, arena_id_t arenaId);
160-
void* allocateBuffer(JS::Zone* zone, gc::Cell* owner, size_t nbytes);
160+
void* allocateBuffer(JS::Zone* zone, gc::Cell* owner, size_t nbytes,
161+
size_t maxNurserySize);
161162

162163
// Allocate a zero-initialized buffer for a given zone, using the nursery if
163164
// possible. If the buffer isn't allocated in the nursery, the given arena is
@@ -178,7 +179,8 @@ class Nursery {
178179

179180
// Resize an existing buffer.
180181
void* reallocateBuffer(JS::Zone* zone, gc::Cell* cell, void* oldBuffer,
181-
size_t oldBytes, size_t newBytes);
182+
size_t oldBytes, size_t newBytes,
183+
size_t maxNurserySize);
182184

183185
// Free an existing buffer.
184186
void freeBuffer(JS::Zone* zone, gc::Cell* cell, void* buffer, size_t bytes);

0 commit comments

Comments
 (0)