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


Quelle  Nursery-inl.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=4 sw=2 et tw=80 ft=cpp:
 *
 * 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/. */


#ifndef gc_Nursery_inl_h
#define gc_Nursery_inl_h

#include "gc/Nursery.h"

#include "gc/GCRuntime.h"
#include "gc/RelocationOverlay.h"
#include "js/TracingAPI.h"
#include "vm/JSContext.h"
#include "vm/NativeObject.h"
#include "vm/StringType.h"

namespace js {
namespace gc {
struct Cell;
}  // namespace gc
}  // namespace js

inline JSRuntime* js::Nursery::runtime() const { return gc->rt; }

template <typename T>
bool js::Nursery::isInside(const SharedMem<T>& p) const {
  return isInside(p.unwrap(/*safe - used for value in comparison above*/));
}

inline void js::Nursery::addMallocedBufferBytes(size_t nbytes) {
  MOZ_ASSERT(nbytes > 0);
  toSpace.mallocedBufferBytes += nbytes;
  if (MOZ_UNLIKELY(toSpace.mallocedBufferBytes > capacity() * 8)) {
    requestMinorGC(JS::GCReason::NURSERY_MALLOC_BUFFERS);
  }
}

inline bool js::Nursery::addStringBuffer(JSLinearString* s) {
  MOZ_ASSERT(IsInsideNursery(s));
  MOZ_ASSERT(isEnabled());
  MOZ_ASSERT(s->hasStringBuffer());

  auto* buffer = s->stringBuffer();
  if (!stringBuffers_.emplaceBack(s, buffer)) {
    return false;
  }

  // Note: update mallocedBufferBytes only if the buffer has a refcount of 1, to
  // avoid double counting when the same buffer is used by multiple nursery
  // strings.
  if (!buffer->HasMultipleReferences()) {
    addMallocedBufferBytes(buffer->AllocationSize());
  }
  return true;
}

inline bool js::Nursery::addExtensibleStringBuffer(
    JSLinearString* s, mozilla::StringBuffer* buffer, bool updateMallocBytes) {
  MOZ_ASSERT(IsInsideNursery(s));
  MOZ_ASSERT(isEnabled());
  if (!extensibleStringBuffers_.putNew(s, buffer)) {
    return false;
  }
  MOZ_ASSERT(!buffer->HasMultipleReferences());
  if (updateMallocBytes) {
    addMallocedBufferBytes(buffer->AllocationSize());
  }
  return true;
}

inline void js::Nursery::removeMallocedBuffer(void* buffer, size_t nbytes) {
  MOZ_ASSERT(!JS::RuntimeHeapIsMinorCollecting());
  MOZ_ASSERT(toSpace.mallocedBuffers.has(buffer));
  MOZ_ASSERT(nbytes > 0);
  MOZ_ASSERT(toSpace.mallocedBufferBytes >= nbytes);
  toSpace.mallocedBuffers.remove(buffer);
  toSpace.mallocedBufferBytes -= nbytes;
}

void js::Nursery::removeMallocedBufferDuringMinorGC(void* buffer) {
  MOZ_ASSERT(JS::RuntimeHeapIsMinorCollecting());
  MOZ_ASSERT(fromSpace.mallocedBuffers.has(buffer));
  fromSpace.mallocedBuffers.remove(buffer);
}

inline void js::Nursery::removeExtensibleStringBuffer(JSLinearString* s,
                                                      bool updateMallocBytes) {
  MOZ_ASSERT(gc::IsInsideNursery(s));
  extensibleStringBuffers_.remove(s);

  if (updateMallocBytes) {
    size_t nbytes = s->stringBuffer()->AllocationSize();
    MOZ_ASSERT(toSpace.mallocedBufferBytes >= nbytes);
    toSpace.mallocedBufferBytes -= nbytes;
  }
}

