1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
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 /* JS execution context. */
8 
9 #ifndef vm_JSContext_h
10 #define vm_JSContext_h
11 
12 #include "mozilla/MemoryReporting.h"
13 
14 #include "js/CharacterEncoding.h"
15 #include "js/GCVector.h"
16 #include "js/Result.h"
17 #include "js/Utility.h"
18 #include "js/Vector.h"
19 #include "threading/ProtectedData.h"
20 #include "vm/ErrorReporting.h"
21 #include "vm/MallocProvider.h"
22 #include "vm/Runtime.h"
23 
24 #ifdef _MSC_VER
25 #pragma warning(push)
26 #pragma warning( \
27     disable : 4100) /* Silence unreferenced formal parameter warnings */
28 #endif
29 
30 struct DtoaState;
31 
32 namespace js {
33 
34 class AutoCompartment;
35 
36 namespace jit {
37 class JitContext;
38 class DebugModeOSRVolatileJitFrameIter;
39 }  // namespace jit
40 
41 namespace gc {
42 class AutoSuppressNurseryCellAlloc;
43 }
44 
45 typedef HashSet<Shape*> ShapeSet;
46 
47 /* Detects cycles when traversing an object graph. */
48 class MOZ_RAII AutoCycleDetector {
49  public:
50   using Vector = GCVector<JSObject*, 8>;
51 
AutoCycleDetector(JSContext * cx,HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)52   AutoCycleDetector(JSContext* cx,
53                     HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
54       : cx(cx), obj(cx, objArg), cyclic(true) {
55     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
56   }
57 
58   ~AutoCycleDetector();
59 
60   bool init();
61 
foundCycle()62   bool foundCycle() { return cyclic; }
63 
64  private:
65   JSContext* cx;
66   RootedObject obj;
67   bool cyclic;
68   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
69 };
70 
71 struct AutoResolving;
72 
73 struct HelperThread;
74 
75 using JobQueue = GCVector<JSObject*, 0, SystemAllocPolicy>;
76 
77 class AutoLockForExclusiveAccess;
78 class AutoLockScriptData;
79 
80 void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
81 
82 /* Thread Local Storage slot for storing the context for a thread. */
83 extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
84 
85 enum class ContextKind { Cooperative, Background };
86 
87 } /* namespace js */
88 
89 /*
90  * A JSContext encapsulates the thread local state used when using the JS
91  * runtime.
92  */
93 struct JSContext : public JS::RootingContext,
94                    public js::MallocProvider<JSContext> {
95   JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
96   ~JSContext();
97 
98   bool init(js::ContextKind kind);
99 
100  private:
101   js::UnprotectedData<JSRuntime*> runtime_;
102   js::WriteOnceData<js::ContextKind> kind_;
103 
104   // System handle for the thread this context is associated with.
105   js::WriteOnceData<size_t> threadNative_;
106 
107   // The thread on which this context is running, if this is performing a parse
108   // task.
109   js::ThreadLocalData<js::HelperThread*> helperThread_;
110 
111   friend class js::gc::AutoSuppressNurseryCellAlloc;
112   js::ThreadLocalData<size_t> nurserySuppressions_;
113 
114   js::ThreadLocalData<JS::ContextOptions> options_;
115 
116   js::ThreadLocalData<js::gc::ArenaLists*> arenas_;
117 
118  public:
119   // This is used by helper threads to change the runtime their context is
120   // currently operating on.
121   void setRuntime(JSRuntime* rt);
122 
isCooperativelyScheduledJSContext123   bool isCooperativelyScheduled() const {
124     return kind_ == js::ContextKind::Cooperative;
125   }
threadNativeJSContext126   size_t threadNative() const { return threadNative_; }
127 
arenasJSContext128   inline js::gc::ArenaLists* arenas() const { return arenas_; }
129 
130   template <typename T>
isInsideCurrentZoneJSContext131   bool isInsideCurrentZone(T thing) const {
132     return thing->zoneFromAnyThread() == zone_;
133   }
134 
135   template <typename T>
isInsideCurrentCompartmentJSContext136   inline bool isInsideCurrentCompartment(T thing) const {
137     return thing->compartment() == compartment_;
138   }
139 
140   void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes,
141                       void* reallocPtr = nullptr) {
142     if (helperThread()) {
143       addPendingOutOfMemory();
144       return nullptr;
145     }
146     return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, this);
147   }
148 
149   /* Clear the pending exception (if any) due to OOM. */
150   void recoverFromOutOfMemory();
151 
152   void updateMallocCounter(size_t nbytes);
153 
reportAllocationOverflowJSContext154   void reportAllocationOverflow() { js::ReportAllocationOverflow(this); }
155 
156   // Accessors for immutable runtime data.
namesJSContext157   JSAtomState& names() { return *runtime_->commonNames; }
staticStringsJSContext158   js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
sharedImmutableStringsJSContext159   js::SharedImmutableStringsCache& sharedImmutableStrings() {
160     return runtime_->sharedImmutableStrings();
161   }
isPermanentAtomsInitializedJSContext162   bool isPermanentAtomsInitialized() { return !!runtime_->permanentAtoms; }
permanentAtomsJSContext163   js::FrozenAtomSet& permanentAtoms() { return *runtime_->permanentAtoms; }
wellKnownSymbolsJSContext164   js::WellKnownSymbols& wellKnownSymbols() {
165     return *runtime_->wellKnownSymbols;
166   }
buildIdOpJSContext167   JS::BuildIdOp buildIdOp() { return runtime_->buildIdOp; }
asmJSCacheOpsJSContext168   const JS::AsmJSCacheOps& asmJSCacheOps() { return runtime_->asmJSCacheOps; }
emptyStringJSContext169   js::PropertyName* emptyString() { return runtime_->emptyString; }
defaultFreeOpJSContext170   js::FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
stackLimitAddressJSContext171   void* stackLimitAddress(JS::StackKind kind) {
172     return &nativeStackLimit[kind];
173   }
174   void* stackLimitAddressForJitCode(JS::StackKind kind);
stackLimitJSContext175   uintptr_t stackLimit(JS::StackKind kind) { return nativeStackLimit[kind]; }
176   uintptr_t stackLimitForJitCode(JS::StackKind kind);
gcSystemPageSizeJSContext177   size_t gcSystemPageSize() { return js::gc::SystemPageSize(); }
jitSupportsFloatingPointJSContext178   bool jitSupportsFloatingPoint() const {
179     return runtime_->jitSupportsFloatingPoint;
180   }
jitSupportsUnalignedAccessesJSContext181   bool jitSupportsUnalignedAccesses() const {
182     return runtime_->jitSupportsUnalignedAccesses;
183   }
jitSupportsSimdJSContext184   bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }
lcovEnabledJSContext185   bool lcovEnabled() const { return runtime_->lcovOutput().isEnabled(); }
186 
187   /*
188    * "Entering" a compartment changes cx->compartment (which changes
189    * cx->global). Note that this does not push any InterpreterFrame which means
190    * that it is possible for cx->fp()->compartment() != cx->compartment.
191    * This is not a problem since, in general, most places in the VM cannot
192    * know that they were called from script (e.g., they may have been called
193    * through the JSAPI via JS_CallFunction) and thus cannot expect fp.
194    *
195    * Compartments should be entered/left in a LIFO fasion. The depth of this
196    * enter/leave stack is maintained by enterCompartmentDepth_ and queried by
197    * hasEnteredCompartment.
198    *
199    * To enter a compartment, code should prefer using AutoCompartment over
200    * manually calling cx->enterCompartment/leaveCompartment.
201    */
202  protected:
203   js::ThreadLocalData<unsigned> enterCompartmentDepth_;
204 
205   inline void setCompartment(
206       JSCompartment* comp,
207       const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
208 
209  public:
hasEnteredCompartmentJSContext210   bool hasEnteredCompartment() const { return enterCompartmentDepth_ > 0; }
211 #ifdef DEBUG
getEnterCompartmentDepthJSContext212   unsigned getEnterCompartmentDepth() const { return enterCompartmentDepth_; }
213 #endif
214 
215  private:
216   // We distinguish between entering the atoms compartment and all other
217   // compartments. Entering the atoms compartment requires a lock. Also, we
218   // don't call enterZoneGroup when entering the atoms compartment since that
219   // can induce GC hazards.
220   inline void enterNonAtomsCompartment(JSCompartment* c);
221   inline void enterAtomsCompartment(JSCompartment* c,
222                                     const js::AutoLockForExclusiveAccess& lock);
223 
224   friend class js::AutoCompartment;
225 
226  public:
227   template <typename T>
228   inline void enterCompartmentOf(const T& target);
229   inline void enterNullCompartment();
230   inline void leaveCompartment(
231       JSCompartment* oldCompartment,
232       const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
233 
234   inline void enterZoneGroup(js::ZoneGroup* group);
235   inline void leaveZoneGroup(js::ZoneGroup* group);
236 
237   void setHelperThread(js::HelperThread* helperThread);
helperThreadJSContext238   js::HelperThread* helperThread() const { return helperThread_; }
239 
isNurseryAllocSuppressedJSContext240   bool isNurseryAllocSuppressed() const { return nurserySuppressions_; }
241 
242   // Threads may freely access any data in their compartment and zone.
compartmentJSContext243   JSCompartment* compartment() const { return compartment_; }
zoneJSContext244   JS::Zone* zone() const {
245     MOZ_ASSERT_IF(!compartment(), !zone_);
246     MOZ_ASSERT_IF(compartment(),
247                   js::GetCompartmentZone(compartment()) == zone_);
248     return zoneRaw();
249   }
250 
251   // For use when the context's zone is being read by another thread and the
252   // compartment and zone pointers might not be in sync.
zoneRawJSContext253   JS::Zone* zoneRaw() const { return zone_; }
254 
255   // For JIT use.
offsetOfZoneJSContext256   static size_t offsetOfZone() { return offsetof(JSContext, zone_); }
257 
258   // Zone local methods that can be used freely.
259   inline js::LifoAlloc& typeLifoAlloc();
260 
261   // Current global. This is only safe to use within the scope of the
262   // AutoCompartment from which it's called.
263   inline js::Handle<js::GlobalObject*> global() const;
264 
265   // Methods to access runtime data that must be protected by locks.
atomsJSContext266   js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
267     return runtime_->atoms(lock);
268   }
atomsCompartmentJSContext269   JSCompartment* atomsCompartment(js::AutoLockForExclusiveAccess& lock) {
270     return runtime_->atomsCompartment(lock);
271   }
symbolRegistryJSContext272   js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
273     return runtime_->symbolRegistry(lock);
274   }
scriptDataTableJSContext275   js::ScriptDataTable& scriptDataTable(js::AutoLockScriptData& lock) {
276     return runtime_->scriptDataTable(lock);
277   }
278 
279   // Methods to access other runtime data that checks locking internally.
atomMarkingJSContext280   js::gc::AtomMarkingRuntime& atomMarking() { return runtime_->gc.atomMarking; }
markAtomJSContext281   void markAtom(JSAtom* atom) { atomMarking().markAtom(this, atom); }
markAtomJSContext282   void markAtom(JS::Symbol* symbol) { atomMarking().markAtom(this, symbol); }
markIdJSContext283   void markId(jsid id) { atomMarking().markId(this, id); }
markAtomValueJSContext284   void markAtomValue(const js::Value& value) {
285     atomMarking().markAtomValue(this, value);
286   }
287 
288   // Methods specific to any HelperThread for the context.
289   bool addPendingCompileError(js::CompileError** err);
290   void addPendingOverRecursed();
291   void addPendingOutOfMemory();
292 
runtimeJSContext293   JSRuntime* runtime() { return runtime_; }
runtimeJSContext294   const JSRuntime* runtime() const { return runtime_; }
295 
offsetOfCompartmentJSContext296   static size_t offsetOfCompartment() {
297     return offsetof(JSContext, compartment_);
298   }
299 
300   friend class JS::AutoSaveExceptionState;
301   friend class js::jit::DebugModeOSRVolatileJitFrameIter;
302   friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
303 
304   // Returns to the embedding to allow other cooperative threads to run. We
305   // may do this if we need access to a ZoneGroup that is in use by another
306   // thread.
yieldToEmbeddingJSContext307   void yieldToEmbedding() { (*yieldCallback_)(this); }
308 
setYieldCallbackJSContext309   void setYieldCallback(js::YieldCallback callback) {
310     yieldCallback_ = callback;
311   }
312 
313  private:
314   static JS::Error reportedError;
315   static JS::OOM reportedOOM;
316 
317   // This callback is used to ask the embedding to allow other cooperative
318   // threads to run. We may do this if we need access to a ZoneGroup that is
319   // in use by another thread.
320   js::ThreadLocalData<js::YieldCallback> yieldCallback_;
321 
322  public:
323   inline JS::Result<> boolToResult(bool ok);
324 
325   /**
326    * Intentionally awkward signpost method that is stationed on the
327    * boundary between Result-using and non-Result-using code.
328    */
329   template <typename V, typename E>
resultToBoolJSContext330   bool resultToBool(const JS::Result<V, E>& result) {
331     return result.isOk();
332   }
333 
334   template <typename V, typename E>
resultToPtrJSContext335   V* resultToPtr(const JS::Result<V*, E>& result) {
336     return result.isOk() ? result.unwrap() : nullptr;
337   }
338 
339   mozilla::GenericErrorResult<JS::OOM&> alreadyReportedOOM();
340   mozilla::GenericErrorResult<JS::Error&> alreadyReportedError();
341 
342   /*
343    * Points to the most recent JitActivation pushed on the thread.
344    * See JitActivation constructor in vm/Stack.cpp
345    */
346   js::ThreadLocalData<js::jit::JitActivation*> jitActivation;
347 
348   // Information about the heap allocated backtrack stack used by RegExp JIT
349   // code.
350   js::ThreadLocalData<js::irregexp::RegExpStack> regexpStack;
351 
352   /*
353    * Points to the most recent activation running on the thread.
354    * See Activation comment in vm/Stack.h.
355    */
356   js::ThreadLocalData<js::Activation*> activation_;
357 
358   /*
359    * Points to the most recent profiling activation running on the
360    * thread.
361    */
362   js::Activation* volatile profilingActivation_;
363 
364  public:
activationJSContext365   js::Activation* activation() const { return activation_; }
offsetOfActivationJSContext366   static size_t offsetOfActivation() {
367     return offsetof(JSContext, activation_);
368   }
369 
profilingActivationJSContext370   js::Activation* profilingActivation() const { return profilingActivation_; }
offsetOfProfilingActivationJSContext371   static size_t offsetOfProfilingActivation() {
372     return offsetof(JSContext, profilingActivation_);
373   }
374 
offsetOfJitActivationJSContext375   static size_t offsetOfJitActivation() {
376     return offsetof(JSContext, jitActivation);
377   }
378 
379 #ifdef DEBUG
offsetOfInUnsafeCallWithABIJSContext380   static size_t offsetOfInUnsafeCallWithABI() {
381     return offsetof(JSContext, inUnsafeCallWithABI);
382   }
383 #endif
384 
385  private:
386   /* Space for interpreter frames. */
387   js::ThreadLocalData<js::InterpreterStack> interpreterStack_;
388 
389  public:
interpreterStackJSContext390   js::InterpreterStack& interpreterStack() { return interpreterStack_.ref(); }
391 
392   /* Base address of the native stack for the current thread. */
393   const uintptr_t nativeStackBase;
394 
395   /* The native stack size limit that runtime should not exceed. */
396   js::ThreadLocalData<size_t> nativeStackQuota[JS::StackKindCount];
397 
398  public:
399   /* If non-null, report JavaScript entry points to this monitor. */
400   js::ThreadLocalData<JS::dbg::AutoEntryMonitor*> entryMonitor;
401 
402   /*
403    * Stack of debuggers that currently disallow debuggee execution.
404    *
405    * When we check for NX we are inside the debuggee compartment, and thus a
406    * stack of Debuggers that have prevented execution need to be tracked to
407    * enter the correct Debugger compartment to report the error.
408    */
409   js::ThreadLocalData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
410 
411   js::ThreadLocalData<js::ActivityCallback> activityCallback;
412   js::ThreadLocalData<void*> activityCallbackArg;
413   void triggerActivityCallback(bool active);
414 
415   /* The request depth for this thread. */
416   js::ThreadLocalData<unsigned> requestDepth;
417 
418 #ifdef DEBUG
419   js::ThreadLocalData<unsigned> checkRequestDepth;
420   js::ThreadLocalData<uint32_t> inUnsafeCallWithABI;
421   js::ThreadLocalData<bool> hasAutoUnsafeCallWithABI;
422 #endif
423 
424 #ifdef JS_SIMULATOR
425  private:
426   js::ThreadLocalData<js::jit::Simulator*> simulator_;
427 
428  public:
429   js::jit::Simulator* simulator() const;
430   uintptr_t* addressOfSimulatorStackLimit();
431 #endif
432 
433 #ifdef JS_TRACE_LOGGING
434   js::ThreadLocalData<js::TraceLoggerThread*> traceLogger;
435 #endif
436 
437  private:
438   /* Pointer to the current AutoFlushICache. */
439   js::ThreadLocalData<js::jit::AutoFlushICache*> autoFlushICache_;
440 
441  public:
442   js::jit::AutoFlushICache* autoFlushICache() const;
443   void setAutoFlushICache(js::jit::AutoFlushICache* afc);
444 
445   // State used by util/DoubleToString.cpp.
446   js::ThreadLocalData<DtoaState*> dtoaState;
447 
448   // Any GC activity occurring on this thread.
449   js::ThreadLocalData<JS::HeapState> heapState;
450 
451   /*
452    * When this flag is non-zero, any attempt to GC will be skipped. It is used
453    * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in
454    * debugging facilities that cannot tolerate a GC and would rather OOM
455    * immediately, such as utilities exposed to GDB. Setting this flag is
456    * extremely dangerous and should only be used when in an OOM situation or
457    * in non-exposed debugging facilities.
458    */
459   js::ThreadLocalData<int32_t> suppressGC;
460 
461 #ifdef DEBUG
462   // Whether this thread is actively Ion compiling.
463   js::ThreadLocalData<bool> ionCompiling;
464 
465   // Whether this thread is actively Ion compiling in a context where a minor
466   // GC could happen simultaneously. If this is true, this thread cannot use
467   // any pointers into the nursery.
468   js::ThreadLocalData<bool> ionCompilingSafeForMinorGC;
469 
470   // Whether this thread is currently performing GC.  This thread could be the
471   // active thread or a helper thread while the active thread is running the
472   // collector.
473   js::ThreadLocalData<bool> performingGC;
474 
475   // Whether this thread is currently sweeping GC things.  This thread could
476   // be the active thread or a helper thread while the active thread is running
477   // the mutator.  This is used to assert that destruction of GCPtr only
478   // happens when we are sweeping.
479   js::ThreadLocalData<bool> gcSweeping;
480 
481   // Whether this thread is performing work in the background for a runtime's
482   // GCHelperState.
483   js::ThreadLocalData<bool> gcHelperStateThread;
484 
485   // Whether this thread is currently manipulating possibly-gray GC things.
486   js::ThreadLocalData<size_t> isTouchingGrayThings;
487 
488   js::ThreadLocalData<size_t> noGCOrAllocationCheck;
489   js::ThreadLocalData<size_t> noNurseryAllocationCheck;
490 
491   /*
492    * If this is 0, all cross-compartment proxies must be registered in the
493    * wrapper map. This checking must be disabled temporarily while creating
494    * new wrappers. When non-zero, this records the recursion depth of wrapper
495    * creation.
496    */
497   js::ThreadLocalData<uintptr_t> disableStrictProxyCheckingCount;
498 
isAllocAllowedJSContext499   bool isAllocAllowed() { return noGCOrAllocationCheck == 0; }
disallowAllocJSContext500   void disallowAlloc() { ++noGCOrAllocationCheck; }
allowAllocJSContext501   void allowAlloc() {
502     MOZ_ASSERT(!isAllocAllowed());
503     --noGCOrAllocationCheck;
504   }
505 
isNurseryAllocAllowedJSContext506   bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; }
disallowNurseryAllocJSContext507   void disallowNurseryAlloc() { ++noNurseryAllocationCheck; }
allowNurseryAllocJSContext508   void allowNurseryAlloc() {
509     MOZ_ASSERT(!isNurseryAllocAllowed());
510     --noNurseryAllocationCheck;
511   }
512 
isStrictProxyCheckingEnabledJSContext513   bool isStrictProxyCheckingEnabled() {
514     return disableStrictProxyCheckingCount == 0;
515   }
disableStrictProxyCheckingJSContext516   void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; }
enableStrictProxyCheckingJSContext517   void enableStrictProxyChecking() {
518     MOZ_ASSERT(disableStrictProxyCheckingCount > 0);
519     --disableStrictProxyCheckingCount;
520   }
521 #endif
522 
523 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
524   // We are currently running a simulated OOM test.
525   js::ThreadLocalData<bool> runningOOMTest;
526 #endif
527 
528   // True if we should assert that
529   //     !comp->validAccessPtr || *comp->validAccessPtr
530   // is true for every |comp| that we run JS code in.
531   js::ThreadLocalData<unsigned> enableAccessValidation;
532 
533   /*
534    * Some regions of code are hard for the static rooting hazard analysis to
535    * understand. In those cases, we trade the static analysis for a dynamic
536    * analysis. When this is non-zero, we should assert if we trigger, or
537    * might trigger, a GC.
538    */
539   js::ThreadLocalData<int> inUnsafeRegion;
540 
541   // Count of AutoDisableGenerationalGC instances on the thread's stack.
542   js::ThreadLocalData<unsigned> generationalDisabled;
543 
544   // Some code cannot tolerate compacting GC so it can be disabled temporarily
545   // with AutoDisableCompactingGC which uses this counter.
546   js::ThreadLocalData<unsigned> compactingDisabledCount;
547 
548   // Count of AutoKeepAtoms instances on the current thread's stack. When any
549   // instances exist, atoms in the runtime will not be collected. Threads
550   // parsing off the active thread do not increment this value, but the presence
551   // of any such threads also inhibits collection of atoms. We don't scan the
552   // stacks of exclusive threads, so we need to avoid collecting their
553   // objects in another way. The only GC thing pointers they have are to
554   // their exclusive compartment (which is not collected) or to the atoms
555   // compartment. Therefore, we avoid collecting the atoms compartment when
556   // exclusive threads are running.
557   js::ThreadLocalData<unsigned> keepAtoms;
558 
canCollectAtomsJSContext559   bool canCollectAtoms() const {
560     return !keepAtoms && !runtime()->hasHelperThreadZones();
561   }
562 
563  private:
564   // Pools used for recycling name maps and vectors when parsing and
565   // emitting bytecode. Purged on GC when there are no active script
566   // compilations.
567   js::ThreadLocalData<js::frontend::NameCollectionPool> frontendCollectionPool_;
568 
569  public:
frontendCollectionPoolJSContext570   js::frontend::NameCollectionPool& frontendCollectionPool() {
571     return frontendCollectionPool_.ref();
572   }
573 
verifyIsSafeToGCJSContext574   void verifyIsSafeToGC() {
575     MOZ_DIAGNOSTIC_ASSERT(!inUnsafeRegion,
576                           "[AutoAssertNoGC] possible GC in GC-unsafe region");
577   }
578 
579   /* Whether sampling should be enabled or not. */
580  private:
581   mozilla::Atomic<bool, mozilla::SequentiallyConsistent>
582       suppressProfilerSampling;
583 
584  public:
isProfilerSamplingEnabledJSContext585   bool isProfilerSamplingEnabled() const { return !suppressProfilerSampling; }
disableProfilerSamplingJSContext586   void disableProfilerSampling() { suppressProfilerSampling = true; }
enableProfilerSamplingJSContext587   void enableProfilerSampling() { suppressProfilerSampling = false; }
588 
589 #if defined(XP_DARWIN)
590   js::wasm::MachExceptionHandler wasmMachExceptionHandler;
591 #endif
592 
593   /* Temporary arena pool used while compiling and decompiling. */
594   static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
595 
596  private:
597   js::ThreadLocalData<js::LifoAlloc> tempLifoAlloc_;
598 
599  public:
tempLifoAllocJSContext600   js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
tempLifoAllocJSContext601   const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
602 
603   js::ThreadLocalData<uint32_t> debuggerMutations;
604 
605   // Cache for jit::GetPcScript().
606   js::ThreadLocalData<js::jit::PcScriptCache*> ionPcScriptCache;
607 
608  private:
609   /* Exception state -- the exception member is a GC root by definition. */
610   js::ThreadLocalData<bool> throwing; /* is there a pending exception? */
611   js::ThreadLocalData<JS::PersistentRooted<JS::Value>>
612       unwrappedException_; /* most-recently-thrown exception */
613 
unwrappedExceptionJSContext614   JS::Value& unwrappedException() {
615     if (!unwrappedException_.ref().initialized())
616       unwrappedException_.ref().init(this);
617     return unwrappedException_.ref().get();
618   }
619 
620   // True if the exception currently being thrown is by result of
621   // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
622   js::ThreadLocalData<bool> overRecursed_;
623 
624   // True if propagating a forced return from an interrupt handler during
625   // debug mode.
626   js::ThreadLocalData<bool> propagatingForcedReturn_;
627 
628   // A stack of live iterators that need to be updated in case of debug mode
629   // OSR.
630   js::ThreadLocalData<js::jit::DebugModeOSRVolatileJitFrameIter*>
631       liveVolatileJitFrameIter_;
632 
633  public:
634   js::ThreadLocalData<int32_t> reportGranularity; /* see vm/Probes.h */
635 
636   js::ThreadLocalData<js::AutoResolving*> resolvingList;
637 
638 #ifdef DEBUG
639   js::ThreadLocalData<js::AutoEnterPolicy*> enteredPolicy;
640 #endif
641 
642   /* True if generating an error, to prevent runaway recursion. */
643   js::ThreadLocalData<bool> generatingError;
644 
645  private:
646   /* State for object and array toSource conversion. */
647   js::ThreadLocalData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
648 
649  public:
cycleDetectorVectorJSContext650   js::AutoCycleDetector::Vector& cycleDetectorVector() {
651     return cycleDetectorVector_.ref();
652   }
cycleDetectorVectorJSContext653   const js::AutoCycleDetector::Vector& cycleDetectorVector() const {
654     return cycleDetectorVector_.ref();
655   }
656 
657   /* Client opaque pointer. */
658   js::UnprotectedData<void*> data;
659 
660   void initJitStackLimit();
661   void resetJitStackLimit();
662 
663  public:
optionsJSContext664   JS::ContextOptions& options() { return options_.ref(); }
665 
runtimeMatchesJSContext666   bool runtimeMatches(JSRuntime* rt) const { return runtime_ == rt; }
667 
668   // Number of JS_BeginRequest calls without the corresponding JS_EndRequest.
669   js::ThreadLocalData<unsigned> outstandingRequests;
670 
671   js::ThreadLocalData<bool> jitIsBroken;
672 
673   void updateJITEnabled();
674 
675  private:
676   /*
677    * Youngest frame of a saved stack that will be picked up as an async stack
678    * by any new Activation, and is nullptr when no async stack should be used.
679    *
680    * The JS::AutoSetAsyncStackForNewCalls class can be used to set this.
681    *
682    * New activations will reset this to nullptr on construction after getting
683    * the current value, and will restore the previous value on destruction.
684    */
685   js::ThreadLocalData<JS::PersistentRooted<js::SavedFrame*>>
686       asyncStackForNewActivations_;
687 
688  public:
asyncStackForNewActivationsJSContext689   js::SavedFrame*& asyncStackForNewActivations() {
690     if (!asyncStackForNewActivations_.ref().initialized())
691       asyncStackForNewActivations_.ref().init(this);
692     return asyncStackForNewActivations_.ref().get();
693   }
694 
695   /*
696    * Value of asyncCause to be attached to asyncStackForNewActivations.
697    */
698   js::ThreadLocalData<const char*> asyncCauseForNewActivations;
699 
700   /*
701    * True if the async call was explicitly requested, e.g. via
702    * callFunctionWithAsyncStack.
703    */
704   js::ThreadLocalData<bool> asyncCallIsExplicit;
705 
currentlyRunningInInterpreterJSContext706   bool currentlyRunningInInterpreter() const {
707     return activation()->isInterpreter();
708   }
currentlyRunningInJitJSContext709   bool currentlyRunningInJit() const { return activation()->isJit(); }
interpreterFrameJSContext710   js::InterpreterFrame* interpreterFrame() const {
711     return activation()->asInterpreter()->current();
712   }
interpreterRegsJSContext713   js::InterpreterRegs& interpreterRegs() const {
714     return activation()->asInterpreter()->regs();
715   }
716 
717   /*
718    * Get the topmost script and optional pc on the stack. By default, this
719    * function only returns a JSScript in the current compartment, returning
720    * nullptr if the current script is in a different compartment. This
721    * behavior can be overridden by passing ALLOW_CROSS_COMPARTMENT.
722    */
723   enum MaybeAllowCrossCompartment {
724     DONT_ALLOW_CROSS_COMPARTMENT = false,
725     ALLOW_CROSS_COMPARTMENT = true
726   };
727   inline JSScript* currentScript(
728       jsbytecode** pc = nullptr,
729       MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
730 
731   inline js::Nursery& nursery();
732   inline void minorGC(JS::gcreason::Reason reason);
733 
734  public:
isExceptionPendingJSContext735   bool isExceptionPending() const { return throwing; }
736 
737   MOZ_MUST_USE
738   bool getPendingException(JS::MutableHandleValue rval);
739 
740   bool isThrowingOutOfMemory();
741   bool isThrowingDebuggeeWouldRun();
742   bool isClosingGenerator();
743 
744   void setPendingException(const js::Value& v);
745 
clearPendingExceptionJSContext746   void clearPendingException() {
747     throwing = false;
748     overRecursed_ = false;
749     unwrappedException().setUndefined();
750   }
751 
isThrowingOverRecursedJSContext752   bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
isPropagatingForcedReturnJSContext753   bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
setPropagatingForcedReturnJSContext754   void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
clearPropagatingForcedReturnJSContext755   void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
756 
757   /*
758    * See JS_SetTrustedPrincipals in jsapi.h.
759    * Note: !cx->compartment is treated as trusted.
760    */
761   inline bool runningWithTrustedPrincipals();
762 
763   JS_FRIEND_API size_t
764   sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
765 
766   void trace(JSTracer* trc);
767 
768   inline js::RuntimeCaches& caches();
769 
770  private:
771   /*
772    * The allocation code calls the function to indicate either OOM failure
773    * when p is null or that a memory pressure counter has reached some
774    * threshold when p is not null. The function takes the pointer and not
775    * a boolean flag to minimize the amount of code in its inlined callers.
776    */
777   JS_FRIEND_API void checkMallocGCPressure(void* p);
778 
779  public:
780   using InterruptCallbackVector =
781       js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
782 
783  private:
784   js::ThreadLocalData<InterruptCallbackVector> interruptCallbacks_;
785 
786  public:
interruptCallbacksJSContext787   InterruptCallbackVector& interruptCallbacks() {
788     return interruptCallbacks_.ref();
789   }
790 
791   js::ThreadLocalData<bool> interruptCallbackDisabled;
792 
793   mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
794   mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptRegExpJit_;
795 
796   enum InterruptMode { RequestInterruptUrgent, RequestInterruptCanWait };
797 
798   // Any thread can call requestInterrupt() to request that this thread
799   // stop running and call the interrupt callback (allowing the interrupt
800   // callback to halt execution). To stop this thread, requestInterrupt
801   // sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to
802   // UINTPTR_MAX). The JS engine must continually poll one of these fields
803   // and call handleInterrupt if either field has the interrupt value. (The
804   // point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already
805   // needs to guard on jitStackLimit_ in every function prologue to avoid
806   // stack overflow, so we avoid a second branch on interrupt_ by setting
807   // jitStackLimit_ to a value that is guaranteed to fail the guard.)
808   //
809   // Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed
810   // Atomic so, while the writes are guaranteed to eventually be visible to
811   // this thread, it can happen in any order. handleInterrupt calls the
812   // interrupt callback if either is set, so it really doesn't matter as long
813   // as the JS engine is continually polling at least one field. In corner
814   // cases, this relaxed ordering could lead to an interrupt handler being
815   // called twice in succession after a single requestInterrupt call, but
816   // that's fine.
817   void requestInterrupt(InterruptMode mode);
818   bool handleInterrupt();
819 
hasPendingInterruptJSContext820   MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const {
821     static_assert(sizeof(interrupt_) == sizeof(uint32_t),
822                   "Assumed by JIT callers");
823     return interrupt_;
824   }
825 
826  private:
827   // Set when we're handling an interrupt of JIT/wasm code in
828   // InterruptRunningJitCode.
829   mozilla::Atomic<bool> handlingJitInterrupt_;
830 
831  public:
startHandlingJitInterruptJSContext832   bool startHandlingJitInterrupt() {
833     // Return true if we changed handlingJitInterrupt_ from
834     // false to true.
835     return handlingJitInterrupt_.compareExchange(false, true);
836   }
finishHandlingJitInterruptJSContext837   void finishHandlingJitInterrupt() {
838     MOZ_ASSERT(handlingJitInterrupt_);
839     handlingJitInterrupt_ = false;
840   }
handlingJitInterruptJSContext841   bool handlingJitInterrupt() const { return handlingJitInterrupt_; }
842 
843   /* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics
844    * object */
845   js::FutexThread fx;
846 
847   // Buffer for OSR from baseline to Ion. To avoid holding on to this for
848   // too long, it's also freed in EnterBaseline (after returning from JIT code).
849   js::ThreadLocalData<uint8_t*> osrTempData_;
850 
851   uint8_t* allocateOsrTempData(size_t size);
852   void freeOsrTempData();
853 
854   // In certain cases, we want to optimize certain opcodes to typed
855   // instructions, to avoid carrying an extra register to feed into an unbox.
856   // Unfortunately, that's not always possible. For example, a GetPropertyCacheT
857   // could return a typed double, but if it takes its out-of-line path, it could
858   // return an object, and trigger invalidation. The invalidation bailout will
859   // consider the return value to be a double, and create a garbage Value.
860   //
861   // To allow the GetPropertyCacheT optimization, we allow the ability for
862   // GetPropertyCache to override the return value at the top of the stack - the
863   // value that will be temporarily corrupt. This special override value is set
864   // only in callVM() targets that are about to return *and* have invalidated
865   // their callee.
866   js::ThreadLocalData<js::Value> ionReturnOverride_;
867 
hasIonReturnOverrideJSContext868   bool hasIonReturnOverride() const {
869     return !ionReturnOverride_.ref().isMagic(JS_ARG_POISON);
870   }
takeIonReturnOverrideJSContext871   js::Value takeIonReturnOverride() {
872     js::Value v = ionReturnOverride_;
873     ionReturnOverride_ = js::MagicValue(JS_ARG_POISON);
874     return v;
875   }
setIonReturnOverrideJSContext876   void setIonReturnOverride(const js::Value& v) {
877     MOZ_ASSERT(!hasIonReturnOverride());
878     MOZ_ASSERT(!v.isMagic());
879     ionReturnOverride_ = v;
880   }
881 
882   mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
883 
884   // Like jitStackLimit, but not reset to trigger interrupts.
885   js::ThreadLocalData<uintptr_t> jitStackLimitNoInterrupt;
886 
887   // Promise callbacks.
888   js::ThreadLocalData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
889   js::ThreadLocalData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
890   js::ThreadLocalData<void*> enqueuePromiseJobCallbackData;
891 
892   // Queue of pending jobs as described in ES2016 section 8.4.
893   // Only used if internal job queue handling was activated using
894   // `js::UseInternalJobQueues`.
895   js::ThreadLocalData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
896   js::ThreadLocalData<bool> drainingJobQueue;
897   js::ThreadLocalData<bool> stopDrainingJobQueue;
898 
899   js::ThreadLocalData<JSPromiseRejectionTrackerCallback>
900       promiseRejectionTrackerCallback;
901   js::ThreadLocalData<void*> promiseRejectionTrackerCallbackData;
902 
903   JSObject* getIncumbentGlobal(JSContext* cx);
904   bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
905                          js::HandleObject promise,
906                          js::HandleObject incumbentGlobal);
907   void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
908   void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
909 }; /* struct JSContext */
910 
boolToResult(bool ok)911 inline JS::Result<> JSContext::boolToResult(bool ok) {
912   if (MOZ_LIKELY(ok)) {
913     MOZ_ASSERT(!isExceptionPending());
914     MOZ_ASSERT(!isPropagatingForcedReturn());
915     return JS::Ok();
916   }
917   return JS::Result<>(reportedError);
918 }
919 
activeContextFromOwnThread()920 inline JSContext* JSRuntime::activeContextFromOwnThread() {
921   MOZ_ASSERT(activeContext() == js::TlsContext.get());
922   return activeContext();
923 }
924 
925 namespace js {
926 
927 struct MOZ_RAII AutoResolving {
928  public:
929   enum Kind { LOOKUP, WATCH };
930 
931   AutoResolving(JSContext* cx, HandleObject obj, HandleId id,
932                 Kind kind = LOOKUP MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
contextAutoResolving933       : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList) {
934     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
935     MOZ_ASSERT(obj);
936     cx->resolvingList = this;
937   }
938 
~AutoResolvingAutoResolving939   ~AutoResolving() {
940     MOZ_ASSERT(context->resolvingList == this);
941     context->resolvingList = link;
942   }
943 
alreadyStartedAutoResolving944   bool alreadyStarted() const { return link && alreadyStartedSlow(); }
945 
946  private:
947   bool alreadyStartedSlow() const;
948 
949   JSContext* const context;
950   HandleObject object;
951   HandleId id;
952   Kind const kind;
953   AutoResolving* const link;
954   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
955 };
956 
957 /*
958  * Create and destroy functions for JSContext, which is manually allocated
959  * and exclusively owned.
960  */
961 extern JSContext* NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes,
962                              JSRuntime* parentRuntime);
963 
964 extern JSContext* NewCooperativeContext(JSContext* siblingContext);
965 
966 extern void YieldCooperativeContext(JSContext* cx);
967 
968 extern void ResumeCooperativeContext(JSContext* cx);
969 
970 extern void DestroyContext(JSContext* cx);
971 
972 enum ErrorArgumentsType {
973   ArgumentsAreUnicode,
974   ArgumentsAreASCII,
975   ArgumentsAreLatin1,
976   ArgumentsAreUTF8
977 };
978 
979 /*
980  * Loads and returns a self-hosted function by name. For performance, define
981  * the property name in vm/CommonPropertyNames.h.
982  *
983  * Defined in SelfHosting.cpp.
984  */
985 JSFunction* SelfHostedFunction(JSContext* cx, HandlePropertyName propName);
986 
987 /**
988  * Report an exception, using printf-style APIs to generate the error
989  * message.
990  */
991 #ifdef va_start
992 extern bool ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
993                           ErrorArgumentsType argumentsType, va_list ap)
994     MOZ_FORMAT_PRINTF(3, 0);
995 
996 extern bool ReportErrorNumberVA(JSContext* cx, unsigned flags,
997                                 JSErrorCallback callback, void* userRef,
998                                 const unsigned errorNumber,
999                                 ErrorArgumentsType argumentsType, va_list ap);
1000 
1001 extern bool ReportErrorNumberUCArray(JSContext* cx, unsigned flags,
1002                                      JSErrorCallback callback, void* userRef,
1003                                      const unsigned errorNumber,
1004                                      const char16_t** args);
1005 #endif
1006 
1007 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
1008                                    void* userRef, const unsigned errorNumber,
1009                                    const char16_t** messageArgs,
1010                                    ErrorArgumentsType argumentsType,
1011                                    JSErrorReport* reportp, va_list ap);
1012 
1013 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
1014                                    void* userRef, const unsigned errorNumber,
1015                                    const char16_t** messageArgs,
1016                                    ErrorArgumentsType argumentsType,
1017                                    JSErrorNotes::Note* notep, va_list ap);
1018 
1019 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
1020 extern void ReportUsageErrorASCII(JSContext* cx, HandleObject callee,
1021                                   const char* msg);
1022 
1023 /*
1024  * Prints a full report and returns true if the given report is non-nullptr
1025  * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings
1026  * is true.
1027  * Returns false otherwise.
1028  */
1029 extern bool PrintError(JSContext* cx, FILE* file,
1030                        JS::ConstUTF8CharsZ toStringResult,
1031                        JSErrorReport* report, bool reportWarnings);
1032 
1033 extern bool ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
1034 
1035 extern bool ReportIsNotDefined(JSContext* cx, HandleId id);
1036 
1037 /*
1038  * Report an attempt to access the property of a null or undefined value (v).
1039  */
1040 extern bool ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v,
1041                                     HandleString fallback);
1042 
1043 extern void ReportMissingArg(JSContext* cx, js::HandleValue v, unsigned arg);
1044 
1045 /*
1046  * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
1047  * the first argument for the error message. If the error message has less
1048  * then 3 arguments, use null for arg1 or arg2.
1049  */
1050 extern bool ReportValueErrorFlags(JSContext* cx, unsigned flags,
1051                                   const unsigned errorNumber, int spindex,
1052                                   HandleValue v, HandleString fallback,
1053                                   const char* arg1, const char* arg2);
1054 
1055 #define ReportValueError(cx, errorNumber, spindex, v, fallback)             \
1056   ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, spindex, v, \
1057                                fallback, nullptr, nullptr))
1058 
1059 #define ReportValueError2(cx, errorNumber, spindex, v, fallback, arg1)      \
1060   ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, spindex, v, \
1061                                fallback, arg1, nullptr))
1062 
1063 #define ReportValueError3(cx, errorNumber, spindex, v, fallback, arg1, arg2) \
1064   ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, spindex, v,  \
1065                                fallback, arg1, arg2))
1066 
1067 JSObject* CreateErrorNotesArray(JSContext* cx, JSErrorReport* report);
1068 
1069 } /* namespace js */
1070 
1071 extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
1072 
1073 namespace js {
1074 
1075 /************************************************************************/
1076 
1077 /* AutoArrayRooter roots an external array of Values. */
1078 class MOZ_RAII AutoArrayRooter : private JS::AutoGCRooter {
1079  public:
AutoArrayRooter(JSContext * cx,size_t len,Value * vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1080   AutoArrayRooter(JSContext* cx, size_t len,
1081                   Value* vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1082       : JS::AutoGCRooter(cx, len), array(vec) {
1083     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1084     MOZ_ASSERT(tag_ >= 0);
1085   }
1086 
changeLength(size_t newLength)1087   void changeLength(size_t newLength) {
1088     tag_ = ptrdiff_t(newLength);
1089     MOZ_ASSERT(tag_ >= 0);
1090   }
1091 
changeArray(Value * newArray,size_t newLength)1092   void changeArray(Value* newArray, size_t newLength) {
1093     changeLength(newLength);
1094     array = newArray;
1095   }
1096 
start()1097   Value* start() { return array; }
1098 
length()1099   size_t length() {
1100     MOZ_ASSERT(tag_ >= 0);
1101     return size_t(tag_);
1102   }
1103 
handleAt(size_t i)1104   MutableHandleValue handleAt(size_t i) {
1105     MOZ_ASSERT(i < size_t(tag_));
1106     return MutableHandleValue::fromMarkedLocation(&array[i]);
1107   }
handleAt(size_t i)1108   HandleValue handleAt(size_t i) const {
1109     MOZ_ASSERT(i < size_t(tag_));
1110     return HandleValue::fromMarkedLocation(&array[i]);
1111   }
1112   MutableHandleValue operator[](size_t i) {
1113     MOZ_ASSERT(i < size_t(tag_));
1114     return MutableHandleValue::fromMarkedLocation(&array[i]);
1115   }
1116   HandleValue operator[](size_t i) const {
1117     MOZ_ASSERT(i < size_t(tag_));
1118     return HandleValue::fromMarkedLocation(&array[i]);
1119   }
1120 
1121   friend void JS::AutoGCRooter::trace(JSTracer* trc);
1122 
1123  private:
1124   Value* array;
1125   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1126 };
1127 
1128 class AutoAssertNoException {
1129 #ifdef DEBUG
1130   JSContext* cx;
1131   bool hadException;
1132 #endif
1133 
1134  public:
AutoAssertNoException(JSContext * cx)1135   explicit AutoAssertNoException(JSContext* cx)
1136 #ifdef DEBUG
1137       : cx(cx),
1138         hadException(cx->isExceptionPending())
1139 #endif
1140   {
1141   }
1142 
~AutoAssertNoException()1143   ~AutoAssertNoException() {
1144     MOZ_ASSERT_IF(!hadException, !cx->isExceptionPending());
1145   }
1146 };
1147 
1148 class MOZ_RAII AutoLockForExclusiveAccess {
1149   JSRuntime* runtime;
1150 
init(JSRuntime * rt)1151   void init(JSRuntime* rt) {
1152     runtime = rt;
1153     if (runtime->hasHelperThreadZones()) {
1154       runtime->exclusiveAccessLock.lock();
1155     } else {
1156       MOZ_ASSERT(!runtime->activeThreadHasExclusiveAccess);
1157 #ifdef DEBUG
1158       runtime->activeThreadHasExclusiveAccess = true;
1159 #endif
1160     }
1161   }
1162 
1163  public:
AutoLockForExclusiveAccess(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1164   explicit AutoLockForExclusiveAccess(
1165       JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1166     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1167     init(cx->runtime());
1168   }
AutoLockForExclusiveAccess(JSRuntime * rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1169   explicit AutoLockForExclusiveAccess(
1170       JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1171     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1172     init(rt);
1173   }
~AutoLockForExclusiveAccess()1174   ~AutoLockForExclusiveAccess() {
1175     if (runtime->hasHelperThreadZones()) {
1176       runtime->exclusiveAccessLock.unlock();
1177     } else {
1178       MOZ_ASSERT(runtime->activeThreadHasExclusiveAccess);
1179 #ifdef DEBUG
1180       runtime->activeThreadHasExclusiveAccess = false;
1181 #endif
1182     }
1183   }
1184 
1185   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1186 };
1187 
1188 class MOZ_RAII AutoLockScriptData {
1189   JSRuntime* runtime;
1190 
1191  public:
AutoLockScriptData(JSRuntime * rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1192   explicit AutoLockScriptData(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1193     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1194     runtime = rt;
1195     if (runtime->hasHelperThreadZones()) {
1196       runtime->scriptDataLock.lock();
1197     } else {
1198       MOZ_ASSERT(!runtime->activeThreadHasScriptDataAccess);
1199 #ifdef DEBUG
1200       runtime->activeThreadHasScriptDataAccess = true;
1201 #endif
1202     }
1203   }
~AutoLockScriptData()1204   ~AutoLockScriptData() {
1205     if (runtime->hasHelperThreadZones()) {
1206       runtime->scriptDataLock.unlock();
1207     } else {
1208       MOZ_ASSERT(runtime->activeThreadHasScriptDataAccess);
1209 #ifdef DEBUG
1210       runtime->activeThreadHasScriptDataAccess = false;
1211 #endif
1212     }
1213   }
1214 
1215   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1216 };
1217 
1218 class MOZ_RAII AutoKeepAtoms {
1219   JSContext* cx;
1220   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1221 
1222  public:
AutoKeepAtoms(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1223   explicit AutoKeepAtoms(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1224       : cx(cx) {
1225     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1226     cx->keepAtoms++;
1227   }
~AutoKeepAtoms()1228   ~AutoKeepAtoms() {
1229     MOZ_ASSERT(cx->keepAtoms);
1230     cx->keepAtoms--;
1231 
1232     JSRuntime* rt = cx->runtime();
1233     if (!cx->helperThread()) {
1234       if (rt->gc.fullGCForAtomsRequested() && cx->canCollectAtoms())
1235         rt->gc.triggerFullGCForAtoms(cx);
1236     }
1237   }
1238 };
1239 
1240 // Debugging RAII class which marks the current thread as performing an Ion
1241 // compilation, for use by CurrentThreadCan{Read,Write}CompilationData
1242 class MOZ_RAII AutoEnterIonCompilation {
1243  public:
AutoEnterIonCompilation(bool safeForMinorGC MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1244   explicit AutoEnterIonCompilation(
1245       bool safeForMinorGC MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1246     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1247 
1248 #ifdef DEBUG
1249     JSContext* cx = TlsContext.get();
1250     MOZ_ASSERT(!cx->ionCompiling);
1251     MOZ_ASSERT(!cx->ionCompilingSafeForMinorGC);
1252     cx->ionCompiling = true;
1253     cx->ionCompilingSafeForMinorGC = safeForMinorGC;
1254 #endif
1255   }
1256 
~AutoEnterIonCompilation()1257   ~AutoEnterIonCompilation() {
1258 #ifdef DEBUG
1259     JSContext* cx = TlsContext.get();
1260     MOZ_ASSERT(cx->ionCompiling);
1261     cx->ionCompiling = false;
1262     cx->ionCompilingSafeForMinorGC = false;
1263 #endif
1264   }
1265 
1266   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1267 };
1268 
1269 // Should be used in functions called directly from JIT code (with
1270 // masm.callWithABI) to assert invariants in debug builds.
1271 class MOZ_RAII AutoUnsafeCallWithABI {
1272 #ifdef DEBUG
1273   JSContext* cx_;
1274   bool nested_;
1275 #endif
1276   JS::AutoCheckCannotGC nogc;
1277 
1278  public:
1279 #ifdef DEBUG
1280   AutoUnsafeCallWithABI();
1281   ~AutoUnsafeCallWithABI();
1282 #endif
1283 };
1284 
1285 namespace gc {
1286 
1287 // In debug builds, set/unset the performing GC flag for the current thread.
1288 struct MOZ_RAII AutoSetThreadIsPerformingGC {
1289 #ifdef DEBUG
AutoSetThreadIsPerformingGCAutoSetThreadIsPerformingGC1290   AutoSetThreadIsPerformingGC() : cx(TlsContext.get()) {
1291     MOZ_ASSERT(!cx->performingGC);
1292     cx->performingGC = true;
1293   }
1294 
~AutoSetThreadIsPerformingGCAutoSetThreadIsPerformingGC1295   ~AutoSetThreadIsPerformingGC() {
1296     MOZ_ASSERT(cx->performingGC);
1297     cx->performingGC = false;
1298   }
1299 
1300  private:
1301   JSContext* cx;
1302 #else
1303   AutoSetThreadIsPerformingGC() {}
1304 #endif
1305 };
1306 
1307 // In debug builds, set/unset the GC sweeping flag for the current thread.
1308 struct MOZ_RAII AutoSetThreadIsSweeping {
1309 #ifdef DEBUG
AutoSetThreadIsSweepingAutoSetThreadIsSweeping1310   AutoSetThreadIsSweeping() : cx(TlsContext.get()) {
1311     MOZ_ASSERT(!cx->gcSweeping);
1312     cx->gcSweeping = true;
1313   }
1314 
~AutoSetThreadIsSweepingAutoSetThreadIsSweeping1315   ~AutoSetThreadIsSweeping() {
1316     MOZ_ASSERT(cx->gcSweeping);
1317     cx->gcSweeping = false;
1318   }
1319 
1320  private:
1321   JSContext* cx;
1322 #else
1323   AutoSetThreadIsSweeping() {}
1324 #endif
1325 };
1326 
1327 }  // namespace gc
1328 
1329 } /* namespace js */
1330 
1331 #ifdef _MSC_VER
1332 #pragma warning(pop)
1333 #endif
1334 
1335 #endif /* vm_JSContext_h */
1336