Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  WeakMap.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/WeakMap-inl.h"

#include "gc/PublicIterators.h"
#include "vm/JSObject.h"

#include "gc/AtomMarking-inl.h"
#include "gc/Marking-inl.h"
#include "gc/StoreBuffer-inl.h"

using namespace js;
using namespace js::gc;

void js::gc::MarkSymbolForWeakMapReadBarrier(JS::Zone* zone, JS::Symbol* sym) {
  MOZ_ASSERT(zone && !zone->isAtomsZone());
  zone->runtimeFromMainThread()->gc.atomMarking.inlinedMarkAtom(zone, sym);
}

WeakMapBase::WeakMapBase(JSObject* memOf, Zone* zone)
    : memberOf(memOf), zone_(zone) {
  MOZ_ASSERT_IF(memberOf, memberOf->compartment()->zone() == zone);
  MOZ_ASSERT(!isMarked());

  if (zone->isGCMarking()) {
    setMapColor(CellColor::Black);
  }

  SlimLinkedList<WeakMapBase>* list;
  if (isSystem()) {
    list = &zone->gcSystemWeakMaps();
  } else if (isMarked()) {
    list = &zone->gcMarkedUserWeakMaps();
  } else {
    list = &zone->gcUserWeakMaps();
  }

#ifdef JS_GC_CONCURRENT_MARKING
  // Lock if background thread is marking concurrently.
  mozilla::Maybe<AutoLockGC> lock;
  if (!isSystem() && zone->needsMarkingBarrier(Zone::Concurrent)) {
    lock.emplace(zone->runtimeFromMainThread());
  }
#endif

  list->pushFront(this);
}

void WeakMapBase::unmarkZone(JS::Zone* zone) {
  zone->gcEphemeronEdges().clearAndCompact();
  ForAllWeakMapsInZone(
      zone, [](WeakMapBase* map) { map->setMapColor(CellColor::White); });
  zone->gcUserWeakMaps().append(std::move(zone->gcMarkedUserWeakMaps()));
  MOZ_ASSERT(zone->gcMarkedUserWeakMaps().isEmpty());
}

#ifdef DEBUG
void WeakMapBase::checkZoneUnmarked(JS::Zone* zone) {
  MOZ_ASSERT(zone->gcEphemeronEdges().empty());
  MOZ_ASSERT(zone->gcMarkedUserWeakMaps().isEmpty());
  ForAllWeakMapsInZone(zone, [](WeakMapBase* map) {
    MOZ_ASSERT(map->mapColor() == CellColor::White);
  });
}
#endif

void Zone::traceWeakMaps(JSTracer* trc) {
  MOZ_ASSERT(trc->weakMapAction() != JS::WeakMapTraceAction::Skip);
  ForAllWeakMapsInZone(this, [trc](WeakMapBase* map) { map->trace(trc); });
}

mozilla::Maybe<CellColor> WeakMapBase::markMap(MarkColor markColor) {
  // We may be marking in parallel here so use a compare exchange loop to handle
  // concurrent updates to the map color.
  //
  // The color increases monotonically; we don't downgrade from black to gray.
  //
  // We can attempt to mark gray after marking black when a barrier pushes the
  // map object onto the black mark stack when it's already present on the
  // gray mark stack, since this is marked later.

  uint32_t targetColor = uint32_t(markColor);

  for (;;) {
    uint32_t currentColor = mapColor_;

    if (currentColor >= targetColor) {
      return mozilla::Nothing();
    }

    if (mapColor_.compareExchange(currentColor, targetColor)) {
      return mozilla::Some(CellColor(currentColor));
    }
  }
}