inline bool js::Nursery::shouldTenure(gc::Cell* cell) {
  MOZ_ASSERT(semispaceEnabled());
  MOZ_ASSERT(inCollectedRegion(cell));

  size_t offset = fromSpace.offsetFromAddress(uintptr_t(cell));
  MOZ_ASSERT(offset >=
             fromSpace.offsetFromExclusiveAddress(fromSpace.startPosition_));
  return offset <= tenureThreshold_;
}

inline bool js::Nursery::inCollectedRegion(gc::Cell* cell) const {
  return gc::InCollectedNurseryRegion(cell);
}

inline bool js::Nursery::inCollectedRegion(void* ptr) const {
  if (!semispaceEnabled()) {
    return toSpace.isInside(ptr);
  }

  return fromSpace.isInside(ptr);
}

inline size_t js::Nursery::Space::offsetFromExclusiveAddress(
    uintptr_t addr) const {
  if ((addr & gc::ChunkMask) == 0) {
    // |addr| points one past the end of the previous chunk.
    return offsetFromAddress(addr - 1) + 1;
  }

  return offsetFromAddress(addr);
}

inline size_t js::Nursery::Space::offsetFromAddress(uintptr_t addr) const {
  gc::ChunkBase* chunk =
      gc::detail::GetCellChunkBase(reinterpret_cast<gc::Cell*>(addr));
  MOZ_ASSERT(chunk->getKind() == kind);
  MOZ_ASSERT(findChunkIndex(addr & ~gc::ChunkMask) == chunk->nurseryChunkIndex);

  uint32_t offset = addr & gc::ChunkMask;
  MOZ_ASSERT(offset >= sizeof(gc::ChunkBase));
  return (chunk->nurseryChunkIndex << gc::ChunkShift) | offset;
}

MOZ_ALWAYS_INLINE /* static */ bool js::Nursery::getForwardedPointer(
    js::gc::Cell** ref) {
  js::gc::Cell* cell = (*ref);
  MOZ_ASSERT(IsInsideNursery(cell));
  if (!cell->isForwarded()) {
    return false;
  }
  const gc::RelocationOverlay* overlay = gc::RelocationOverlay::fromCell(cell);
  *ref = overlay->forwardingAddress();
  return true;
}

inline void js::Nursery::maybeSetForwardingPointer(JSTracer* trc, void* oldData,
                                                   void* newData, bool direct) {
  if (trc->isTenuringTracer()) {
    setForwardingPointerWhileTenuring(oldData, newData, direct);
  }
}

inline void js::Nursery::setForwardingPointerWhileTenuring(void* oldData,
                                                           void* newData,
                                                           bool direct) {
  if (isInside(oldData)) {
    setForwardingPointer(oldData, newData, direct);
  }
}

inline void js::Nursery::setSlotsForwardingPointer(HeapSlot* oldSlots,
                                                   HeapSlot* newSlots,
                                                   uint32_t nslots) {
  // Slot arrays always have enough space for a forwarding pointer, since the
  // number of slots is never zero.
  MOZ_ASSERT(nslots > 0);
  setDirectForwardingPointer(oldSlots, newSlots);
}

inline void js::Nursery::setElementsForwardingPointer(ObjectElements* oldHeader,
                                                      ObjectElements* newHeader,
                                                      uint32_t capacity) {
  // Only use a direct forwarding pointer if there is enough space for one.
  setForwardingPointer(oldHeader->elements(), newHeader->elements(),
                       capacity > 0);
}

inline void js::Nursery::setForwardingPointer(void* oldData, void* newData,
                                              bool direct) {
  if (direct) {
    setDirectForwardingPointer(oldData, newData);
    return;
  }

  setIndirectForwardingPointer(oldData, newData);
}

inline void js::Nursery::setDirectForwardingPointer(void* oldData,
                                                    void* newData) {
  MOZ_ASSERT(isInside(oldData));
  MOZ_ASSERT_IF(isInside(newData), !inCollectedRegion(newData));

  new (oldData) BufferRelocationOverlay{newData};
}

