tor-browser

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

PublicIterators.cpp (9347B)


      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/GCInternals.h"
      8 #include "gc/GCLock.h"
      9 #include "vm/Realm.h"
     10 #include "vm/Runtime.h"
     11 
     12 #include "gc/PrivateIterators-inl.h"
     13 
     14 using namespace js;
     15 using namespace js::gc;
     16 
     17 static void IterateRealmsArenasCellsUnbarriered(
     18    JSContext* cx, Zone* zone, void* data,
     19    JS::IterateRealmCallback realmCallback, IterateArenaCallback arenaCallback,
     20    IterateCellCallback cellCallback, const JS::AutoRequireNoGC& nogc) {
     21  {
     22    Rooted<Realm*> realm(cx);
     23    for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
     24      realm = r;
     25      (*realmCallback)(cx, data, realm, nogc);
     26    }
     27  }
     28 
     29  for (auto thingKind : AllAllocKinds()) {
     30    JS::TraceKind traceKind = MapAllocToTraceKind(thingKind);
     31    size_t thingSize = Arena::thingSize(thingKind);
     32 
     33    for (ArenaIter aiter(zone, thingKind); !aiter.done(); aiter.next()) {
     34      Arena* arena = aiter.get();
     35      (*arenaCallback)(cx->runtime(), data, arena, traceKind, thingSize, nogc);
     36      for (ArenaCellIter cell(arena); !cell.done(); cell.next()) {
     37        (*cellCallback)(cx->runtime(), data, JS::GCCellPtr(cell, traceKind),
     38                        thingSize, nogc);
     39      }
     40    }
     41  }
     42 }
     43 
     44 void js::IterateHeapUnbarriered(JSContext* cx, void* data,
     45                                IterateZoneCallback zoneCallback,
     46                                JS::IterateRealmCallback realmCallback,
     47                                IterateArenaCallback arenaCallback,
     48                                IterateCellCallback cellCallback,
     49                                const js::gc::AutoTraceSession& session) {
     50  auto iterateZone = [&](Zone* zone) -> void {
     51    JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
     52    (*zoneCallback)(cx->runtime(), data, zone, session);
     53    IterateRealmsArenasCellsUnbarriered(cx, zone, data, realmCallback,
     54                                        arenaCallback, cellCallback, session);
     55  };
     56 
     57  // Include the shared atoms zone if present.
     58  if (Zone* zone = cx->runtime()->gc.maybeSharedAtomsZone()) {
     59    iterateZone(zone);
     60  }
     61 
     62  for (ZonesIter zone(cx->runtime(), WithAtoms); !zone.done(); zone.next()) {
     63    iterateZone(zone);
     64  }
     65 }
     66 
     67 void js::IterateHeapUnbarrieredForZone(
     68    JSContext* cx, Zone* zone, void* data, IterateZoneCallback zoneCallback,
     69    JS::IterateRealmCallback realmCallback, IterateArenaCallback arenaCallback,
     70    IterateCellCallback cellCallback, const js::gc::AutoTraceSession& session) {
     71  JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
     72  (*zoneCallback)(cx->runtime(), data, zone, session);
     73  IterateRealmsArenasCellsUnbarriered(cx, zone, data, realmCallback,
     74                                      arenaCallback, cellCallback, session);
     75 }
     76 
     77 void js::IterateChunks(JSContext* cx, void* data,
     78                       IterateChunkCallback chunkCallback,
     79                       const js::gc::AutoTraceSession& session) {
     80  AutoLockGC lock(cx->runtime());
     81 
     82  for (auto chunk = cx->runtime()->gc.allNonEmptyChunks(lock); !chunk.done();
     83       chunk.next()) {
     84    JS::AutoSuppressGCAnalysis nogc(cx);
     85    chunkCallback(cx->runtime(), data, chunk, session);
     86  }
     87 }
     88 
     89 static void TraverseInnerLazyScriptsForLazyScript(
     90    JSContext* cx, void* data, BaseScript* enclosingScript,
     91    IterateScriptCallback lazyScriptCallback, const JS::AutoRequireNoGC& nogc) {
     92  for (JS::GCCellPtr gcThing : enclosingScript->gcthings()) {
     93    if (!gcThing.is<JSObject>()) {
     94      continue;
     95    }
     96    JSObject* obj = &gcThing.as<JSObject>();
     97 
     98    MOZ_ASSERT(obj->is<JSFunction>(),
     99               "All objects in lazy scripts should be functions");
    100    JSFunction* fun = &obj->as<JSFunction>();
    101 
    102    if (!fun->hasBaseScript()) {
    103      // Ignore asm.js.
    104      continue;
    105    }
    106    MOZ_ASSERT(fun->baseScript());
    107    if (!fun->baseScript()) {
    108      // If the function doesn't have script, ignore it.
    109      continue;
    110    }
    111 
    112    if (fun->hasBytecode()) {
    113      // Ignore non lazy function.
    114      continue;
    115    }
    116 
    117    // If the function is "ghost", we shouldn't expose it to the debugger.
    118    //
    119    // See GHOST_FUNCTION in FunctionFlags.h for more details.
    120    if (fun->isGhost()) {
    121      continue;
    122    }
    123 
    124    BaseScript* script = fun->baseScript();
    125    MOZ_ASSERT_IF(script->hasEnclosingScript(),
    126                  script->enclosingScript() == enclosingScript);
    127 
    128    {
    129      JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
    130      lazyScriptCallback(cx->runtime(), data, script, nogc);
    131    }
    132 
    133    TraverseInnerLazyScriptsForLazyScript(cx, data, script, lazyScriptCallback,
    134                                          nogc);
    135  }
    136 }
    137 
    138 static inline void DoScriptCallback(JSContext* cx, void* data,
    139                                    BaseScript* script,
    140                                    IterateScriptCallback callback,
    141                                    const JS::AutoRequireNoGC& nogc) {
    142  // Exclude any scripts that may be the result of a failed compile. Check that
    143  // script either has bytecode or is ready to delazify.
    144  //
    145  // This excludes lazy scripts that do not have an enclosing scope because we
    146  // cannot distinguish a failed compile fragment from a lazy script with a lazy
    147  // parent.
    148  if (!script->hasBytecode() && !script->isReadyForDelazification()) {
    149    return;
    150  }
    151 
    152  // Invoke callback.
    153  {
    154    JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
    155    callback(cx->runtime(), data, script, nogc);
    156  }
    157 
    158  // The check above excluded lazy scripts with lazy parents, so explicitly
    159  // visit inner scripts now if we are lazy with a successfully compiled parent.
    160  if (!script->hasBytecode()) {
    161    TraverseInnerLazyScriptsForLazyScript(cx, data, script, callback, nogc);
    162  }
    163 }
    164 
    165 void js::IterateScripts(JSContext* cx, Realm* realm, void* data,
    166                        IterateScriptCallback scriptCallback) {
    167  MOZ_ASSERT(!cx->suppressGC);
    168  AutoEmptyNurseryAndPrepareForTracing session(cx);
    169 
    170  if (realm) {
    171    Zone* zone = realm->zone();
    172    for (auto iter = zone->cellIter<BaseScript>(session); !iter.done();
    173         iter.next()) {
    174      if (iter->realm() != realm) {
    175        continue;
    176      }
    177      DoScriptCallback(cx, data, iter.get(), scriptCallback, session);
    178    }
    179  } else {
    180    for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) {
    181      for (auto iter = zone->cellIter<BaseScript>(session); !iter.done();
    182           iter.next()) {
    183        DoScriptCallback(cx, data, iter.get(), scriptCallback, session);
    184      }
    185    }
    186  }
    187 }
    188 
    189 void js::IterateGrayObjects(Zone* zone, IterateGCThingCallback cellCallback,
    190                            void* data) {
    191  MOZ_ASSERT(!JS::RuntimeHeapIsBusy());
    192 
    193  JSContext* cx = TlsContext.get();
    194  AutoPrepareForTracing session(cx);
    195  JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
    196 
    197  for (auto kind : ObjectAllocKinds()) {
    198    for (GrayObjectIter obj(zone, kind); !obj.done(); obj.next()) {
    199      if (obj->asTenured().isMarkedGray()) {
    200        cellCallback(data, JS::GCCellPtr(obj.get()), session);
    201      }
    202    }
    203  }
    204 }
    205 
    206 JS_PUBLIC_API void JS_IterateCompartments(
    207    JSContext* cx, void* data,
    208    JSIterateCompartmentCallback compartmentCallback) {
    209  AutoTraceSession session(cx->runtime());
    210 
    211  for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) {
    212    JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
    213    if ((*compartmentCallback)(cx, data, c) ==
    214        JS::CompartmentIterResult::Stop) {
    215      break;
    216    }
    217  }
    218 }
    219 
    220 JS_PUBLIC_API void JS_IterateCompartmentsInZone(
    221    JSContext* cx, JS::Zone* zone, void* data,
    222    JSIterateCompartmentCallback compartmentCallback) {
    223  AutoTraceSession session(cx->runtime());
    224 
    225  for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) {
    226    JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
    227    if ((*compartmentCallback)(cx, data, c) ==
    228        JS::CompartmentIterResult::Stop) {
    229      break;
    230    }
    231  }
    232 }
    233 
    234 JS_PUBLIC_API void JS::IterateRealms(JSContext* cx, void* data,
    235                                     JS::IterateRealmCallback realmCallback) {
    236  AutoTraceSession session(cx->runtime());
    237  JS::AutoSuppressGCAnalysis nogc(cx);
    238 
    239  Rooted<Realm*> realm(cx);
    240  for (RealmsIter r(cx->runtime()); !r.done(); r.next()) {
    241    realm = r;
    242    (*realmCallback)(cx, data, realm, nogc);
    243  }
    244 }
    245 
    246 JS_PUBLIC_API void JS::IterateRealmsWithPrincipals(
    247    JSContext* cx, JSPrincipals* principals, void* data,
    248    JS::IterateRealmCallback realmCallback) {
    249  MOZ_ASSERT(principals);
    250 
    251  AutoTraceSession session(cx->runtime());
    252  JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
    253 
    254  Rooted<Realm*> realm(cx);
    255  for (RealmsIter r(cx->runtime()); !r.done(); r.next()) {
    256    if (r->principals() != principals) {
    257      continue;
    258    }
    259    realm = r;
    260    (*realmCallback)(cx, data, realm, session);
    261  }
    262 }
    263 
    264 JS_PUBLIC_API void JS::IterateRealmsInCompartment(
    265    JSContext* cx, JS::Compartment* compartment, void* data,
    266    JS::IterateRealmCallback realmCallback) {
    267  AutoTraceSession session(cx->runtime());
    268  JS::AutoSuppressGCAnalysis callingSafeCallback(cx);
    269 
    270  Rooted<Realm*> realm(cx);
    271  for (RealmsInCompartmentIter r(compartment); !r.done(); r.next()) {
    272    realm = r;
    273    (*realmCallback)(cx, data, realm, session);
    274  }
    275 }