/* -*- 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(); e.popFront(); BufferableRef* edge = e.get(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(data); new (cells) ArenaCellSet(arena); arena->bufferedCells = cells; rt->gc.storeBuffer.addToWholeCellBuffer(cells); return cells; } template struct StoreBuffer::MonoTypeBuffer; template struct StoreBuffer::MonoTypeBuffer; template struct StoreBuffer::MonoTypeBuffer;