Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  StoreBuffer.cpp

  Sprache: C
 

/* 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 "gc/GCRuntime.h"
#include "gc/Statistics.h"
#include "vm/MutexIDs.h"
#include "vm/Runtime.h"

using namespace js;
using namespace js::gc;

ArenaCellSet ArenaCellSet::Empty;

ArenaCellSet::ArenaCellSet(Arena* arena)
    : arena(arena)
#ifdef DEBUG
      ,
      minorGCNumberAtCreation(
          arena->zone()->runtimeFromMainThread()->gc.minorGCCount())
#endif
{
  MOZ_ASSERT(arena);
  MOZ_ASSERT(bits.isAllClear());
}

template <typename T>
StoreBuffer::MonoTypeBuffer<T>::MonoTypeBuffer(MonoTypeBuffer&& other)
    : stores_(std::move(other.stores_)),
      maxEntries_(other.maxEntries_),
      last_(std::move(other.last_)) {
  other.clear();
}
template <typename T>
StoreBuffer::MonoTypeBuffer<T>& StoreBuffer::MonoTypeBuffer<T>::operator=(
    MonoTypeBuffer&& other) {
  if (&other != this) {
    this->~MonoTypeBuffer();
    new (this) MonoTypeBuffer(std::move(other));
  }
  return *this;
}

template <typename T>
void StoreBuffer::MonoTypeBuffer<T>::setSize(size_t entryCount) {
  MOZ_ASSERT(entryCount != 0);
  maxEntries_ = entryCount;
}

template <typename T>
bool StoreBuffer::MonoTypeBuffer<T>::isEmpty() const {
  return last_ == T() && stores_.empty();
}

template <typename T>
void StoreBuffer::MonoTypeBuffer<T>::clear() {
  last_ = T();
  stores_.clear();
}

template <typename T>
size_t StoreBuffer::MonoTypeBuffer<T>::sizeOfExcludingThis(
    mozilla::MallocSizeOf mallocSizeOf) {
  return stores_.shallowSizeOfExcludingThis(mallocSizeOf);
}

StoreBuffer::WholeCellBuffer::WholeCellBuffer(WholeCellBuffer&& other)
    : storage_(std::move(other.storage_)),
      maxSize_(other.maxSize_),
      last_(other.last_) {
  other.last_ = nullptr;
}
StoreBuffer::WholeCellBuffer& StoreBuffer::WholeCellBuffer::operator=(
    WholeCellBuffer&& other) {
  if (&other != this) {
    this->~WholeCellBuffer();
    new (this) WholeCellBuffer(std::move(other));
  }
  return *this;
}

bool StoreBuffer::WholeCellBuffer::init() {
  if (!storage_) {
    storage_ = MakeUnique<LifoAlloc>(LifoAllocBlockSize, js::MallocArena);
    if (!storage_) {
      return false;
    }
  }

  // This prevents LifoAlloc::Enum from crashing with a release
  // assertion if we ever allocate one entry larger than
  // LifoAllocBlockSize.
  storage_->disableOversize();

  clear();
  return true;
}

void StoreBuffer::WholeCellBuffer::setSize(size_t entryCount) {
  MOZ_ASSERT(entryCount);
  maxSize_ = entryCount * sizeof(ArenaCellSet);
}

bool StoreBuffer::WholeCellBuffer::isEmpty() const {
  return !storage_ || storage_->isEmpty();
}

void StoreBuffer::WholeCellBuffer::clear() {
  if (storage_) {
    for (LifoAlloc::Enum e(*storage_); !e.empty();) {
      ArenaCellSet* cellSet = e.read<ArenaCellSet>();
      cellSet->arena->bufferedCells() = &ArenaCellSet::Empty;
    }

    storage_->used() ? storage_->releaseAll() : storage_->freeAll();
  }

  last_ = nullptr;
}

ArenaCellSet* StoreBuffer::WholeCellBuffer::allocateCellSet(Arena* arena) {
  MOZ_ASSERT(arena->bufferedCells() == &ArenaCellSet::Empty);

  Zone* zone = arena->zone();
  JSRuntime* rt = zone->runtimeFromMainThread();
  if (!rt->gc.nursery().isEnabled()) {
    return nullptr;
  }

  AutoEnterOOMUnsafeRegion oomUnsafe;
  auto* cells = storage_->new_<ArenaCellSet>(arena);
  if (!cells) {
    oomUnsafe.crash("Failed to allocate ArenaCellSet");
  }

  arena->bufferedCells() = cells;

  if (isAboutToOverflow()) {
    rt->gc.storeBuffer().setAboutToOverflow(
        JS::GCReason::FULL_WHOLE_CELL_BUFFER);
  }

  return cells;
}

size_t StoreBuffer::WholeCellBuffer::sizeOfExcludingThis(
    mozilla::MallocSizeOf mallocSizeOf) {
  return storage_ ? storage_->sizeOfIncludingThis(mallocSizeOf) : 0;
}

StoreBuffer::GenericBuffer::GenericBuffer(GenericBuffer&& other)
    : storage_(std::move(other.storage_)), maxSize_(other.maxSize_) {}
StoreBuffer::GenericBuffer& StoreBuffer::GenericBuffer::operator=(
    GenericBuffer&& other) {
  if (&other != this) {
    this->~GenericBuffer();
    new (this) GenericBuffer(std::move(other));
  }
  return *this;
}

bool StoreBuffer::GenericBuffer::isEmpty() const {
  return !storage_ || storage_->isEmpty();
}

void StoreBuffer::GenericBuffer::clear() {
  if (storage_) {
    storage_->used() ? storage_->releaseAll() : storage_->freeAll();
  }
}

size_t StoreBuffer::GenericBuffer::sizeOfExcludingThis(
    mozilla::MallocSizeOf mallocSizeOf) {
  return storage_ ? storage_->sizeOfIncludingThis(mallocSizeOf) : 0;
}

bool StoreBuffer::GenericBuffer::init() {
  if (!storage_) {
    storage_ = MakeUnique<LifoAlloc>(LifoAllocBlockSize, js::MallocArena);
    if (!storage_) {
      return false;
    }
  }

  clear();
  return true;
}

void StoreBuffer::GenericBuffer::setSize(size_t entryCount) {
  MOZ_ASSERT(entryCount != 0);
  maxSize_ = entryCount * (sizeof(BufferableRef) + sizeof(void*));
}

void StoreBuffer::GenericBuffer::trace(JSTracer* trc, StoreBuffer* owner) {
  mozilla::ReentrancyGuard g(*owner);
  MOZ_ASSERT(owner->isEnabled());
  if (!storage_) {
    return;
  }

  for (LifoAlloc::Enum e(*storage_); !e.empty();) {
    unsigned size = *e.read<unsigned>();
    BufferableRef* edge = e.read<BufferableRef>(size);
    edge->trace(trc);
  }
}

StoreBuffer::StoreBuffer(GCRuntime* gc)
    : gc_(gc),
      nursery_(gc->nursery()),
      entryCount_(gc->tunables.storeBufferEntries()),
      entryScaling_(gc->tunables.storeBufferScaling()),
      aboutToOverflow_(false),
      enabled_(false),
      mayHavePointersToDeadCells_(false)
#ifdef DEBUG
      ,
      mEntered(false)
#endif
{
  MOZ_ASSERT(entryCount_ != 0);
}

StoreBuffer::StoreBuffer(StoreBuffer&& other)
    : bufferVal(std::move(other.bufferVal)),
      bufStrCell(std::move(other.bufStrCell)),
      bufBigIntCell(std::move(other.bufBigIntCell)),
      bufGetterSetterCell(std::move(other.bufGetterSetterCell)),
      bufObjCell(std::move(other.bufObjCell)),
      bufferSlot(std::move(other.bufferSlot)),
      bufferWasmAnyRef(std::move(other.bufferWasmAnyRef)),
      bufferWholeCell(std::move(other.bufferWholeCell)),
      bufferGeneric(std::move(other.bufferGeneric)),
      gc_(other.gc_),
      nursery_(other.nursery_),
      entryCount_(other.entryCount_),
      entryScaling_(other.entryScaling_),
      aboutToOverflow_(other.aboutToOverflow_),
      enabled_(other.enabled_),
      mayHavePointersToDeadCells_(other.mayHavePointersToDeadCells_)
#ifdef DEBUG
      ,
      mEntered(other.mEntered)
#endif
{
  MOZ_ASSERT(entryCount_ != 0);
  MOZ_ASSERT(enabled_);
  MOZ_ASSERT(!mEntered);
  other.disable();
}

StoreBuffer& StoreBuffer::operator=(StoreBuffer&& other) {
  if (&other != this) {
    this->~StoreBuffer();
    new (this) StoreBuffer(std::move(other));
  }
  return *this;
}

#ifdef DEBUG
void StoreBuffer::checkAccess() const {
  // The GC runs tasks that may access the storebuffer in parallel and so must
  // take a lock. The mutator may only access the storebuffer from the main
  // thread.
  if (gc_->heapState() != JS::HeapState::Idle &&
      gc_->heapState() != JS::HeapState::MinorCollecting) {
    MOZ_ASSERT(!CurrentThreadIsGCMarking());
    gc_->assertCurrentThreadHasLockedSweepingLock();
  } else {
    MOZ_ASSERT(CurrentThreadCanAccessRuntime(gc_->rt));
  }
}
#endif

void StoreBuffer::checkEmpty() const { MOZ_ASSERT(isEmpty()); }

bool StoreBuffer::isEmpty() const {
  return bufferVal.isEmpty() && bufStrCell.isEmpty() &&
         bufBigIntCell.isEmpty() && bufGetterSetterCell.isEmpty() &&
         bufObjCell.isEmpty() && bufferSlot.isEmpty() &&
         bufferWasmAnyRef.isEmpty() && bufferWholeCell.isEmpty() &&
         bufferGeneric.isEmpty();
}

bool StoreBuffer::enable() {
  if (enabled_) {
    return true;
  }

  checkEmpty();
  if (!bufferWholeCell.init() || !bufferGeneric.init()) {
    return false;
  }

  updateSize();

  enabled_ = true;
  return true;
}

void StoreBuffer::updateSize() {
  // The entry counts for the individual buffers are scaled based on the initial
  // entryCount parameter passed to the constructor.
  MOZ_ASSERT(entryCount_ != 0);
  MOZ_ASSERT(entryScaling_ >= 0.0 && entryScaling_ <= 1.0);

  // Scale the entry count linearly based on the size of the nursery. The entry
  // count parameter specifies the result at a nursery size of 16MB.
  const double nurseryBaseSize = 16 * 1024 * 1024;
  double nurserySizeRatio = double(nursery_.capacity()) / nurseryBaseSize;
  double count =
      ((nurserySizeRatio - 1.0) * entryScaling_ + 1.0) * double(entryCount_);
  MOZ_ASSERT(count > 0.0);
  size_t defaultEntryCount = size_t(std::max(count, 1.0));

  size_t slotsEntryCount = std::max(defaultEntryCount / 2, size_t(1));
  size_t wholeCellEntryCount = std::max(defaultEntryCount / 10, size_t(1));
  size_t genericEntryCount = std::max(defaultEntryCount / 4, size_t(1));

  bufferVal.setSize(defaultEntryCount);
  bufStrCell.setSize(defaultEntryCount);
  bufBigIntCell.setSize(defaultEntryCount);
  bufGetterSetterCell.setSize(defaultEntryCount);
  bufObjCell.setSize(defaultEntryCount);
  bufferSlot.setSize(slotsEntryCount);
  bufferWasmAnyRef.setSize(defaultEntryCount);
  bufferWholeCell.setSize(wholeCellEntryCount);
  bufferGeneric.setSize(genericEntryCount);
}

void StoreBuffer::disable() {
  checkEmpty();

  if (!enabled_) {
    return;
  }

  aboutToOverflow_ = false;

  enabled_ = false;
}

void StoreBuffer::clear() {
  if (!enabled_) {
    return;
  }

  aboutToOverflow_ = false;
  mayHavePointersToDeadCells_ = false;

  bufferVal.clear();
  bufStrCell.clear();
  bufBigIntCell.clear();
  bufGetterSetterCell.clear();
  bufObjCell.clear();
  bufferSlot.clear();
  bufferWasmAnyRef.clear();
  bufferWholeCell.clear();
  bufferGeneric.clear();
}

void StoreBuffer::setAboutToOverflow(JS::GCReason reason) {
  if (!aboutToOverflow_) {
    aboutToOverflow_ = true;
    gc_->stats().count(gcstats::COUNT_STOREBUFFER_OVERFLOW);
  }
  nursery_.requestMinorGC(reason);
}

void StoreBuffer::traceValues(TenuringTracer& mover) {
  bufferVal.trace(mover, this);
}
void StoreBuffer::traceCells(TenuringTracer& mover) {
  bufStrCell.trace(mover, this);
  bufBigIntCell.trace(mover, this);
  bufGetterSetterCell.trace(mover, this);
  bufObjCell.trace(mover, this);
}
void StoreBuffer::traceSlots(TenuringTracer& mover) {
  bufferSlot.trace(mover, this);
}
void StoreBuffer::traceWasmAnyRefs(TenuringTracer& mover) {
  bufferWasmAnyRef.trace(mover, this);
}
void StoreBuffer::traceWholeCells(TenuringTracer& mover) {
  bufferWholeCell.trace(mover, this);
}
void StoreBuffer::traceGenericEntries(JSTracer* trc) {
  bufferGeneric.trace(trc, this);
}

void StoreBuffer::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                         JS::GCSizes* sizes) {
  sizes->storeBufferVals += bufferVal.sizeOfExcludingThis(mallocSizeOf);
  sizes->storeBufferCells +=
      bufStrCell.sizeOfExcludingThis(mallocSizeOf) +
      bufBigIntCell.sizeOfExcludingThis(mallocSizeOf) +
      bufGetterSetterCell.sizeOfExcludingThis(mallocSizeOf) +
      bufObjCell.sizeOfExcludingThis(mallocSizeOf);
  sizes->storeBufferSlots += bufferSlot.sizeOfExcludingThis(mallocSizeOf);
  sizes->storeBufferWasmAnyRefs +=
      bufferWasmAnyRef.sizeOfExcludingThis(mallocSizeOf);
  sizes->storeBufferWholeCells +=
      bufferWholeCell.sizeOfExcludingThis(mallocSizeOf);
  sizes->storeBufferGenerics += bufferGeneric.sizeOfExcludingThis(mallocSizeOf);
}

void gc::CellHeaderPostWriteBarrier(JSObject** ptr, JSObject* prev,
                                    JSObject* next) {
  InternalBarrierMethods<JSObject*>::postBarrier(ptr, prev, next);
}

template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::ValueEdge>;
template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::SlotsEdge>;
template struct StoreBuffer::MonoTypeBuffer<StoreBuffer::WasmAnyRefEdge>;

void js::gc::PostWriteBarrierCell(Cell* cell, Cell* prev, Cell* next) {
  if (!next || !cell->isTenured()) {
    return;
  }

  StoreBuffer* buffer = next->storeBuffer();
  if (!buffer || (prev && prev->storeBuffer())) {
    return;
  }

  buffer->putWholeCell(cell);
}

Messung V0.5 in Prozent
C=92 H=92 G=91

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002