bool WeakMapBase::addEphemeronEdgesForEntry(MarkColor mapColor,
                                            TenuredCell* key, Cell* delegate,
                                            TenuredCell* value) {
  if (delegate) {
    if (!delegate->isTenured()) {
      MOZ_ASSERT(false);
      // This case is probably not possible, or wasn't at the time of this
      // writing. It requires a tenured wrapper with a nursery wrappee delegate,
      // which is tough to create given that the wrapper has to be created after
      // its target, and in fact appears impossible because the delegate has to
      // be created after the GC begins to avoid being tenured at the beginning
      // of the GC, and adding the key to the weakmap will mark the key via a
      // pre-barrier. But still, handling this case is straightforward:

      // The delegate is already being kept alive in a minor GC since it has an
      // edge from a tenured cell (the key). Make sure the key stays alive too.
      delegate->storeBuffer()->putWholeCell(key);
    } else if (!addEphemeronEdge(mapColor, &delegate->asTenured(), key)) {
      return false;
    }
  }

  if (value && !addEphemeronEdge(mapColor, key, value)) {
    return false;
  }

  return true;
}

bool WeakMapBase::addEphemeronEdge(MarkColor color, gc::TenuredCell* src,
                                   gc::TenuredCell* dst) {
  // Add an implicit edge from |src| to |dst|.

  auto& edgeTable = src->zone()->gcEphemeronEdges();
  auto p = edgeTable.lookupForAdd(src);
  if (!p) {
    if (!edgeTable.add(p, src, EphemeronEdgeVector())) {
      return false;
    }
  }
  return p->value().emplaceBack(color, dst);
}

#if defined(JS_GC_ZEAL) || defined(DEBUG)
bool WeakMapBase::checkMarkingForZone(JS::Zone* zone) {
  // This is called at the end of marking.
  MOZ_ASSERT(zone->isGCMarking());

  bool ok = true;
  ForAllWeakMapsInZone(zone, [&ok](WeakMapBase* map) {
    if (map->isMarked() && !map->checkMarking()) {
      ok = false;
    }
  });

  return ok;
}
#endif

#ifdef JSGC_HASH_TABLE_CHECKS
/* static */
void WeakMapBase::checkWeakMapsAfterMovingGC(JS::Zone* zone) {
  ForAllWeakMapsInZone(zone,
                       [](WeakMapBase* map) { map->checkAfterMovingGC(); });
}
#endif

bool WeakMapBase::markZoneIteratively(JS::Zone* zone, GCMarker* marker) {
  MOZ_ASSERT(zone->isGCMarking());

  bool markedAny = false;
  ForAllWeakMapsInZone(zone, [&](WeakMapBase* map) {
    if (map->isMarked() && map->markEntries(marker)) {
      markedAny = true;
    }
  });
  return markedAny;
}

bool WeakMapBase::findSweepGroupEdgesForZone(JS::Zone* atomsZone,
                                             JS::Zone* mapZone) {
#ifdef DEBUG
  ForAllWeakMapsInZone(mapZone,
                       [](WeakMapBase* map) { map->checkCachedFlags(); });
#endif

  // Because this might involve iterating over all weakmap edges in the zone we
  // cache some information on the zone to allow us to avoid it if possible.
  //
  //  - mapZone->gcWeakMapsMayHaveSymbolKeys() is set if any weakmap may have
  //    symbol keys
  //
  //  - mapZone->gcUserWeakMapsMayHaveKeyDelegates() is set if any user weakmap
  //    may have key delegates
  //
  //  It's assumed that system weakmaps may have key delegates so these are
  //  always scanned. There are a limited number of these.

  if (mapZone->gcWeakMapsMayHaveSymbolKeys()) {
    MOZ_ASSERT(JS::Prefs::experimental_symbols_as_weakmap_keys());
    if (atomsZone->isGCMarking()) {
      if (!atomsZone->addSweepGroupEdgeTo(mapZone)) {
        return false;
      }
    }
  }

  for (WeakMapBase* map : mapZone->gcSystemWeakMaps()) {
    if (!map->findSweepGroupEdges(atomsZone)) {
      return false;
    }
  }

  if (mapZone->gcUserWeakMapsMayHaveKeyDelegates()) {
    for (WeakMapBase* map : mapZone->gcMarkedUserWeakMaps()) {
      if (!map->findSweepGroupEdges(atomsZone)) {
        return false;
      }
    }
    for (WeakMapBase* map : mapZone->gcUserWeakMaps()) {
      if (!map->findSweepGroupEdges(atomsZone)) {
        return false;
      }
    }
  }

  return true;
}