inline void* js::Nursery::tryAllocateCell(gc::AllocSite* site, size_t size,
                                          JS::TraceKind kind) {
  // Ensure there's enough space to replace the contents with a
  // RelocationOverlay.
  // MOZ_ASSERT(size >= sizeof(RelocationOverlay));
  MOZ_ASSERT(size % gc::CellAlignBytes == 0);
  MOZ_ASSERT(size_t(kind) < gc::NurseryTraceKinds);
  MOZ_ASSERT_IF(kind == JS::TraceKind::String, canAllocateStrings());
  MOZ_ASSERT_IF(kind == JS::TraceKind::BigInt, canAllocateBigInts());

  void* ptr = tryAllocate(sizeof(gc::NurseryCellHeader) + size);
  if (MOZ_UNLIKELY(!ptr)) {
    return nullptr;
  }

  new (ptr) gc::NurseryCellHeader(site, kind);

  void* cell =
      reinterpret_cast<void*>(uintptr_t(ptr) + sizeof(gc::NurseryCellHeader));
  if (!cell) {
    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
        "Successful allocation cannot result in nullptr");
  }

  // Update the allocation site. This code is also inlined in
  // MacroAssembler::updateAllocSite.
  uint32_t allocCount = site->incAllocCount();
  if (allocCount == gc::NormalSiteAttentionThreshold) {
    pretenuringNursery.insertIntoAllocatedList(site);
  }
  MOZ_ASSERT_IF(
      site->isNormal() && allocCount >= gc::NormalSiteAttentionThreshold,
      site->isInAllocatedList());

  gc::gcprobes::NurseryAlloc(cell, kind);
  return cell;
}

inline void* js::Nursery::tryAllocate(size_t size) {
  MOZ_ASSERT(isEnabled());
  MOZ_ASSERT_IF(JS::RuntimeHeapIsBusy(), JS::RuntimeHeapIsMinorCollecting());
  MOZ_ASSERT_IF(currentChunk() == startChunk(), position() >= startPosition());
  MOZ_ASSERT(size % gc::CellAlignBytes == 0);
  MOZ_ASSERT(position() % gc::CellAlignBytes == 0);

  if (MOZ_UNLIKELY(currentEnd() < position() + size)) {
    return nullptr;
  }

  void* ptr = reinterpret_cast<void*>(position());
  if (!ptr) {
    MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
        "Successful allocation cannot result in nullptr");
  }

  toSpace.position_ = position() + size;

  DebugOnlyPoison(ptr, JS_ALLOCATED_NURSERY_PATTERN, size,
                  MemCheckKind::MakeUndefined);

  return ptr;
}

inline bool js::Nursery::registerTrailer(PointerAndUint7 blockAndListID,
                                         size_t nBytes) {
  MOZ_ASSERT(toSpace.trailersAdded_.length() ==
             toSpace.trailersRemoved_.length());
  MOZ_ASSERT(nBytes > 0);
  if (MOZ_UNLIKELY(!toSpace.trailersAdded_.append(blockAndListID))) {
    return false;
  }
  if (MOZ_UNLIKELY(!toSpace.trailersRemoved_.append(nullptr))) {
    toSpace.trailersAdded_.popBack();
    return false;
  }

  // This is a clone of the logic in ::registerMallocedBuffer.  It may be
  // that some other heuristic is better, once we know more about the
  // typical behaviour of wasm-GC applications.
  toSpace.trailerBytes_ += nBytes;
  if (MOZ_UNLIKELY(toSpace.trailerBytes_ > capacity() * 8)) {
    requestMinorGC(JS::GCReason::NURSERY_TRAILERS);
  }
  return true;
}

inline void js::Nursery::unregisterTrailer(void* block) {
  // Unlike removeMallocedBuffer this is only called during minor GC.
  MOZ_ASSERT(fromSpace.trailersRemovedUsed_ <
             fromSpace.trailersRemoved_.length());
  fromSpace.trailersRemoved_[fromSpace.trailersRemovedUsed_] = block;
  fromSpace.trailersRemovedUsed_++;
}

