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 /* JS execution context. */
8 
9 #ifndef vm_JSContext_h
10 #define vm_JSContext_h
11 
12 #include "mozilla/Maybe.h"
13 #include "mozilla/MemoryReporting.h"
14 
15 #include "jstypes.h"  // JS_PUBLIC_API
16 
17 #include "ds/TraceableFifo.h"
18 #include "gc/Memory.h"
19 #include "irregexp/RegExpTypes.h"
20 #include "js/CharacterEncoding.h"
21 #include "js/ContextOptions.h"  // JS::ContextOptions
22 #include "js/GCVector.h"
23 #include "js/Promise.h"
24 #include "js/Result.h"
25 #include "js/Utility.h"
26 #include "js/Vector.h"
27 #include "threading/ProtectedData.h"
28 #include "util/StructuredSpewer.h"
29 #include "vm/Activation.h"  // js::Activation
30 #include "vm/ErrorReporting.h"
31 #include "vm/MallocProvider.h"
32 #include "vm/Runtime.h"
33 #include "vm/SharedStencil.h"  // js::SharedImmutableScriptDataTable
34 #include "wasm/WasmContext.h"
35 
36 struct JS_PUBLIC_API JSContext;
37 
38 struct DtoaState;
39 
40 namespace js {
41 
42 class AutoAllocInAtomsZone;
43 class AutoMaybeLeaveAtomsZone;
44 class AutoRealm;
45 
46 namespace frontend {
47 class WellKnownParserAtoms;
48 }  // namespace frontend
49 
50 namespace jit {
51 class ICScript;
52 class JitActivation;
53 class JitContext;
54 class DebugModeOSRVolatileJitFrameIter;
55 }  // namespace jit
56 
57 namespace gc {
58 class AutoCheckCanAccessAtomsDuringGC;
59 class AutoSuppressNurseryCellAlloc;
60 }  // namespace gc
61 
62 /* Detects cycles when traversing an object graph. */
63 class MOZ_RAII AutoCycleDetector {
64  public:
65   using Vector = GCVector<JSObject*, 8>;
66 
AutoCycleDetector(JSContext * cx,HandleObject objArg)67   AutoCycleDetector(JSContext* cx, HandleObject objArg)
68       : cx(cx), obj(cx, objArg), cyclic(true) {}
69 
70   ~AutoCycleDetector();
71 
72   bool init();
73 
foundCycle()74   bool foundCycle() { return cyclic; }
75 
76  private:
77   JSContext* cx;
78   RootedObject obj;
79   bool cyclic;
80 };
81 
82 struct AutoResolving;
83 
84 struct ParseTask;
85 
86 class InternalJobQueue : public JS::JobQueue {
87  public:
InternalJobQueue(JSContext * cx)88   explicit InternalJobQueue(JSContext* cx)
89       : queue(cx, SystemAllocPolicy()), draining_(false), interrupted_(false) {}
90   ~InternalJobQueue() = default;
91 
92   // JS::JobQueue methods.
93   JSObject* getIncumbentGlobal(JSContext* cx) override;
94   bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise,
95                          JS::HandleObject job, JS::HandleObject allocationSite,
96                          JS::HandleObject incumbentGlobal) override;
97   void runJobs(JSContext* cx) override;
98   bool empty() const override;
99 
100   // If we are currently in a call to runJobs(), make that call stop processing
101   // jobs once the current one finishes, and return. If we are not currently in
102   // a call to runJobs, make all future calls return immediately.
interrupt()103   void interrupt() { interrupted_ = true; }
104 
105   // Return the front element of the queue, or nullptr if the queue is empty.
106   // This is only used by shell testing functions.
107   JSObject* maybeFront() const;
108 
109  private:
110   using Queue = js::TraceableFifo<JSObject*, 0, SystemAllocPolicy>;
111 
112   JS::PersistentRooted<Queue> queue;
113 
114   // True if we are in the midst of draining jobs from this queue. We use this
115   // to avoid re-entry (nested calls simply return immediately).
116   bool draining_;
117 
118   // True if we've been asked to interrupt draining jobs. Set by interrupt().
119   bool interrupted_;
120 
121   class SavedQueue;
122   js::UniquePtr<JobQueue::SavedJobQueue> saveJobQueue(JSContext*) override;
123 };
124 
125 class AutoLockScriptData;
126 
127 void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
128 
129 /* Thread Local Storage slot for storing the context for a thread. */
130 extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
131 
132 enum class ContextKind {
133   Uninitialized,
134 
135   // Context for the main thread of a JSRuntime.
136   MainThread,
137 
138   // Context for a helper thread.
139   HelperThread
140 };
141 
142 #ifdef DEBUG
143 JSContext* MaybeGetJSContext();
144 bool CurrentThreadIsParseThread();
145 #endif
146 
147 enum class InterruptReason : uint32_t {
148   GC = 1 << 0,
149   AttachIonCompilations = 1 << 1,
150   CallbackUrgent = 1 << 2,
151   CallbackCanWait = 1 << 3,
152 };
153 
154 } /* namespace js */
155 
156 /*
157  * A JSContext encapsulates the thread local state used when using the JS
158  * runtime.
159  */
160 struct JS_PUBLIC_API JSContext : public JS::RootingContext,
161                                  public js::MallocProvider<JSContext> {
162   JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
163   ~JSContext();
164 
165   bool init(js::ContextKind kind);
166 
167  private:
168   js::UnprotectedData<JSRuntime*> runtime_;
169   js::WriteOnceData<js::ContextKind> kind_;
170 
171   friend class js::gc::AutoSuppressNurseryCellAlloc;
172   js::ContextData<size_t> nurserySuppressions_;
173 
174   js::ContextData<JS::ContextOptions> options_;
175 
176   // Free lists for allocating in the current zone.
177   js::ContextData<js::gc::FreeLists*> freeLists_;
178 
179   // This is reset each time we switch zone, then added to the variable in the
180   // zone when we switch away from it.  This would be a js::ThreadData but we
181   // need to take its address.
182   uint32_t allocsThisZoneSinceMinorGC_;
183 
184   // Free lists for parallel allocation in the atoms zone on helper threads.
185   js::ContextData<js::gc::FreeLists*> atomsZoneFreeLists_;
186 
187   js::ContextData<JSFreeOp> defaultFreeOp_;
188 
189   // Thread that the JSContext is currently running on, if in use.
190   js::ThreadId currentThread_;
191 
192   js::ParseTask* parseTask_;
193 
194   // When a helper thread is using a context, it may need to periodically
195   // free unused memory.
196   mozilla::Atomic<bool, mozilla::ReleaseAcquire> freeUnusedMemory;
197 
198   // Are we currently timing execution? This flag ensures that we do not
199   // double-count execution time in reentrant situations.
200   js::ContextData<bool> measuringExecutionTime_;
201 
202  public:
203   // This is used by helper threads to change the runtime their context is
204   // currently operating on.
205   void setRuntime(JSRuntime* rt);
206 
207   void setHelperThread(const js::AutoLockHelperThreadState& locked);
208   void clearHelperThread(const js::AutoLockHelperThreadState& locked);
209 
contextAvailableJSContext210   bool contextAvailable(js::AutoLockHelperThreadState& locked) {
211     MOZ_ASSERT(kind_ == js::ContextKind::HelperThread);
212     return currentThread_ == js::ThreadId();
213   }
214 
setFreeUnusedMemoryJSContext215   void setFreeUnusedMemory(bool shouldFree) { freeUnusedMemory = shouldFree; }
216 
shouldFreeUnusedMemoryJSContext217   bool shouldFreeUnusedMemory() const {
218     return kind_ == js::ContextKind::HelperThread && freeUnusedMemory;
219   }
220 
isMeasuringExecutionTimeJSContext221   bool isMeasuringExecutionTime() const { return measuringExecutionTime_; }
setIsMeasuringExecutionTimeJSContext222   void setIsMeasuringExecutionTime(bool value) {
223     measuringExecutionTime_ = value;
224   }
225 
226 #ifdef DEBUG
isInitializedJSContext227   bool isInitialized() const { return kind_ != js::ContextKind::Uninitialized; }
228 #endif
229 
isMainThreadContextJSContext230   bool isMainThreadContext() const {
231     return kind_ == js::ContextKind::MainThread;
232   }
233 
isHelperThreadContextJSContext234   bool isHelperThreadContext() const {
235     return kind_ == js::ContextKind::HelperThread;
236   }
237 
freeListsJSContext238   js::gc::FreeLists& freeLists() {
239     MOZ_ASSERT(freeLists_);
240     return *freeLists_;
241   }
242 
atomsZoneFreeListsJSContext243   js::gc::FreeLists& atomsZoneFreeLists() {
244     MOZ_ASSERT(atomsZoneFreeLists_);
245     return *atomsZoneFreeLists_;
246   }
247 
248   template <typename T>
isInsideCurrentZoneJSContext249   bool isInsideCurrentZone(T thing) const {
250     return thing->zoneFromAnyThread() == zone_;
251   }
252 
253   template <typename T>
isInsideCurrentCompartmentJSContext254   inline bool isInsideCurrentCompartment(T thing) const {
255     return thing->compartment() == compartment();
256   }
257 
258   void* onOutOfMemory(js::AllocFunction allocFunc, arena_id_t arena,
259                       size_t nbytes, void* reallocPtr = nullptr) {
260     if (isHelperThreadContext()) {
261       addPendingOutOfMemory();
262       return nullptr;
263     }
264     return runtime_->onOutOfMemory(allocFunc, arena, nbytes, reallocPtr, this);
265   }
266 
267   /* Clear the pending exception (if any) due to OOM. */
268   void recoverFromOutOfMemory();
269 
reportAllocationOverflowJSContext270   void reportAllocationOverflow() { js::ReportAllocationOverflow(this); }
271 
noteTenuredAllocJSContext272   void noteTenuredAlloc() { allocsThisZoneSinceMinorGC_++; }
273 
addressOfTenuredAllocCountJSContext274   uint32_t* addressOfTenuredAllocCount() {
275     return &allocsThisZoneSinceMinorGC_;
276   }
277 
getAndResetAllocsThisZoneSinceMinorGCJSContext278   uint32_t getAndResetAllocsThisZoneSinceMinorGC() {
279     uint32_t allocs = allocsThisZoneSinceMinorGC_;
280     allocsThisZoneSinceMinorGC_ = 0;
281     return allocs;
282   }
283 
284   // Accessors for immutable runtime data.
namesJSContext285   JSAtomState& names() { return *runtime_->commonNames; }
staticStringsJSContext286   js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
sharedImmutableStringsJSContext287   js::SharedImmutableStringsCache& sharedImmutableStrings() {
288     return runtime_->sharedImmutableStrings();
289   }
permanentAtomsPopulatedJSContext290   bool permanentAtomsPopulated() { return runtime_->permanentAtomsPopulated(); }
permanentAtomsJSContext291   const js::FrozenAtomSet& permanentAtoms() {
292     return *runtime_->permanentAtoms();
293   }
wellKnownSymbolsJSContext294   js::WellKnownSymbols& wellKnownSymbols() {
295     return *runtime_->wellKnownSymbols;
296   }
emptyStringJSContext297   js::PropertyName* emptyString() { return runtime_->emptyString; }
defaultFreeOpJSContext298   JSFreeOp* defaultFreeOp() { return &defaultFreeOp_.ref(); }
stackLimitJSContext299   uintptr_t stackLimit(JS::StackKind kind) { return nativeStackLimit[kind]; }
300   uintptr_t stackLimitForJitCode(JS::StackKind kind);
gcSystemPageSizeJSContext301   size_t gcSystemPageSize() { return js::gc::SystemPageSize(); }
302 
303   /*
304    * "Entering" a realm changes cx->realm (which changes cx->global). Note
305    * that this does not push an Activation so it's possible for the caller's
306    * realm to be != cx->realm(). This is not a problem since, in general, most
307    * places in the VM cannot know that they were called from script (e.g.,
308    * they may have been called through the JSAPI via JS_CallFunction) and thus
309    * cannot expect there is a scripted caller.
310    *
311    * Realms should be entered/left in a LIFO fasion. To enter a realm, code
312    * should prefer using AutoRealm over JS::EnterRealm/JS::LeaveRealm.
313    *
314    * Also note that the JIT can enter (same-compartment) realms without going
315    * through these methods - it will update cx->realm_ directly.
316    */
317  private:
318   inline void setRealm(JS::Realm* realm);
319   inline void enterRealm(JS::Realm* realm);
320 
321   inline void enterAtomsZone();
322   inline void leaveAtomsZone(JS::Realm* oldRealm);
323   enum IsAtomsZone { AtomsZone, NotAtomsZone };
324   inline void setZone(js::Zone* zone, IsAtomsZone isAtomsZone);
325 
326   friend class js::AutoAllocInAtomsZone;
327   friend class js::AutoMaybeLeaveAtomsZone;
328   friend class js::AutoRealm;
329 
330  public:
331   inline void enterRealmOf(JSObject* target);
332   inline void enterRealmOf(JSScript* target);
333   inline void enterRealmOf(js::Shape* target);
334   inline void enterNullRealm();
335 
336   inline void setRealmForJitExceptionHandler(JS::Realm* realm);
337 
338   inline void leaveRealm(JS::Realm* oldRealm);
339 
setParseTaskJSContext340   void setParseTask(js::ParseTask* parseTask) { parseTask_ = parseTask; }
parseTaskJSContext341   js::ParseTask* parseTask() const { return parseTask_; }
342 
isNurseryAllocSuppressedJSContext343   bool isNurseryAllocSuppressed() const { return nurserySuppressions_; }
344 
345   // Threads may freely access any data in their realm, compartment and zone.
compartmentJSContext346   JS::Compartment* compartment() const {
347     return realm_ ? JS::GetCompartmentForRealm(realm_) : nullptr;
348   }
349 
realmJSContext350   JS::Realm* realm() const { return realm_; }
351 
352 #ifdef DEBUG
353   bool inAtomsZone() const;
354 #endif
355 
zoneJSContext356   JS::Zone* zone() const {
357     MOZ_ASSERT_IF(!realm() && zone_, inAtomsZone());
358     MOZ_ASSERT_IF(realm(), js::GetRealmZone(realm()) == zone_);
359     return zoneRaw();
360   }
361 
362   // For use when the context's zone is being read by another thread and the
363   // compartment and zone pointers might not be in sync.
zoneRawJSContext364   JS::Zone* zoneRaw() const { return zone_; }
365 
366   // For JIT use.
offsetOfZoneJSContext367   static size_t offsetOfZone() { return offsetof(JSContext, zone_); }
368 
369   // Current global. This is only safe to use within the scope of the
370   // AutoRealm from which it's called.
371   inline js::Handle<js::GlobalObject*> global() const;
372 
atomsJSContext373   js::AtomsTable& atoms() { return runtime_->atoms(); }
374 
atomsZoneJSContext375   const JS::Zone* atomsZone(const js::AutoAccessAtomsZone& access) {
376     return runtime_->atomsZone(access);
377   }
378 
symbolRegistryJSContext379   js::SymbolRegistry& symbolRegistry() { return runtime_->symbolRegistry(); }
380 
381   // Methods to access runtime data that must be protected by locks.
scriptDataTableJSContext382   js::SharedImmutableScriptDataTable& scriptDataTable(
383       js::AutoLockScriptData& lock) {
384     return runtime_->scriptDataTable(lock);
385   }
386 
387   // Methods to access other runtime data that checks locking internally.
atomMarkingJSContext388   js::gc::AtomMarkingRuntime& atomMarking() { return runtime_->gc.atomMarking; }
markAtomJSContext389   void markAtom(JSAtom* atom) { atomMarking().markAtom(this, atom); }
markAtomJSContext390   void markAtom(JS::Symbol* symbol) { atomMarking().markAtom(this, symbol); }
markIdJSContext391   void markId(jsid id) { atomMarking().markId(this, id); }
markAtomValueJSContext392   void markAtomValue(const js::Value& value) {
393     atomMarking().markAtomValue(this, value);
394   }
395 
396   // Methods specific to any HelperThread for the context.
397   bool addPendingCompileError(js::CompileError** err);
398   void addPendingOverRecursed();
399   void addPendingOutOfMemory();
400 
401   bool isCompileErrorPending() const;
402 
runtimeJSContext403   JSRuntime* runtime() { return runtime_; }
runtimeJSContext404   const JSRuntime* runtime() const { return runtime_; }
405 
offsetOfRealmJSContext406   static size_t offsetOfRealm() { return offsetof(JSContext, realm_); }
407 
408   friend class JS::AutoSaveExceptionState;
409   friend class js::jit::DebugModeOSRVolatileJitFrameIter;
410   friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
411 
412  public:
413   inline JS::Result<> boolToResult(bool ok);
414 
415   /**
416    * Intentionally awkward signpost method that is stationed on the
417    * boundary between Result-using and non-Result-using code.
418    */
419   template <typename V, typename E>
resultToBoolJSContext420   bool resultToBool(const JS::Result<V, E>& result) {
421     return result.isOk();
422   }
423 
424   template <typename V, typename E>
resultToPtrJSContext425   V* resultToPtr(JS::Result<V*, E>& result) {
426     return result.isOk() ? result.unwrap() : nullptr;
427   }
428 
429   mozilla::GenericErrorResult<JS::OOM> alreadyReportedOOM();
430   mozilla::GenericErrorResult<JS::Error> alreadyReportedError();
431 
432   /*
433    * Points to the most recent JitActivation pushed on the thread.
434    * See JitActivation constructor in vm/Stack.cpp
435    */
436   js::ContextData<js::jit::JitActivation*> jitActivation;
437 
438   // Shim for V8 interfaces used by irregexp code
439   js::ContextData<js::irregexp::Isolate*> isolate;
440 
441   /*
442    * Points to the most recent activation running on the thread.
443    * See Activation comment in vm/Stack.h.
444    */
445   js::ContextData<js::Activation*> activation_;
446 
447   /*
448    * Points to the most recent profiling activation running on the
449    * thread.
450    */
451   js::Activation* volatile profilingActivation_;
452 
453  public:
activationJSContext454   js::Activation* activation() const { return activation_; }
offsetOfActivationJSContext455   static size_t offsetOfActivation() {
456     return offsetof(JSContext, activation_);
457   }
458 
profilingActivationJSContext459   js::Activation* profilingActivation() const { return profilingActivation_; }
offsetOfProfilingActivationJSContext460   static size_t offsetOfProfilingActivation() {
461     return offsetof(JSContext, profilingActivation_);
462   }
463 
offsetOfJitActivationJSContext464   static size_t offsetOfJitActivation() {
465     return offsetof(JSContext, jitActivation);
466   }
467 
468 #ifdef DEBUG
offsetOfInUnsafeCallWithABIJSContext469   static size_t offsetOfInUnsafeCallWithABI() {
470     return offsetof(JSContext, inUnsafeCallWithABI);
471   }
472 #endif
473 
offsetOfInlinedICScriptJSContext474   static size_t offsetOfInlinedICScript() {
475     return offsetof(JSContext, inlinedICScript_);
476   }
477 
478  public:
interpreterStackJSContext479   js::InterpreterStack& interpreterStack() {
480     return runtime()->interpreterStack();
481   }
482 
483  private:
484   // Base address of the native stack for the current thread.
485   mozilla::Maybe<uintptr_t> nativeStackBase_;
486 
487  public:
nativeStackBaseJSContext488   uintptr_t nativeStackBase() const { return *nativeStackBase_; }
489 
490  public:
491   /* If non-null, report JavaScript entry points to this monitor. */
492   js::ContextData<JS::dbg::AutoEntryMonitor*> entryMonitor;
493 
494   /*
495    * Stack of debuggers that currently disallow debuggee execution.
496    *
497    * When we check for NX we are inside the debuggee compartment, and thus a
498    * stack of Debuggers that have prevented execution need to be tracked to
499    * enter the correct Debugger compartment to report the error.
500    */
501   js::ContextData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
502 
503 #ifdef DEBUG
504   js::ContextData<uint32_t> inUnsafeCallWithABI;
505   js::ContextData<bool> hasAutoUnsafeCallWithABI;
506 #endif
507 
508 #ifdef JS_SIMULATOR
509  private:
510   js::ContextData<js::jit::Simulator*> simulator_;
511 
512  public:
513   js::jit::Simulator* simulator() const;
514   uintptr_t* addressOfSimulatorStackLimit();
515 #endif
516 
517 #ifdef JS_TRACE_LOGGING
518   js::UnprotectedData<js::TraceLoggerThread*> traceLogger;
519 #endif
520 
521  public:
522   // State used by util/DoubleToString.cpp.
523   js::ContextData<DtoaState*> dtoaState;
524 
525   /*
526    * When this flag is non-zero, any attempt to GC will be skipped. See the
527    * AutoSuppressGC class for for details.
528    */
529   js::ContextData<int32_t> suppressGC;
530 
531   // clang-format off
532   enum class GCUse {
533     // This thread is not running in the garbage collector.
534     None,
535 
536     // This thread is currently marking GC things. This thread could be the main
537     // thread or a helper thread doing sweep-marking.
538     Marking,
539 
540     // This thread is currently sweeping GC things. This thread could be the
541     // main thread or a helper thread while the main thread is running the
542     // mutator.
543     Sweeping,
544 
545     // Whether this thread is currently finalizing GC things. This thread could
546     // be the main thread or a helper thread doing finalization while the main
547     // thread is running the mutator.
548     Finalizing
549   };
550   // clang-format on
551 
552 #ifdef DEBUG
553   // Which part of the garbage collector this context is running at the moment.
554   js::ContextData<GCUse> gcUse;
555 
556   // The specific zone currently being swept, if any.
557   js::ContextData<JS::Zone*> gcSweepZone;
558 
559   // Whether this thread is currently manipulating possibly-gray GC things.
560   js::ContextData<size_t> isTouchingGrayThings;
561 
562   js::ContextData<size_t> noNurseryAllocationCheck;
563 
564   /*
565    * If this is 0, all cross-compartment proxies must be registered in the
566    * wrapper map. This checking must be disabled temporarily while creating
567    * new wrappers. When non-zero, this records the recursion depth of wrapper
568    * creation.
569    */
570   js::ContextData<uintptr_t> disableStrictProxyCheckingCount;
571 
isNurseryAllocAllowedJSContext572   bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; }
disallowNurseryAllocJSContext573   void disallowNurseryAlloc() { ++noNurseryAllocationCheck; }
allowNurseryAllocJSContext574   void allowNurseryAlloc() {
575     MOZ_ASSERT(!isNurseryAllocAllowed());
576     --noNurseryAllocationCheck;
577   }
578 
isStrictProxyCheckingEnabledJSContext579   bool isStrictProxyCheckingEnabled() {
580     return disableStrictProxyCheckingCount == 0;
581   }
disableStrictProxyCheckingJSContext582   void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; }
enableStrictProxyCheckingJSContext583   void enableStrictProxyChecking() {
584     MOZ_ASSERT(disableStrictProxyCheckingCount > 0);
585     --disableStrictProxyCheckingCount;
586   }
587 #endif
588 
589 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
590   // We are currently running a simulated OOM test.
591   js::ContextData<bool> runningOOMTest;
592 #endif
593 
594 #ifdef DEBUG
595   js::ContextData<bool> disableCompartmentCheckTracer;
596 #endif
597 
598   /*
599    * Some regions of code are hard for the static rooting hazard analysis to
600    * understand. In those cases, we trade the static analysis for a dynamic
601    * analysis. When this is non-zero, we should assert if we trigger, or
602    * might trigger, a GC.
603    */
604   js::ContextData<int> inUnsafeRegion;
605 
606   // Count of AutoDisableGenerationalGC instances on the thread's stack.
607   js::ContextData<unsigned> generationalDisabled;
608 
609   // Some code cannot tolerate compacting GC so it can be disabled temporarily
610   // with AutoDisableCompactingGC which uses this counter.
611   js::ContextData<unsigned> compactingDisabledCount;
612 
canCollectAtomsJSContext613   bool canCollectAtoms() const {
614     // TODO: We may be able to improve this by collecting if
615     // !isOffThreadParseRunning() (bug 1468422).
616     return !runtime()->hasHelperThreadZones();
617   }
618 
619  private:
620   // Pools used for recycling name maps and vectors when parsing and
621   // emitting bytecode. Purged on GC when there are no active script
622   // compilations.
623   js::ContextData<js::frontend::NameCollectionPool> frontendCollectionPool_;
624 
625  public:
frontendCollectionPoolJSContext626   js::frontend::NameCollectionPool& frontendCollectionPool() {
627     return frontendCollectionPool_.ref();
628   }
629 
verifyIsSafeToGCJSContext630   void verifyIsSafeToGC() {
631     MOZ_DIAGNOSTIC_ASSERT(!inUnsafeRegion,
632                           "[AutoAssertNoGC] possible GC in GC-unsafe region");
633   }
634 
635   /* Whether sampling should be enabled or not. */
636  private:
637   mozilla::Atomic<bool, mozilla::SequentiallyConsistent>
638       suppressProfilerSampling;
639 
640  public:
isProfilerSamplingEnabledJSContext641   bool isProfilerSamplingEnabled() const { return !suppressProfilerSampling; }
disableProfilerSamplingJSContext642   void disableProfilerSampling() { suppressProfilerSampling = true; }
enableProfilerSamplingJSContext643   void enableProfilerSampling() { suppressProfilerSampling = false; }
644 
645  private:
646   js::wasm::Context wasm_;
647 
648  public:
wasmJSContext649   js::wasm::Context& wasm() { return wasm_; }
650 
651   /* Temporary arena pool used while compiling and decompiling. */
652   static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
653 
654  private:
655   js::ContextData<js::LifoAlloc> tempLifoAlloc_;
656 
657  public:
tempLifoAllocJSContext658   js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
tempLifoAllocJSContext659   const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
tempLifoAllocNoCheckJSContext660   js::LifoAlloc& tempLifoAllocNoCheck() { return tempLifoAlloc_.refNoCheck(); }
661 
662   js::ContextData<uint32_t> debuggerMutations;
663 
664   // Cache for jit::GetPcScript().
665   js::ContextData<js::UniquePtr<js::jit::PcScriptCache>> ionPcScriptCache;
666 
667  private:
668   /* Exception state -- the exception member is a GC root by definition. */
669   js::ContextData<bool> throwing; /* is there a pending exception? */
670   js::ContextData<JS::PersistentRooted<JS::Value>>
671       unwrappedException_; /* most-recently-thrown exception */
672   js::ContextData<JS::PersistentRooted<js::SavedFrame*>>
673       unwrappedExceptionStack_; /* stack when the exception was thrown */
674 
unwrappedExceptionJSContext675   JS::Value& unwrappedException() {
676     if (!unwrappedException_.ref().initialized()) {
677       unwrappedException_.ref().init(this);
678     }
679     return unwrappedException_.ref().get();
680   }
681 
unwrappedExceptionStackJSContext682   js::SavedFrame*& unwrappedExceptionStack() {
683     if (!unwrappedExceptionStack_.ref().initialized()) {
684       unwrappedExceptionStack_.ref().init(this);
685     }
686     return unwrappedExceptionStack_.ref().get();
687   }
688 
689   // True if the exception currently being thrown is by result of
690   // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
691   js::ContextData<bool> overRecursed_;
692 
693 #ifdef DEBUG
694   // True if this context has ever called ReportOverRecursed.
695   js::ContextData<bool> hadOverRecursed_;
696 
697  public:
hadNondeterministicExceptionJSContext698   bool hadNondeterministicException() const {
699     return hadOverRecursed_ || runtime()->hadOutOfMemory;
700   }
701 #endif
702 
703  private:
704   // True if propagating a forced return from an interrupt handler during
705   // debug mode.
706   js::ContextData<bool> propagatingForcedReturn_;
707 
708  public:
709   js::ContextData<int32_t> reportGranularity; /* see vm/Probes.h */
710 
711   js::ContextData<js::AutoResolving*> resolvingList;
712 
713 #ifdef DEBUG
714   js::ContextData<js::AutoEnterPolicy*> enteredPolicy;
715 #endif
716 
717   /* True if generating an error, to prevent runaway recursion. */
718   js::ContextData<bool> generatingError;
719 
720  private:
721   /* State for object and array toSource conversion. */
722   js::ContextData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
723 
724  public:
cycleDetectorVectorJSContext725   js::AutoCycleDetector::Vector& cycleDetectorVector() {
726     return cycleDetectorVector_.ref();
727   }
cycleDetectorVectorJSContext728   const js::AutoCycleDetector::Vector& cycleDetectorVector() const {
729     return cycleDetectorVector_.ref();
730   }
731 
732   /* Client opaque pointer. */
733   js::UnprotectedData<void*> data;
734 
735   void initJitStackLimit();
736   void resetJitStackLimit();
737 
738  public:
optionsJSContext739   JS::ContextOptions& options() { return options_.ref(); }
740 
runtimeMatchesJSContext741   bool runtimeMatches(JSRuntime* rt) const { return runtime_ == rt; }
742 
743  private:
744   /*
745    * Youngest frame of a saved stack that will be picked up as an async stack
746    * by any new Activation, and is nullptr when no async stack should be used.
747    *
748    * The JS::AutoSetAsyncStackForNewCalls class can be used to set this.
749    *
750    * New activations will reset this to nullptr on construction after getting
751    * the current value, and will restore the previous value on destruction.
752    */
753   js::ContextData<JS::PersistentRooted<js::SavedFrame*>>
754       asyncStackForNewActivations_;
755 
756  public:
asyncStackForNewActivationsJSContext757   js::SavedFrame*& asyncStackForNewActivations() {
758     if (!asyncStackForNewActivations_.ref().initialized()) {
759       asyncStackForNewActivations_.ref().init(this);
760     }
761     return asyncStackForNewActivations_.ref().get();
762   }
763 
764   /*
765    * Value of asyncCause to be attached to asyncStackForNewActivations.
766    */
767   js::ContextData<const char*> asyncCauseForNewActivations;
768 
769   /*
770    * True if the async call was explicitly requested, e.g. via
771    * callFunctionWithAsyncStack.
772    */
773   js::ContextData<bool> asyncCallIsExplicit;
774 
currentlyRunningInInterpreterJSContext775   bool currentlyRunningInInterpreter() const {
776     return activation()->isInterpreter();
777   }
currentlyRunningInJitJSContext778   bool currentlyRunningInJit() const { return activation()->isJit(); }
interpreterFrameJSContext779   js::InterpreterFrame* interpreterFrame() const {
780     return activation()->asInterpreter()->current();
781   }
interpreterRegsJSContext782   js::InterpreterRegs& interpreterRegs() const {
783     return activation()->asInterpreter()->regs();
784   }
785 
786   /*
787    * Get the topmost script and optional pc on the stack. By default, this
788    * function only returns a JSScript in the current realm, returning nullptr
789    * if the current script is in a different realm. This behavior can be
790    * overridden by passing AllowCrossRealm::Allow.
791    */
792   enum class AllowCrossRealm { DontAllow = false, Allow = true };
793   inline JSScript* currentScript(
794       jsbytecode** pc = nullptr,
795       AllowCrossRealm allowCrossRealm = AllowCrossRealm::DontAllow) const;
796 
797   inline js::Nursery& nursery();
798   inline void minorGC(JS::GCReason reason);
799 
800  public:
isExceptionPendingJSContext801   bool isExceptionPending() const { return throwing; }
802 
803   [[nodiscard]] bool getPendingException(JS::MutableHandleValue rval);
804 
805   js::SavedFrame* getPendingExceptionStack();
806 
807   bool isThrowingOutOfMemory();
808   bool isThrowingDebuggeeWouldRun();
809   bool isClosingGenerator();
810 
811   void setPendingException(JS::HandleValue v, js::HandleSavedFrame stack);
812   void setPendingExceptionAndCaptureStack(JS::HandleValue v);
813 
clearPendingExceptionJSContext814   void clearPendingException() {
815     throwing = false;
816     overRecursed_ = false;
817     unwrappedException().setUndefined();
818     unwrappedExceptionStack() = nullptr;
819   }
820 
isThrowingOverRecursedJSContext821   bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
isPropagatingForcedReturnJSContext822   bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
setPropagatingForcedReturnJSContext823   void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
clearPropagatingForcedReturnJSContext824   void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
825 
826   /*
827    * See JS_SetTrustedPrincipals in jsapi.h.
828    * Note: !cx->realm() is treated as trusted.
829    */
830   inline bool runningWithTrustedPrincipals();
831 
832   size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
833   size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
834 
835   void trace(JSTracer* trc);
836 
837   inline js::RuntimeCaches& caches();
838 
839  public:
840   using InterruptCallbackVector =
841       js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
842 
843  private:
844   js::ContextData<InterruptCallbackVector> interruptCallbacks_;
845 
846  public:
interruptCallbacksJSContext847   InterruptCallbackVector& interruptCallbacks() {
848     return interruptCallbacks_.ref();
849   }
850 
851   js::ContextData<bool> interruptCallbackDisabled;
852 
853   // Bitfield storing InterruptReason values.
854   mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptBits_;
855 
856   // Any thread can call requestInterrupt() to request that this thread
857   // stop running. To stop this thread, requestInterrupt sets two fields:
858   // interruptBits_ (a bitset of InterruptReasons) and jitStackLimit_ (set to
859   // UINTPTR_MAX). The JS engine must continually poll one of these fields
860   // and call handleInterrupt if either field has the interrupt value.
861   //
862   // The point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code
863   // already needs to guard on jitStackLimit_ in every function prologue to
864   // avoid stack overflow, so we avoid a second branch on interruptBits_ by
865   // setting jitStackLimit_ to a value that is guaranteed to fail the guard.)
866   //
867   // Note that the writes to interruptBits_ and jitStackLimit_ use a Relaxed
868   // Atomic so, while the writes are guaranteed to eventually be visible to
869   // this thread, it can happen in any order. handleInterrupt calls the
870   // interrupt callback if either is set, so it really doesn't matter as long
871   // as the JS engine is continually polling at least one field. In corner
872   // cases, this relaxed ordering could lead to an interrupt handler being
873   // called twice in succession after a single requestInterrupt call, but
874   // that's fine.
875   void requestInterrupt(js::InterruptReason reason);
876   bool handleInterrupt();
877 
hasAnyPendingInterruptJSContext878   MOZ_ALWAYS_INLINE bool hasAnyPendingInterrupt() const {
879     static_assert(sizeof(interruptBits_) == sizeof(uint32_t),
880                   "Assumed by JIT callers");
881     return interruptBits_ != 0;
882   }
hasPendingInterruptJSContext883   bool hasPendingInterrupt(js::InterruptReason reason) const {
884     return interruptBits_ & uint32_t(reason);
885   }
886 
887   // For JIT use. Points to the inlined ICScript for a baseline script
888   // being invoked as part of a trial inlining.  Contains nullptr at
889   // all times except for the brief moment between being set in the
890   // caller and read in the callee's prologue.
891   js::ContextData<js::jit::ICScript*> inlinedICScript_;
892 
893  public:
addressOfInterruptBitsJSContext894   void* addressOfInterruptBits() { return &interruptBits_; }
addressOfJitStackLimitJSContext895   void* addressOfJitStackLimit() { return &jitStackLimit; }
addressOfJitStackLimitNoInterruptJSContext896   void* addressOfJitStackLimitNoInterrupt() {
897     return &jitStackLimitNoInterrupt;
898   }
addressOfZoneJSContext899   void* addressOfZone() { return &zone_; }
900 
addressOfRealmJSContext901   const void* addressOfRealm() const { return &realm_; }
902 
addressOfInlinedICScriptJSContext903   void* addressOfInlinedICScript() { return &inlinedICScript_; }
904 
905   // Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics
906   // object.
907   js::FutexThread fx;
908 
909   mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
910 
911   // Like jitStackLimit, but not reset to trigger interrupts.
912   js::ContextData<uintptr_t> jitStackLimitNoInterrupt;
913 
914   // Queue of pending jobs as described in ES2016 section 8.4.
915   //
916   // This is a non-owning pointer to either:
917   // - a JobQueue implementation the embedding provided by calling
918   //   JS::SetJobQueue, owned by the embedding, or
919   // - our internal JobQueue implementation, established by calling
920   //   js::UseInternalJobQueues, owned by JSContext::internalJobQueue below.
921   js::ContextData<JS::JobQueue*> jobQueue;
922 
923   // If the embedding has called js::UseInternalJobQueues, this is the owning
924   // pointer to our internal JobQueue implementation, which JSContext::jobQueue
925   // borrows.
926   js::ContextData<js::UniquePtr<js::InternalJobQueue>> internalJobQueue;
927 
928   // True if jobQueue is empty, or we are running the last job in the queue.
929   // Such conditions permit optimizations around `await` expressions.
930   js::ContextData<bool> canSkipEnqueuingJobs;
931 
932   js::ContextData<JS::PromiseRejectionTrackerCallback>
933       promiseRejectionTrackerCallback;
934   js::ContextData<void*> promiseRejectionTrackerCallbackData;
935 
936   JSObject* getIncumbentGlobal(JSContext* cx);
937   bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
938                          js::HandleObject promise,
939                          js::HandleObject incumbentGlobal);
940   void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
941   void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
942 
943  private:
944   template <class... Args>
945   inline void checkImpl(const Args&... args);
946 
contextChecksEnabledJSContext947   bool contextChecksEnabled() const {
948     // Don't perform these checks when called from a finalizer. The checking
949     // depends on other objects not having been swept yet.
950     return !RuntimeHeapIsCollecting(runtime()->heapState());
951   }
952 
953  public:
954   // Assert the arguments are in this context's realm (for scripts),
955   // compartment (for objects) or zone (for strings, symbols).
956   template <class... Args>
957   inline void check(const Args&... args);
958   template <class... Args>
959   inline void releaseCheck(const Args&... args);
960   template <class... Args>
961   MOZ_ALWAYS_INLINE void debugOnlyCheck(const Args&... args);
962 
963 #ifdef JS_STRUCTURED_SPEW
964  private:
965   // Spewer for this thread
966   js::UnprotectedData<js::StructuredSpewer> structuredSpewer_;
967 
968  public:
spewerJSContext969   js::StructuredSpewer& spewer() { return structuredSpewer_.ref(); }
970 #endif
971 
972   // During debugger evaluations which need to observe native calls, JITs are
973   // completely disabled. This flag indicates whether we are in this state, and
974   // the debugger which initiated the evaluation. This debugger has other
975   // references on the stack and does not need to be traced.
976   js::ContextData<js::Debugger*> insideDebuggerEvaluationWithOnNativeCallHook;
977 
978 }; /* struct JSContext */
979 
boolToResult(bool ok)980 inline JS::Result<> JSContext::boolToResult(bool ok) {
981   if (MOZ_LIKELY(ok)) {
982     MOZ_ASSERT(!isExceptionPending());
983     MOZ_ASSERT(!isPropagatingForcedReturn());
984     return JS::Ok();
985   }
986   return JS::Result<>(JS::Error());
987 }
988 
mainContextFromOwnThread()989 inline JSContext* JSRuntime::mainContextFromOwnThread() {
990   MOZ_ASSERT(mainContextFromAnyThread() == js::TlsContext.get());
991   return mainContextFromAnyThread();
992 }
993 
994 namespace js {
995 
996 struct MOZ_RAII AutoResolving {
997  public:
998   enum Kind { LOOKUP, WATCH };
999 
1000   AutoResolving(JSContext* cx, HandleObject obj, HandleId id,
1001                 Kind kind = LOOKUP)
contextAutoResolving1002       : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList) {
1003     MOZ_ASSERT(obj);
1004     cx->resolvingList = this;
1005   }
1006 
~AutoResolvingAutoResolving1007   ~AutoResolving() {
1008     MOZ_ASSERT(context->resolvingList == this);
1009     context->resolvingList = link;
1010   }
1011 
alreadyStartedAutoResolving1012   bool alreadyStarted() const { return link && alreadyStartedSlow(); }
1013 
1014  private:
1015   bool alreadyStartedSlow() const;
1016 
1017   JSContext* const context;
1018   HandleObject object;
1019   HandleId id;
1020   Kind const kind;
1021   AutoResolving* const link;
1022 };
1023 
1024 /*
1025  * Create and destroy functions for JSContext, which is manually allocated
1026  * and exclusively owned.
1027  */
1028 extern JSContext* NewContext(uint32_t maxBytes, JSRuntime* parentRuntime);
1029 
1030 extern void DestroyContext(JSContext* cx);
1031 
1032 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
1033 extern void ReportUsageErrorASCII(JSContext* cx, HandleObject callee,
1034                                   const char* msg);
1035 
1036 extern void ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
1037 
1038 extern void ReportIsNotDefined(JSContext* cx, HandleId id);
1039 
1040 /*
1041  * Report an attempt to access the property of a null or undefined value (v).
1042  */
1043 extern void ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx,
1044                                                      HandleValue v, int vIndex);
1045 extern void ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx,
1046                                                      HandleValue v, int vIndex,
1047                                                      HandleId key);
1048 
1049 /*
1050  * Report error using js::DecompileValueGenerator(cx, spindex, v, fallback) as
1051  * the first argument for the error message.
1052  */
1053 extern bool ReportValueError(JSContext* cx, const unsigned errorNumber,
1054                              int spindex, HandleValue v, HandleString fallback,
1055                              const char* arg1 = nullptr,
1056                              const char* arg2 = nullptr);
1057 
1058 JSObject* CreateErrorNotesArray(JSContext* cx, JSErrorReport* report);
1059 
1060 /************************************************************************/
1061 
1062 /*
1063  * Encapsulates an external array of values and adds a trace method, for use in
1064  * Rooted.
1065  */
1066 class MOZ_STACK_CLASS ExternalValueArray {
1067  public:
ExternalValueArray(size_t len,Value * vec)1068   ExternalValueArray(size_t len, Value* vec) : array_(vec), length_(len) {}
1069 
begin()1070   Value* begin() { return array_; }
length()1071   size_t length() { return length_; }
1072 
1073   void trace(JSTracer* trc);
1074 
1075  private:
1076   Value* array_;
1077   size_t length_;
1078 };
1079 
1080 /* RootedExternalValueArray roots an external array of Values. */
1081 class MOZ_RAII RootedExternalValueArray
1082     : public JS::Rooted<ExternalValueArray> {
1083  public:
RootedExternalValueArray(JSContext * cx,size_t len,Value * vec)1084   RootedExternalValueArray(JSContext* cx, size_t len, Value* vec)
1085       : JS::Rooted<ExternalValueArray>(cx, ExternalValueArray(len, vec)) {}
1086 
1087  private:
1088 };
1089 
1090 class AutoAssertNoPendingException {
1091 #ifdef DEBUG
1092   JSContext* cx_;
1093 
1094  public:
AutoAssertNoPendingException(JSContext * cxArg)1095   explicit AutoAssertNoPendingException(JSContext* cxArg) : cx_(cxArg) {
1096     MOZ_ASSERT(!JS_IsExceptionPending(cx_));
1097   }
1098 
~AutoAssertNoPendingException()1099   ~AutoAssertNoPendingException() { MOZ_ASSERT(!JS_IsExceptionPending(cx_)); }
1100 #else
1101  public:
1102   explicit AutoAssertNoPendingException(JSContext* cxArg) {}
1103 #endif
1104 };
1105 
1106 class MOZ_RAII AutoLockScriptData {
1107   JSRuntime* runtime;
1108 
1109  public:
AutoLockScriptData(JSRuntime * rt)1110   explicit AutoLockScriptData(JSRuntime* rt) {
1111     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt) ||
1112                CurrentThreadIsParseThread());
1113     runtime = rt;
1114     if (runtime->hasParseTasks()) {
1115       runtime->scriptDataLock.lock();
1116     } else {
1117       MOZ_ASSERT(!runtime->activeThreadHasScriptDataAccess);
1118 #ifdef DEBUG
1119       runtime->activeThreadHasScriptDataAccess = true;
1120 #endif
1121     }
1122   }
~AutoLockScriptData()1123   ~AutoLockScriptData() {
1124     if (runtime->hasParseTasks()) {
1125       runtime->scriptDataLock.unlock();
1126     } else {
1127       MOZ_ASSERT(runtime->activeThreadHasScriptDataAccess);
1128 #ifdef DEBUG
1129       runtime->activeThreadHasScriptDataAccess = false;
1130 #endif
1131     }
1132   }
1133 };
1134 
1135 // A token used to prove you can safely access the atoms zone. This zone is
1136 // accessed by the main thread and by off-thread parsing. There are two
1137 // situations in which it is safe:
1138 //
1139 //  - the current thread holds all atoms table locks (off-thread parsing may be
1140 //    running and must also take one of these locks for access)
1141 //
1142 //  - the GC is running and is collecting the atoms zone (this cannot be started
1143 //    while off-thread parsing is happening)
1144 class MOZ_STACK_CLASS AutoAccessAtomsZone {
1145  public:
AutoAccessAtomsZone(const AutoLockAllAtoms & lock)1146   MOZ_IMPLICIT AutoAccessAtomsZone(const AutoLockAllAtoms& lock) {}
AutoAccessAtomsZone(const gc::AutoCheckCanAccessAtomsDuringGC & canAccess)1147   MOZ_IMPLICIT AutoAccessAtomsZone(
1148       const gc::AutoCheckCanAccessAtomsDuringGC& canAccess) {}
1149 };
1150 
1151 class MOZ_RAII AutoNoteDebuggerEvaluationWithOnNativeCallHook {
1152   JSContext* cx;
1153   Debugger* oldValue;
1154 
1155  public:
AutoNoteDebuggerEvaluationWithOnNativeCallHook(JSContext * cx,Debugger * dbg)1156   AutoNoteDebuggerEvaluationWithOnNativeCallHook(JSContext* cx, Debugger* dbg)
1157       : cx(cx), oldValue(cx->insideDebuggerEvaluationWithOnNativeCallHook) {
1158     cx->insideDebuggerEvaluationWithOnNativeCallHook = dbg;
1159   }
1160 
~AutoNoteDebuggerEvaluationWithOnNativeCallHook()1161   ~AutoNoteDebuggerEvaluationWithOnNativeCallHook() {
1162     cx->insideDebuggerEvaluationWithOnNativeCallHook = oldValue;
1163   }
1164 };
1165 
1166 enum UnsafeABIStrictness {
1167   NoExceptions,
1168   AllowPendingExceptions,
1169   AllowThrownExceptions
1170 };
1171 
1172 // Should be used in functions called directly from JIT code (with
1173 // masm.callWithABI) to assert invariants in debug builds.
1174 // In debug mode, masm.callWithABI inserts code to verify that the
1175 // callee function uses AutoUnsafeCallWithABI.
1176 // While this object is live:
1177 // 1. cx->hasAutoUnsafeCallWithABI must be true.
1178 // 2. We can't GC.
1179 // 3. Exceptions should not be pending/thrown.
1180 //
1181 // Note that #3 is a precaution, not a requirement. By default, we
1182 // assert that the function is not called with a pending exception,
1183 // and that it does not throw an exception itself.
1184 class MOZ_RAII AutoUnsafeCallWithABI {
1185 #ifdef DEBUG
1186   JSContext* cx_;
1187   bool nested_;
1188   bool checkForPendingException_;
1189 #endif
1190   JS::AutoCheckCannotGC nogc;
1191 
1192  public:
1193 #ifdef DEBUG
1194   explicit AutoUnsafeCallWithABI(
1195       UnsafeABIStrictness strictness = UnsafeABIStrictness::NoExceptions);
1196   ~AutoUnsafeCallWithABI();
1197 #else
1198   explicit AutoUnsafeCallWithABI(
1199       UnsafeABIStrictness unused_ = UnsafeABIStrictness::NoExceptions) {}
1200 #endif
1201 };
1202 
1203 namespace gc {
1204 
1205 // Set/restore the performing GC flag for the current thread.
1206 class MOZ_RAII AutoSetThreadIsPerformingGC {
1207   JSContext* cx;
1208   bool prev;
1209 
1210  public:
AutoSetThreadIsPerformingGC()1211   AutoSetThreadIsPerformingGC()
1212       : cx(TlsContext.get()), prev(cx->defaultFreeOp()->isCollecting_) {
1213     cx->defaultFreeOp()->isCollecting_ = true;
1214   }
1215 
~AutoSetThreadIsPerformingGC()1216   ~AutoSetThreadIsPerformingGC() { cx->defaultFreeOp()->isCollecting_ = prev; }
1217 };
1218 
1219 struct MOZ_RAII AutoSetThreadGCUse {
1220  protected:
1221 #ifndef DEBUG
1222   explicit AutoSetThreadGCUse(JSContext::GCUse use, Zone* sweepZone = nullptr) {
1223   }
1224 #else
1225   explicit AutoSetThreadGCUse(JSContext::GCUse use, Zone* sweepZone = nullptr)
1226       : cx(TlsContext.get()), prevUse(cx->gcUse), prevZone(cx->gcSweepZone) {
1227     MOZ_ASSERT_IF(sweepZone, use == JSContext::GCUse::Sweeping);
1228     cx->gcUse = use;
1229     cx->gcSweepZone = sweepZone;
1230   }
1231 
1232   ~AutoSetThreadGCUse() {
1233     cx->gcUse = prevUse;
1234     cx->gcSweepZone = prevZone;
1235     MOZ_ASSERT_IF(cx->gcUse == JSContext::GCUse::None, !cx->gcSweepZone);
1236   }
1237 
1238  private:
1239   JSContext* cx;
1240   JSContext::GCUse prevUse;
1241   JS::Zone* prevZone;
1242 #endif
1243 };
1244 
1245 // In debug builds, update the context state to indicate that the current thread
1246 // is being used for GC marking.
1247 struct MOZ_RAII AutoSetThreadIsMarking : public AutoSetThreadGCUse {
AutoSetThreadIsMarkingAutoSetThreadIsMarking1248   explicit AutoSetThreadIsMarking()
1249       : AutoSetThreadGCUse(JSContext::GCUse::Marking) {}
1250 };
1251 
1252 // In debug builds, update the context state to indicate that the current thread
1253 // is being used for GC sweeping.
1254 struct MOZ_RAII AutoSetThreadIsSweeping : public AutoSetThreadGCUse {
1255   explicit AutoSetThreadIsSweeping(Zone* zone = nullptr)
AutoSetThreadGCUseAutoSetThreadIsSweeping1256       : AutoSetThreadGCUse(JSContext::GCUse::Sweeping, zone) {}
1257 };
1258 
1259 // In debug builds, update the context state to indicate that the current thread
1260 // is being used for GC finalization.
1261 struct MOZ_RAII AutoSetThreadIsFinalizing : public AutoSetThreadGCUse {
AutoSetThreadIsFinalizingAutoSetThreadIsFinalizing1262   explicit AutoSetThreadIsFinalizing()
1263       : AutoSetThreadGCUse(JSContext::GCUse::Finalizing) {}
1264 };
1265 
1266 // Note that this class does not suppress buffer allocation/reallocation in the
1267 // nursery, only Cells themselves.
1268 class MOZ_RAII AutoSuppressNurseryCellAlloc {
1269   JSContext* cx_;
1270 
1271  public:
AutoSuppressNurseryCellAlloc(JSContext * cx)1272   explicit AutoSuppressNurseryCellAlloc(JSContext* cx) : cx_(cx) {
1273     cx_->nurserySuppressions_++;
1274   }
~AutoSuppressNurseryCellAlloc()1275   ~AutoSuppressNurseryCellAlloc() { cx_->nurserySuppressions_--; }
1276 };
1277 
1278 }  // namespace gc
1279 
1280 } /* namespace js */
1281 
1282 #define CHECK_THREAD(cx)                            \
1283   MOZ_ASSERT_IF(cx, !cx->isHelperThreadContext() && \
1284                         js::CurrentThreadCanAccessRuntime(cx->runtime()))
1285 
1286 #endif /* vm_JSContext_h */
1287