tor-browser

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

GCInternals.h (9817B)


      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 /*
      8 * GC-internal definitions.
      9 */
     10 
     11 #ifndef gc_GCInternals_h
     12 #define gc_GCInternals_h
     13 
     14 #include "mozilla/Maybe.h"
     15 #include "mozilla/Range.h"
     16 #include "mozilla/TimeStamp.h"
     17 #include "mozilla/Vector.h"
     18 
     19 #include "gc/Cell.h"
     20 #include "gc/GC.h"
     21 #include "gc/GCContext.h"
     22 #include "gc/GCMarker.h"
     23 #include "vm/GeckoProfiler.h"
     24 #include "vm/HelperThreads.h"
     25 #include "vm/JSContext.h"
     26 
     27 namespace js {
     28 
     29 class GCMarker;
     30 
     31 namespace gc {
     32 
     33 /*
     34 * There are a couple of classes here that serve mostly as "tokens" indicating
     35 * that a precondition holds. Some functions force the caller to possess such a
     36 * token because they require the precondition to hold, and it is better to make
     37 * the precondition explicit at the API entry point than to crash in an
     38 * assertion later on when it is relied upon.
     39 */
     40 
     41 struct MOZ_RAII AutoAssertNoNurseryAlloc {
     42 #ifdef DEBUG
     43  AutoAssertNoNurseryAlloc();
     44  ~AutoAssertNoNurseryAlloc();
     45 #else
     46  AutoAssertNoNurseryAlloc() {}
     47 #endif
     48 };
     49 
     50 /*
     51 * A class that serves as a token that the nursery in the current thread's zone
     52 * group is empty.
     53 */
     54 class MOZ_RAII AutoAssertEmptyNursery {
     55 protected:
     56  JSContext* cx;
     57 
     58  mozilla::Maybe<AutoAssertNoNurseryAlloc> noAlloc;
     59 
     60  // Check that the nursery is empty.
     61  void checkCondition(JSContext* cx);
     62 
     63  // For subclasses that need to empty the nursery in their constructors.
     64  AutoAssertEmptyNursery() : cx(nullptr) {}
     65 
     66 public:
     67  explicit AutoAssertEmptyNursery(JSContext* cx) : cx(nullptr) {
     68    checkCondition(cx);
     69  }
     70 
     71  AutoAssertEmptyNursery(const AutoAssertEmptyNursery& other)
     72      : AutoAssertEmptyNursery(other.cx) {}
     73 };
     74 
     75 /*
     76 * Evict the nursery upon construction. Serves as a token indicating that the
     77 * nursery is empty. (See AutoAssertEmptyNursery, above.)
     78 */
     79 class MOZ_RAII AutoEmptyNursery : public AutoAssertEmptyNursery {
     80 public:
     81  explicit AutoEmptyNursery(JSContext* cx);
     82 };
     83 
     84 class MOZ_RAII AutoGCSession : public AutoHeapSession {
     85 public:
     86  explicit AutoGCSession(GCRuntime* gc, JS::HeapState state)
     87      : AutoHeapSession(gc, state) {}
     88 };
     89 
     90 class MOZ_RAII AutoMajorGCProfilerEntry : public AutoGeckoProfilerEntry {
     91 public:
     92  explicit AutoMajorGCProfilerEntry(GCRuntime* gc);
     93 };
     94 
     95 // This class should be used by any code that needs exclusive access to the heap
     96 // in order to trace through it.
     97 //
     98 // This version also empties the nursery after finishing any ongoing GC.
     99 class MOZ_RAII AutoEmptyNurseryAndPrepareForTracing : private AutoFinishGC,
    100                                                      public AutoEmptyNursery,
    101                                                      public AutoTraceSession {
    102 public:
    103  explicit AutoEmptyNurseryAndPrepareForTracing(JSContext* cx)
    104      : AutoFinishGC(cx, JS::GCReason::PREPARE_FOR_TRACING),
    105        AutoEmptyNursery(cx),
    106        AutoTraceSession(cx->runtime()) {}
    107 };
    108 
    109 // Set compartments' maybeAlive flags if anything is marked while this class is
    110 // live. This is used while marking roots.
    111 class AutoUpdateLiveCompartments {
    112  GCRuntime* gc;
    113 
    114 public:
    115  explicit AutoUpdateLiveCompartments(GCRuntime* gc);
    116  ~AutoUpdateLiveCompartments();
    117 };
    118 
    119 class MOZ_RAII AutoRunParallelTask : public GCParallelTask {
    120  // This class takes a pointer to a member function of GCRuntime.
    121  using TaskFunc = JS_MEMBER_FN_PTR_TYPE(GCRuntime, void);
    122 
    123  TaskFunc func_;
    124  AutoLockHelperThreadState& lock_;
    125 
    126 public:
    127  AutoRunParallelTask(GCRuntime* gc, TaskFunc func, gcstats::PhaseKind phase,
    128                      GCUse use, AutoLockHelperThreadState& lock)
    129      : GCParallelTask(gc, phase, use), func_(func), lock_(lock) {
    130    gc->startTask(*this, lock_);
    131  }
    132 
    133  ~AutoRunParallelTask() { gc->joinTask(*this, lock_); }
    134 
    135  void run(AutoLockHelperThreadState& lock) override {
    136    AutoUnlockHelperThreadState unlock(lock);
    137 
    138    // The hazard analysis can't tell what the call to func_ will do but it's
    139    // not allowed to GC.
    140    JS::AutoSuppressGCAnalysis nogc;
    141 
    142    // Call pointer to member function on |gc|.
    143    JS_CALL_MEMBER_FN_PTR(gc, func_);
    144  }
    145 };
    146 
    147 #ifdef JS_GC_ZEAL
    148 
    149 class MOZ_RAII AutoStopVerifyingBarriers {
    150  GCRuntime* gc;
    151  bool restartPreVerifier;
    152 
    153 public:
    154  AutoStopVerifyingBarriers(JSRuntime* rt, bool isShutdown) : gc(&rt->gc) {
    155    if (gc->isVerifyPreBarriersEnabled()) {
    156      gc->endVerifyPreBarriers();
    157      restartPreVerifier = !isShutdown;
    158    } else {
    159      restartPreVerifier = false;
    160    }
    161  }
    162 
    163  ~AutoStopVerifyingBarriers() {
    164    // Nasty special case: verification runs a minor GC, which *may* nest
    165    // inside of an outer minor GC. This is not allowed by the
    166    // gc::Statistics phase tree. So we pause the "real" GC, if in fact one
    167    // is in progress.
    168    gcstats::PhaseKind outer = gc->stats().currentPhaseKind();
    169    if (outer != gcstats::PhaseKind::NONE) {
    170      gc->stats().endPhase(outer);
    171    }
    172    MOZ_ASSERT(gc->stats().currentPhaseKind() == gcstats::PhaseKind::NONE);
    173 
    174    if (restartPreVerifier) {
    175      gc->startVerifyPreBarriers();
    176    }
    177 
    178    if (outer != gcstats::PhaseKind::NONE) {
    179      gc->stats().beginPhase(outer);
    180    }
    181  }
    182 };
    183 #else
    184 struct MOZ_RAII AutoStopVerifyingBarriers {
    185  AutoStopVerifyingBarriers(JSRuntime*, bool) {}
    186 };
    187 #endif /* JS_GC_ZEAL */
    188 
    189 class MOZ_RAII AutoPoisonFreedJitCode {
    190  JS::GCContext* const gcx;
    191 
    192 public:
    193  explicit AutoPoisonFreedJitCode(JS::GCContext* gcx) : gcx(gcx) {}
    194  ~AutoPoisonFreedJitCode() { gcx->poisonJitCode(); }
    195 };
    196 
    197 // Set/restore the GCContext GC use flag for the current thread.
    198 
    199 class MOZ_RAII AutoSetThreadGCUse {
    200 public:
    201  AutoSetThreadGCUse(JS::GCContext* gcx, GCUse use)
    202      : gcx(gcx), prevUse(gcx->gcUse_) {
    203    gcx->gcUse_ = use;
    204  }
    205  explicit AutoSetThreadGCUse(GCUse use)
    206      : AutoSetThreadGCUse(TlsGCContext.get(), use) {}
    207 
    208  ~AutoSetThreadGCUse() { gcx->gcUse_ = prevUse; }
    209 
    210 protected:
    211  JS::GCContext* gcx;
    212  GCUse prevUse;
    213 };
    214 
    215 template <GCUse Use>
    216 class AutoSetThreadGCUseT : public AutoSetThreadGCUse {
    217 public:
    218  explicit AutoSetThreadGCUseT(JS::GCContext* gcx)
    219      : AutoSetThreadGCUse(gcx, Use) {}
    220  AutoSetThreadGCUseT() : AutoSetThreadGCUseT(TlsGCContext.get()) {}
    221 };
    222 
    223 using AutoSetThreadIsPerformingGC = AutoSetThreadGCUseT<GCUse::Unspecified>;
    224 using AutoSetThreadIsMarking = AutoSetThreadGCUseT<GCUse::Marking>;
    225 using AutoSetThreadIsFinalizing = AutoSetThreadGCUseT<GCUse::Finalizing>;
    226 
    227 class AutoSetThreadIsSweeping : public AutoSetThreadGCUseT<GCUse::Sweeping> {
    228 public:
    229  explicit AutoSetThreadIsSweeping(JS::GCContext* gcx,
    230                                   JS::Zone* sweepZone = nullptr)
    231      : AutoSetThreadGCUseT(gcx) {
    232 #ifdef DEBUG
    233    prevZone = gcx->gcSweepZone_;
    234    gcx->gcSweepZone_ = sweepZone;
    235 #endif
    236  }
    237  explicit AutoSetThreadIsSweeping(JS::Zone* sweepZone = nullptr)
    238      : AutoSetThreadIsSweeping(TlsGCContext.get(), sweepZone) {}
    239 
    240  ~AutoSetThreadIsSweeping() {
    241 #ifdef DEBUG
    242    MOZ_ASSERT_IF(prevUse == GCUse::None, !prevZone);
    243    gcx->gcSweepZone_ = prevZone;
    244 #endif
    245  }
    246 
    247 private:
    248 #ifdef DEBUG
    249  JS::Zone* prevZone;
    250 #endif
    251 };
    252 
    253 class MOZ_RAII AutoDisallowPreWriteBarrier {
    254 public:
    255  explicit AutoDisallowPreWriteBarrier(JS::GCContext* gcx) {
    256 #ifdef DEBUG
    257    gcx_ = gcx;
    258    MOZ_ASSERT(gcx->preWriteBarrierAllowed_);
    259    gcx->preWriteBarrierAllowed_ = false;
    260 #endif
    261  }
    262  ~AutoDisallowPreWriteBarrier() {
    263 #ifdef DEBUG
    264    MOZ_ASSERT(!gcx_->preWriteBarrierAllowed_);
    265    gcx_->preWriteBarrierAllowed_ = true;
    266 #endif
    267  }
    268 
    269 private:
    270 #ifdef DEBUG
    271  JS::GCContext* gcx_;
    272 #endif
    273 };
    274 
    275 #ifdef JSGC_HASH_TABLE_CHECKS
    276 void CheckHashTablesAfterMovingGC(JSRuntime* rt);
    277 void CheckHeapAfterGC(JSRuntime* rt);
    278 #endif
    279 
    280 struct MovingTracer final : public GenericTracerImpl<MovingTracer> {
    281  explicit MovingTracer(JSRuntime* rt);
    282 
    283 private:
    284  template <typename T>
    285  void onEdge(T** thingp, const char* name);
    286  friend class GenericTracerImpl<MovingTracer>;
    287 };
    288 
    289 struct MinorSweepingTracer final
    290    : public GenericTracerImpl<MinorSweepingTracer> {
    291  explicit MinorSweepingTracer(JSRuntime* rt);
    292 
    293 private:
    294  template <typename T>
    295  void onEdge(T** thingp, const char* name);
    296  friend class GenericTracerImpl<MinorSweepingTracer>;
    297 };
    298 
    299 class MOZ_RAII AutoUpdateMarkStackRanges {
    300  GCMarker& marker_;
    301 
    302 public:
    303  explicit AutoUpdateMarkStackRanges(GCMarker& marker) : marker_(marker) {
    304    marker_.updateRangesAtStartOfSlice();
    305  }
    306  ~AutoUpdateMarkStackRanges() { marker_.updateRangesAtEndOfSlice(); }
    307 };
    308 
    309 extern void DelayCrossCompartmentGrayMarking(GCMarker* maybeMarker,
    310                                             JSObject* src);
    311 
    312 inline bool IsOOMReason(JS::GCReason reason) {
    313  return reason == JS::GCReason::LAST_DITCH ||
    314         reason == JS::GCReason::MEM_PRESSURE;
    315 }
    316 
    317 void* AllocateTenuredCellInGC(JS::Zone* zone, AllocKind thingKind);
    318 
    319 void ReadProfileEnv(const char* envName, const char* helpText, bool* enableOut,
    320                    bool* workersOut, mozilla::TimeDuration* thresholdOut);
    321 
    322 bool ShouldPrintProfile(JSRuntime* runtime, bool enable, bool workers,
    323                        mozilla::TimeDuration threshold,
    324                        mozilla::TimeDuration duration);
    325 
    326 using CharRange = mozilla::Range<const char>;
    327 using CharRangeVector = Vector<CharRange, 0, SystemAllocPolicy>;
    328 
    329 // Split a string on a given character and produce a vector of CharRanges that
    330 // reference the input string.
    331 extern bool SplitStringBy(const char* string, char delimiter,
    332                          CharRangeVector* resultOut);
    333 extern bool SplitStringBy(const CharRange& string, char delimiter,
    334                          CharRangeVector* resultOut);
    335 
    336 } /* namespace gc */
    337 } /* namespace js */
    338 
    339 #endif /* gc_GCInternals_h */