diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index dff65809e4..00041e3348 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -1528,7 +1528,36 @@ class GCRuntime * During incremental sweeping, this field temporarily holds the arenas of * the current AllocKind being swept in order of increasing free space. */ - SortedArenaList incrementalSweepList; + ActiveThreadData incrementalSweepList; + + private: + ActiveThreadData nursery_; + ActiveThreadData storeBuffer_; + public: + Nursery& nursery() { return nursery_.ref(); } + gc::StoreBuffer& storeBuffer() { return storeBuffer_.ref(); } + + // Free LIFO blocks are transferred to this allocator before being freed + // after minor GC. + ActiveThreadData blocksToFreeAfterMinorGC; + + const void* addressOfNurseryPosition() { + return nursery_.refNoCheck().addressOfPosition(); + } + const void* addressOfNurseryCurrentEnd() { + return nursery_.refNoCheck().addressOfCurrentEnd(); + } + + const void* addressOfStringNurseryCurrentEnd() { + return nursery_.refNoCheck().addressOfCurrentStringEnd(); + } + + void minorGC(JS::gcreason::Reason reason, + gcstats::Phase phase = gcstats::PHASE_MINOR_GC) JS_HAZ_GC_CALL; + void evictNursery(JS::gcreason::Reason reason = JS::gcreason::EVICT_NURSERY) { + minorGC(reason, gcstats::PHASE_EVICT_NURSERY); + } + void freeAllLifoBlocksAfterMinorGC(LifoAlloc* lifo); friend class js::GCHelperState; friend class MarkingValidator; diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index bdde70a261..3ae4b1c516 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -120,6 +120,7 @@ js::Nursery::Nursery(JSRuntime* rt) , currentStartChunk_(0) , currentStartPosition_(0) , currentEnd_(0) + , currentStringEnd_(0) , currentChunk_(0) , maxChunkCount_(0) , chunkCountLimit_(0) @@ -240,6 +241,8 @@ js::Nursery::disable() currentEnd_ = 0; + position_ = 0; + currentStringEnd_ = 0; runtime()->gc.storeBuffer().disable(); } @@ -248,6 +251,7 @@ js::Nursery::enableStrings() { MOZ_ASSERT(isEmpty()); canAllocateStrings_ = true; + currentStringEnd_ = currentEnd_; } void @@ -255,6 +259,7 @@ js::Nursery::disableStrings() { MOZ_ASSERT(isEmpty()); canAllocateStrings_ = false; + currentStringEnd_ = 0; } bool @@ -1002,6 +1007,8 @@ js::Nursery::setCurrentChunk(unsigned chunkno) currentChunk_ = chunkno; position_ = chunk(chunkno).start(); currentEnd_ = chunk(chunkno).end(); + if (canAllocateStrings_) + currentStringEnd_ = currentEnd_; chunk(chunkno).poisonAndInit(runtime(), JS_FRESH_NURSERY_PATTERN); } diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 67c2fed982..0dca66e87d 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -316,6 +316,7 @@ class Nursery void* addressOfCurrentEnd() const { return (void*)¤tEnd_; } void* addressOfPosition() const { return (void*)&position_; } + void* addressOfCurrentStringEnd() const { return (void*)¤tStringEnd_; } void requestMinorGC(JS::gcreason::Reason reason) const; @@ -357,6 +358,12 @@ class Nursery /* Pointer to the last byte of space in the current chunk. */ uintptr_t currentEnd_; + /* + * Pointer to the last byte of space in the current chunk, or nullptr if we + * are not allocating strings in the nursery. + */ + uintptr_t currentStringEnd_; + /* The index of the chunk that is currently being allocated from. */ unsigned currentChunk_; diff --git a/js/src/jit/CompileWrappers.cpp b/js/src/jit/CompileWrappers.cpp index 1db0122a49..3fa406274b 100644 --- a/js/src/jit/CompileWrappers.cpp +++ b/js/src/jit/CompileWrappers.cpp @@ -217,6 +217,45 @@ CompileZone::addressOfFreeList(gc::AllocKind allocKind) return zone()->arenas.addressOfFreeList(allocKind); } +const void* +CompileZone::addressOfNurseryPosition() +{ + return zone()->runtimeFromAnyThread()->gc.addressOfNurseryPosition(); +} + +const void* +CompileZone::addressOfStringNurseryPosition() +{ + // Objects and strings share a nursery, for now at least. + return zone()->runtimeFromAnyThread()->gc.addressOfNurseryPosition(); +} + +const void* +CompileZone::addressOfNurseryCurrentEnd() +{ + return zone()->runtimeFromAnyThread()->gc.addressOfNurseryCurrentEnd(); +} + +const void* +CompileZone::addressOfStringNurseryCurrentEnd() +{ + return zone()->runtimeFromAnyThread()->gc.addressOfStringNurseryCurrentEnd(); +} + +bool +CompileZone::nurseryExists() +{ + MOZ_ASSERT(CurrentThreadCanAccessZone(zone())); + return zone()->group()->nursery().exists(); +} + +void +CompileZone::setMinorGCShouldCancelIonCompilations() +{ + MOZ_ASSERT(CurrentThreadCanAccessZone(zone())); + zone()->group()->storeBuffer().setShouldCancelIonCompilations(); +} + JSCompartment* CompileCompartment::compartment() { diff --git a/js/src/jit/CompileWrappers.h b/js/src/jit/CompileWrappers.h index 618735627b..4854b87491 100644 --- a/js/src/jit/CompileWrappers.h +++ b/js/src/jit/CompileWrappers.h @@ -93,6 +93,11 @@ class CompileZone static CompileZone* get(Zone* zone); const void* addressOfNeedsIncrementalBarrier(); + const void* addressOfFreeList(gc::AllocKind allocKind); + const void* addressOfNurseryPosition(); + const void* addressOfStringNurseryPosition(); + const void* addressOfNurseryCurrentEnd(); + const void* addressOfStringNurseryCurrentEnd(); const void* addressOfFreeList(gc::AllocKind allocKind); }; diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index b1510109f4..22f8ca8f8b 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -887,8 +887,8 @@ MOZ_ASSERT(IsNurseryAllocable(allocKind)); // very close to each other. In practice, the zone will probably be close // (within 32 bits) as well. If so, use relative offsets between them, to // avoid multiple 64-bit immediate loads. - auto nurseryPosAddr = intptr_t(zone->addressOfNurseryPosition()); - auto nurseryEndAddr = intptr_t(zone->addressOfNurseryCurrentEnd()); + auto nurseryPosAddr = intptr_t(zone->addressOfStringNurseryPosition()); + auto nurseryEndAddr = intptr_t(zone->addressOfStringNurseryCurrentEnd()); auto zoneAddr = intptr_t(zone); intptr_t maxOffset = std::max(std::abs(nurseryPosAddr - zoneAddr),