void Zone::sweepWeakMaps(JSTracer* trc) {
  MOZ_ASSERT(isGCSweeping());

  // These flags will be recalculated during sweeping.
  clearGCCachedWeakMapKeyData();

  // Sweep all system weakmaps.
  WeakMapBase* weakmap = gcSystemWeakMaps().getFirst();
  while (weakmap) {
    WeakMapBase* next = weakmap->getNext();
    if (weakmap->isMarked()) {
      // Sweep live map to remove dead entries.
      weakmap->traceWeakEdgesDuringSweeping(trc);
      // Unmark swept weak map.
      weakmap->setMapColor(CellColor::White);
    } else {
      // Clean up system weak maps now. This may remove store buffer entries.
      // TODO: Is this still necessary? There should be no nursery entries.
      AutoLockSweepingLock lock(trc->runtime());
      weakmap->clearAndCompact();
      gcSystemWeakMaps().remove(weakmap);
    }
    weakmap = next;
  }

  // Sweep marked user weakmaps.
  for (WeakMapBase* weakmap : gcMarkedUserWeakMaps()) {
    MOZ_ASSERT(weakmap->isMarked());
    MOZ_ASSERT(weakmap->memberOf->isMarkedAny());
    // Sweep live map to remove dead entries.
    weakmap->traceWeakEdgesDuringSweeping(trc);
    // Unmark swept weak map.
    weakmap->setMapColor(CellColor::White);
  }

  // Remove all dead user weakmaps without iterating the list. The data will be
  // cleaned up when their owning objects are finalized. This assumes user
  // weakmaps are allocated using the buffer allocator which will recover the
  // memory without explicit free.
#ifdef DEBUG
  for (WeakMapBase* weakmap : gcUserWeakMaps()) {
    MOZ_ASSERT(!weakmap->isMarked());
    MOZ_ASSERT(!weakmap->memberOf->isMarkedAny());
  }
#endif
  new (&gcUserWeakMaps()) SlimLinkedList<WeakMapBase>();
  gcUserWeakMaps() = std::move(gcMarkedUserWeakMaps());

  WeakMapBase::checkZoneUnmarked(this);
}

void WeakMapBase::traceAllMappings(WeakMapTracer* tracer) {
  JSRuntime* rt = tracer->runtime;
  for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
    ForAllWeakMapsInZone(zone, [tracer](WeakMapBase* map) {
      // The WeakMapTracer callback is not allowed to GC.
      JS::AutoSuppressGCAnalysis nogc;
      map->traceMappings(tracer);
    });
  }
}

#if defined(JS_GC_ZEAL)

bool WeakMapBase::saveZoneMarkedWeakMaps(JS::Zone* zone,
                                         WeakMapColors& markedWeakMaps) {
  bool ok = true;
  ForAllWeakMapsInZone(zone, [&](WeakMapBase* map) {
    if (!markedWeakMaps.put(map, map->mapColor())) {
      ok = false;
    }
  });
  return ok;
}

void WeakMapBase::restoreMarkedWeakMaps(WeakMapColors& markedWeakMaps) {
  for (auto iter = markedWeakMaps.iter(); !iter.done(); iter.next()) {
    WeakMapBase* map = iter.get().key();
    MOZ_ASSERT(!map->isMarked());

    Zone* zone = map->zone();
    MOZ_ASSERT(zone->isGCMarking());

    CellColor color = iter.get().value();
    if (IsMarked(color)) {
      map->setMapColor(color);
      if (!map->isSystem()) {
        zone->gcUserWeakMaps().remove(map);
        zone->gcMarkedUserWeakMaps().pushFront(map);
      }
    }
  }
}

#endif  // JS_GC_ZEAL

void WeakMapBase::setHasNurseryEntries() {
  MOZ_ASSERT(!hasNurseryEntries);

  AutoEnterOOMUnsafeRegion oomUnsafe;

  GCRuntime* gc = &zone()->runtimeFromMainThread()->gc;
  if (!gc->nursery().addWeakMapWithNurseryEntries(this)) {
    oomUnsafe.crash("WeakMapBase::setHasNurseryEntries");
  }

  hasNurseryEntries = true;
}

Messung V0.5 in Prozent
C=86 H=83 G=83

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-08-24) ¤

*© 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