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