mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 12:50:09 +00:00
Bug 1122640 - Free nursery huge slots off main thread r=terrence
This commit is contained in:
parent
103cb3319e
commit
e859cbf0d5
@ -8,6 +8,7 @@
|
||||
#include "gc/Nursery-inl.h"
|
||||
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include "jscompartment.h"
|
||||
#include "jsgc.h"
|
||||
@ -36,6 +37,19 @@ using mozilla::ArrayLength;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodZero;
|
||||
|
||||
struct js::Nursery::FreeHugeSlotsTask : public GCParallelTask
|
||||
{
|
||||
FreeHugeSlotsTask(FreeOp *fop) : fop_(fop) {}
|
||||
bool init() { return slots_.init(); }
|
||||
void transferSlotsToFree(HugeSlotsSet &slotsToFree);
|
||||
|
||||
private:
|
||||
FreeOp *fop_;
|
||||
HugeSlotsSet slots_;
|
||||
|
||||
virtual void run() MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
bool
|
||||
js::Nursery::init(uint32_t maxNurseryBytes)
|
||||
{
|
||||
@ -53,6 +67,10 @@ js::Nursery::init(uint32_t maxNurseryBytes)
|
||||
if (!heap)
|
||||
return false;
|
||||
|
||||
freeHugeSlotsTask = js_new<FreeHugeSlotsTask>(runtime()->defaultFreeOp());
|
||||
if (!freeHugeSlotsTask || !freeHugeSlotsTask->init())
|
||||
return false;
|
||||
|
||||
heapStart_ = uintptr_t(heap);
|
||||
heapEnd_ = heapStart_ + nurserySize();
|
||||
currentStart_ = start();
|
||||
@ -80,6 +98,8 @@ js::Nursery::~Nursery()
|
||||
{
|
||||
if (start())
|
||||
UnmapPages((void *)start(), nurserySize());
|
||||
|
||||
js_delete(freeHugeSlotsTask);
|
||||
}
|
||||
|
||||
void
|
||||
@ -963,13 +983,48 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, ObjectGroupList
|
||||
#undef TIME_END
|
||||
#undef TIME_TOTAL
|
||||
|
||||
void
|
||||
js::Nursery::FreeHugeSlotsTask::transferSlotsToFree(HugeSlotsSet &slotsToFree)
|
||||
{
|
||||
// Transfer the contents of the source set to the task's slots_ member by
|
||||
// swapping the sets, which also clears the source.
|
||||
MOZ_ASSERT(!isRunning());
|
||||
MOZ_ASSERT(slots_.empty());
|
||||
mozilla::Swap(slots_, slotsToFree);
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::FreeHugeSlotsTask::run()
|
||||
{
|
||||
for (HugeSlotsSet::Range r = slots_.all(); !r.empty(); r.popFront())
|
||||
fop_->free_(r.front());
|
||||
slots_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::freeHugeSlots()
|
||||
{
|
||||
FreeOp *fop = runtime()->defaultFreeOp();
|
||||
for (HugeSlotsSet::Range r = hugeSlots.all(); !r.empty(); r.popFront())
|
||||
fop->free_(r.front());
|
||||
hugeSlots.clear();
|
||||
if (hugeSlots.empty())
|
||||
return;
|
||||
|
||||
bool started;
|
||||
{
|
||||
AutoLockHelperThreadState lock;
|
||||
freeHugeSlotsTask->joinWithLockHeld();
|
||||
freeHugeSlotsTask->transferSlotsToFree(hugeSlots);
|
||||
started = freeHugeSlotsTask->startWithLockHeld();
|
||||
}
|
||||
|
||||
if (!started)
|
||||
freeHugeSlotsTask->runFromMainThread(runtime());
|
||||
|
||||
MOZ_ASSERT(hugeSlots.empty());
|
||||
}
|
||||
|
||||
void
|
||||
js::Nursery::waitBackgroundFreeEnd()
|
||||
{
|
||||
freeHugeSlotsTask->join();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -68,7 +68,8 @@ class Nursery
|
||||
numNurseryChunks_(0),
|
||||
finalizers_(nullptr),
|
||||
profileThreshold_(0),
|
||||
enableProfiling_(false)
|
||||
enableProfiling_(false),
|
||||
freeHugeSlotsTask(nullptr)
|
||||
{}
|
||||
~Nursery();
|
||||
|
||||
@ -141,6 +142,8 @@ class Nursery
|
||||
setForwardingPointer(oldData, newData, direct);
|
||||
}
|
||||
|
||||
void waitBackgroundFreeEnd();
|
||||
|
||||
size_t sizeOfHeapCommitted() const {
|
||||
return numActiveChunks_ * gc::ChunkSize;
|
||||
}
|
||||
@ -224,6 +227,10 @@ class Nursery
|
||||
typedef HashSet<HeapSlot *, PointerHasher<HeapSlot *, 3>, SystemAllocPolicy> HugeSlotsSet;
|
||||
HugeSlotsSet hugeSlots;
|
||||
|
||||
/* A task structure used to free the huge slots on a background thread. */
|
||||
struct FreeHugeSlotsTask;
|
||||
FreeHugeSlotsTask *freeHugeSlotsTask;
|
||||
|
||||
/*
|
||||
* During a collection most hoisted slot and element buffers indicate their
|
||||
* new location with a forwarding pointer at the base. This does not work
|
||||
|
@ -6347,6 +6347,9 @@ GCRuntime::onOutOfMallocMemory()
|
||||
// Stop allocating new chunks.
|
||||
allocTask.cancel(GCParallelTask::CancelAndWait);
|
||||
|
||||
// Wait for background free of nursery huge slots to finish.
|
||||
nursery.waitBackgroundFreeEnd();
|
||||
|
||||
AutoLockGC lock(rt);
|
||||
onOutOfMallocMemory(lock);
|
||||
}
|
||||
|
@ -998,6 +998,7 @@ class GCParallelTask
|
||||
|
||||
public:
|
||||
GCParallelTask() : state(NotStarted), duration_(0) {}
|
||||
virtual ~GCParallelTask();
|
||||
|
||||
// Time spent in the most recent invocation of this task.
|
||||
int64_t duration() const { return duration_; }
|
||||
|
@ -738,6 +738,11 @@ GlobalHelperThreadState::canStartGCParallelTask()
|
||||
return !gcParallelWorklist().empty();
|
||||
}
|
||||
|
||||
js::GCParallelTask::~GCParallelTask()
|
||||
{
|
||||
join();
|
||||
}
|
||||
|
||||
bool
|
||||
js::GCParallelTask::startWithLockHeld()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user