namespace js {

// The allocation methods below will not run the garbage collector. If the
// nursery cannot accomodate the allocation, the malloc heap will be used
// instead.

template <typename T>
static inline T* AllocNurseryOrMallocBuffer(Nursery& nursery, gc::Cell* cell,
                                            uint32_t count) {
  size_t nbytes = RoundUp(count * sizeof(T), sizeof(Value));
  return static_cast<T*>(nursery.allocNurseryOrMallocBuffer(
      cell->zone(), cell, nbytes, js::MallocArena));
}

template <typename T>
static inline T* AllocNurseryOrMallocBuffer(JSContext* cx, gc::Cell* cell,
                                            uint32_t count) {
  T* buffer = AllocNurseryOrMallocBuffer<T>(cx->nursery(), cell, count);
  if (!buffer) {
    ReportOutOfMemory(cx);
    return nullptr;
  }

  return buffer;
}

template <typename T>
static inline T* AllocateCellBuffer(Nursery& nursery, JS::Zone* zone,
                                    gc::Cell* cell, uint32_t count) {
  MOZ_ASSERT(zone == cell->zone());

  size_t nbytes = RoundUp(count * sizeof(T), sizeof(Value));
  return static_cast<T*>(nursery.allocateBuffer(zone, cell, nbytes));
}

template <typename T>
static inline T* AllocateCellBuffer(JSContext* cx, gc::Cell* cell,
                                    uint32_t count) {
  T* buffer = AllocateCellBuffer<T>(cx->nursery(), cx->zone(), cell, count);
  if (!buffer) {
    ReportOutOfMemory(cx);
    return nullptr;
  }

  return buffer;
}

// If this returns null then the old buffer will be left alone.
template <typename T>
static inline T* ReallocNurseryOrMallocBuffer(JSContext* cx, gc::Cell* cell,
                                              T* oldBuffer, uint32_t oldCount,
                                              uint32_t newCount,
                                              arena_id_t arenaId) {
  size_t oldBytes = RoundUp(oldCount * sizeof(T), sizeof(Value));
  size_t newBytes = RoundUp(newCount * sizeof(T), sizeof(Value));

  T* buffer = static_cast<T*>(cx->nursery().reallocNurseryOrMallocBuffer(
      cell->zone(), cell, oldBuffer, oldBytes, newBytes, arenaId));
  if (!buffer) {
    ReportOutOfMemory(cx);
  }

  return buffer;
}

// If this returns null then the old buffer will be left alone.
template <typename T>
static inline T* ReallocateCellBuffer(Nursery& nursery, JS::Zone* zone,
                                      gc::Cell* cell, T* oldBuffer,
                                      uint32_t oldCount, uint32_t newCount) {
  MOZ_ASSERT(zone == cell->zone());

  size_t oldBytes = RoundUp(oldCount * sizeof(T), sizeof(Value));
  size_t newBytes = RoundUp(newCount * sizeof(T), sizeof(Value));

  return static_cast<T*>(
      nursery.reallocateBuffer(zone, cell, oldBuffer, oldBytes, newBytes));
}

// If this returns null then the old buffer will be left alone.
template <typename T>
static inline T* ReallocateCellBuffer(JSContext* cx, gc::Cell* cell,
                                      T* oldBuffer, uint32_t oldCount,
                                      uint32_t newCount) {
  T* buffer = ReallocateCellBuffer<T>(cx->nursery(), cx->zone(), cell,
                                      oldBuffer, oldCount, newCount);
  if (!buffer) {
    ReportOutOfMemory(cx);
  }

  return buffer;
}

}  // namespace js

#endif /* gc_Nursery_inl_h */

Messung V0.5
C=93 H=100 G=96

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge