Mypal/js/src/gc/StoreBuffer.cpp

154 lines
3.7 KiB
C++

/* -*- 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>;