tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WeakMap.cpp (6506B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "gc/WeakMap-inl.h"
      8 
      9 #include <string.h>
     10 
     11 #include "gc/PublicIterators.h"
     12 #include "vm/JSObject.h"
     13 
     14 #include "gc/Marking-inl.h"
     15 #include "gc/StoreBuffer-inl.h"
     16 
     17 using namespace js;
     18 using namespace js::gc;
     19 
     20 WeakMapBase::WeakMapBase(JSObject* memOf, Zone* zone)
     21    : memberOf(memOf), zone_(zone) {
     22  MOZ_ASSERT_IF(memberOf, memberOf->compartment()->zone() == zone);
     23  MOZ_ASSERT(!IsMarked(mapColor()));
     24 }
     25 
     26 void WeakMapBase::unmarkZone(JS::Zone* zone) {
     27  zone->gcEphemeronEdges().clearAndCompact();
     28  for (WeakMapBase* m : zone->gcWeakMapList()) {
     29    m->setMapColor(CellColor::White);
     30  }
     31 }
     32 
     33 void Zone::traceWeakMaps(JSTracer* trc) {
     34  MOZ_ASSERT(trc->weakMapAction() != JS::WeakMapTraceAction::Skip);
     35  for (WeakMapBase* m : gcWeakMapList()) {
     36    m->trace(trc);
     37    TraceNullableEdge(trc, &m->memberOf, "memberOf");
     38  }
     39 }
     40 
     41 bool WeakMapBase::markMap(MarkColor markColor) {
     42  // We may be marking in parallel here so use a compare exchange loop to handle
     43  // concurrent updates to the map color.
     44  //
     45  // The color increases monotonically; we don't downgrade from black to gray.
     46  //
     47  // We can attempt to mark gray after marking black when a barrier pushes the
     48  // map object onto the black mark stack when it's already present on the
     49  // gray mark stack, since this is marked later.
     50 
     51  uint32_t targetColor = uint32_t(markColor);
     52 
     53  for (;;) {
     54    uint32_t currentColor = mapColor_;
     55 
     56    if (currentColor >= targetColor) {
     57      return false;
     58    }
     59 
     60    if (mapColor_.compareExchange(currentColor, targetColor)) {
     61      return true;
     62    }
     63  }
     64 }
     65 
     66 bool WeakMapBase::addEphemeronEdgesForEntry(MarkColor mapColor,
     67                                            TenuredCell* key, Cell* delegate,
     68                                            TenuredCell* value) {
     69  if (delegate) {
     70    if (!delegate->isTenured()) {
     71      MOZ_ASSERT(false);
     72      // This case is probably not possible, or wasn't at the time of this
     73      // writing. It requires a tenured wrapper with a nursery wrappee delegate,
     74      // which is tough to create given that the wrapper has to be created after
     75      // its target, and in fact appears impossible because the delegate has to
     76      // be created after the GC begins to avoid being tenured at the beginning
     77      // of the GC, and adding the key to the weakmap will mark the key via a
     78      // pre-barrier. But still, handling this case is straightforward:
     79 
     80      // The delegate is already being kept alive in a minor GC since it has an
     81      // edge from a tenured cell (the key). Make sure the key stays alive too.
     82      delegate->storeBuffer()->putWholeCell(key);
     83    } else if (!addEphemeronEdge(mapColor, &delegate->asTenured(), key)) {
     84      return false;
     85    }
     86  }
     87 
     88  if (value && !addEphemeronEdge(mapColor, key, value)) {
     89    return false;
     90  }
     91 
     92  return true;
     93 }
     94 
     95 bool WeakMapBase::addEphemeronEdge(MarkColor color, gc::TenuredCell* src,
     96                                   gc::TenuredCell* dst) {
     97  // Add an implicit edge from |src| to |dst|.
     98 
     99  auto& edgeTable = src->zone()->gcEphemeronEdges();
    100  auto p = edgeTable.lookupForAdd(src);
    101  if (!p) {
    102    if (!edgeTable.add(p, src, EphemeronEdgeVector())) {
    103      return false;
    104    }
    105  }
    106  return p->value().emplaceBack(color, dst);
    107 }
    108 
    109 #if defined(JS_GC_ZEAL) || defined(DEBUG)
    110 bool WeakMapBase::checkMarkingForZone(JS::Zone* zone) {
    111  // This is called at the end of marking.
    112  MOZ_ASSERT(zone->isGCMarking());
    113 
    114  bool ok = true;
    115  for (WeakMapBase* m : zone->gcWeakMapList()) {
    116    if (IsMarked(m->mapColor()) && !m->checkMarking()) {
    117      ok = false;
    118    }
    119  }
    120 
    121  return ok;
    122 }
    123 #endif
    124 
    125 #ifdef JSGC_HASH_TABLE_CHECKS
    126 /* static */
    127 void WeakMapBase::checkWeakMapsAfterMovingGC(JS::Zone* zone) {
    128  for (WeakMapBase* map : zone->gcWeakMapList()) {
    129    map->checkAfterMovingGC();
    130  }
    131 }
    132 #endif
    133 
    134 bool WeakMapBase::markZoneIteratively(JS::Zone* zone, GCMarker* marker) {
    135  bool markedAny = false;
    136  for (WeakMapBase* m : zone->gcWeakMapList()) {
    137    if (IsMarked(m->mapColor()) && m->markEntries(marker)) {
    138      markedAny = true;
    139    }
    140  }
    141  return markedAny;
    142 }
    143 
    144 bool WeakMapBase::findSweepGroupEdgesForZone(JS::Zone* atomsZone,
    145                                             JS::Zone* mapZone) {
    146  for (WeakMapBase* m : mapZone->gcWeakMapList()) {
    147    if (!m->findSweepGroupEdges(atomsZone)) {
    148      return false;
    149    }
    150  }
    151  return true;
    152 }
    153 
    154 void Zone::sweepWeakMaps(JSTracer* trc) {
    155  for (WeakMapBase* m = gcWeakMapList().getFirst(); m;) {
    156    WeakMapBase* next = m->getNext();
    157    if (IsMarked(m->mapColor())) {
    158      m->traceWeakEdges(trc);
    159    } else {
    160      m->clearAndCompact();
    161      m->removeFrom(gcWeakMapList());
    162    }
    163    m = next;
    164  }
    165 
    166 #ifdef DEBUG
    167  for (WeakMapBase* m : gcWeakMapList()) {
    168    MOZ_ASSERT(m->isInList() && IsMarked(m->mapColor()));
    169  }
    170 #endif
    171 }
    172 
    173 void WeakMapBase::traceAllMappings(WeakMapTracer* tracer) {
    174  JSRuntime* rt = tracer->runtime;
    175  for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
    176    for (WeakMapBase* m : zone->gcWeakMapList()) {
    177      // The WeakMapTracer callback is not allowed to GC.
    178      JS::AutoSuppressGCAnalysis nogc;
    179      m->traceMappings(tracer);
    180    }
    181  }
    182 }
    183 
    184 bool WeakMapBase::saveZoneMarkedWeakMaps(JS::Zone* zone,
    185                                         WeakMapColors& markedWeakMaps) {
    186  for (WeakMapBase* m : zone->gcWeakMapList()) {
    187    if (IsMarked(m->mapColor()) && !markedWeakMaps.put(m, m->mapColor())) {
    188      return false;
    189    }
    190  }
    191  return true;
    192 }
    193 
    194 void WeakMapBase::restoreMarkedWeakMaps(WeakMapColors& markedWeakMaps) {
    195  for (WeakMapColors::Range r = markedWeakMaps.all(); !r.empty();
    196       r.popFront()) {
    197    WeakMapBase* map = r.front().key();
    198    MOZ_ASSERT(map->zone()->isGCMarking());
    199    MOZ_ASSERT(!IsMarked(map->mapColor()));
    200    map->setMapColor(r.front().value());
    201  }
    202 }
    203 
    204 void WeakMapBase::setHasNurseryEntries() {
    205  MOZ_ASSERT(!hasNurseryEntries);
    206 
    207  AutoEnterOOMUnsafeRegion oomUnsafe;
    208 
    209  GCRuntime* gc = &zone()->runtimeFromMainThread()->gc;
    210  if (!gc->nursery().addWeakMapWithNurseryEntries(this)) {
    211    oomUnsafe.crash("WeakMapBase::setHasNurseryEntries");
    212  }
    213 
    214  hasNurseryEntries = true;
    215 }
    216 
    217 namespace js {
    218 template class WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>;
    219 }  // namespace js