summaryrefslogtreecommitdiffstats
path: root/js/src/gc/StoreBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/gc/StoreBuffer.cpp')
-rw-r--r--js/src/gc/StoreBuffer.cpp153
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>;