diff options
Diffstat (limited to 'js/src/gc/StoreBuffer.cpp')
-rw-r--r-- | js/src/gc/StoreBuffer.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/js/src/gc/StoreBuffer.cpp b/js/src/gc/StoreBuffer.cpp new file mode 100644 index 000000000..af13778f0 --- /dev/null +++ b/js/src/gc/StoreBuffer.cpp @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gc/StoreBuffer-inl.h" + +#include "mozilla/Assertions.h" + +#include "jscompartment.h" + +#include "gc/Statistics.h" +#include "vm/ArgumentsObject.h" +#include "vm/Runtime.h" + +#include "jsgcinlines.h" + +using namespace js; +using namespace js::gc; + +void +StoreBuffer::GenericBuffer::trace(StoreBuffer* owner, JSTracer* trc) +{ + mozilla::ReentrancyGuard g(*owner); + MOZ_ASSERT(owner->isEnabled()); + if (!storage_) + return; + + for (LifoAlloc::Enum e(*storage_); !e.empty();) { + unsigned size = *e.get<unsigned>(); + e.popFront<unsigned>(); + BufferableRef* edge = e.get<BufferableRef>(size); + edge->trace(trc); + e.popFront(size); + } +} + +bool +StoreBuffer::enable() +{ + if (enabled_) + return true; + + if (!bufferVal.init() || + !bufferCell.init() || + !bufferSlot.init() || + !bufferGeneric.init()) + { + return false; + } + + enabled_ = true; + return true; +} + +void +StoreBuffer::disable() +{ + if (!enabled_) + return; + + aboutToOverflow_ = false; + + enabled_ = false; +} + +void +StoreBuffer::clear() +{ + if (!enabled_) + return; + + aboutToOverflow_ = false; + cancelIonCompilations_ = false; + + bufferVal.clear(); + bufferCell.clear(); + bufferSlot.clear(); + bufferGeneric.clear(); + + for (ArenaCellSet* set = bufferWholeCell; set; set = set->next) + set->arena->bufferedCells = nullptr; + bufferWholeCell = nullptr; +} + +void +StoreBuffer::setAboutToOverflow() +{ + if (!aboutToOverflow_) { + aboutToOverflow_ = true; + runtime_->gc.stats.count(gcstats::STAT_STOREBUFFER_OVERFLOW); + } + runtime_->gc.requestMinorGC(JS::gcreason::FULL_STORE_BUFFER); +} + +void +StoreBuffer::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::GCSizes +*sizes) +{ + sizes->storeBufferVals += bufferVal.sizeOfExcludingThis(mallocSizeOf); + sizes->storeBufferCells += bufferCell.sizeOfExcludingThis(mallocSizeOf); + sizes->storeBufferSlots += bufferSlot.sizeOfExcludingThis(mallocSizeOf); + sizes->storeBufferGenerics += bufferGeneric.sizeOfExcludingThis(mallocSizeOf); + + for (ArenaCellSet* set = bufferWholeCell; set; set = set->next) + sizes->storeBufferWholeCells += sizeof(ArenaCellSet); +} + +void +StoreBuffer::addToWholeCellBuffer(ArenaCellSet* set) +{ + set->next = bufferWholeCell; + bufferWholeCell = set; +} + +ArenaCellSet ArenaCellSet::Empty(nullptr); + +ArenaCellSet::ArenaCellSet(Arena* arena) + : arena(arena), next(nullptr) +{ + bits.clear(false); +} + +ArenaCellSet* +js::gc::AllocateWholeCellSet(Arena* arena) +{ + Zone* zone = arena->zone; + JSRuntime* rt = zone->runtimeFromMainThread(); + if (!rt->gc.nursery.isEnabled()) + return nullptr; + + AutoEnterOOMUnsafeRegion oomUnsafe; + Nursery& nursery = rt->gc.nursery; + void* data = nursery.allocateBuffer(zone, sizeof(ArenaCellSet)); + if (!data) { + oomUnsafe.crash("Failed to allocate WholeCellSet"); + return nullptr; + } + + if (nursery.freeSpace() < ArenaCellSet::NurseryFreeThresholdBytes) + rt->gc.storeBuffer.setAboutToOverflow(); + + auto cells = static_cast<ArenaCellSet*>(data); + new (cells) ArenaCellSet(arena); + arena->bufferedCells = cells; + rt->gc.storeBuffer.addToWholeCellBuffer(cells); + return cells; +} + +template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>; +template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::CellPtrEdge>; +template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotsEdge>; |