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/MemoryReporting.h"
13 
14 #include "jstypes.h"  // JS_PUBLIC_API
15 
16 #include "ds/TraceableFifo.h"
17 #include "gc/Memory.h"
18 #include "js/CharacterEncoding.h"
19 #include "js/ContextOptions.h"  // JS::ContextOptions
20 #include "js/GCVector.h"
21 #include "js/Promise.h"
22 #include "js/Result.h"
23 #include "js/Utility.h"
24 #include "js/Vector.h"
25 #ifdef ENABLE_NEW_REGEXP
26 #  include "new-regexp/RegExpTypes.h"
27 #endif
28 #include "threading/ProtectedData.h"
29 #include "util/StructuredSpewer.h"
30 #include "vm/Activation.h"  // js::Activation
31 #include "vm/ErrorReporting.h"
32 #include "vm/MallocProvider.h"
33 #include "vm/Runtime.h"
34 
35 struct JS_PUBLIC_API JSContext;
36 
37 struct DtoaState;
38 
39 namespace js {
40 
41 class AutoAllocInAtomsZone;
42 class AutoMaybeLeaveAtomsZone;
43 class AutoRealm;
44 
45 namespace jit {
46 class JitActivation;
47 class JitContext;
48 class DebugModeOSRVolatileJitFrameIter;
49 }  // namespace jit
50 
51 namespace gc {
52 class AutoCheckCanAccessAtomsDuringGC;
53 class AutoSuppressNurseryCellAlloc;
54 }  // namespace gc
55 
56 /* Detects cycles when traversing an object graph. */
57 class MOZ_RAII AutoCycleDetector {
58  public:
59   using Vector = GCVector<JSObject*, 8>;
60 
AutoCycleDetector(JSContext * cx,HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)61   AutoCycleDetector(JSContext* cx,
62                     HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
63       : cx(cx), obj(cx, objArg), cyclic(true) {
64     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
65   }
66 
67   ~AutoCycleDetector();
68 
69   bool init();
70 
foundCycle()71   bool foundCycle() { return cyclic; }
72 
73  private:
74   JSContext* cx;
75   RootedObject obj;
76   bool cyclic;
77   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
78 };
79 
80 struct AutoResolving;
81 
82 struct HelperThread;
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   // Context for the main thread of a JSRuntime.
134   MainThread,
135 
136   // Context for a helper thread.
137   HelperThread
138 };
139 
140 #ifdef DEBUG
141 bool CurrentThreadIsParseThread();
142 #endif
143 
144 enum class InterruptReason : uint32_t {
145   GC = 1 << 0,
146   AttachIonCompilations = 1 << 1,
147   CallbackUrgent = 1 << 2,
148   CallbackCanWait = 1 << 3,
149 };
150 
151 } /* namespace js */
152 
153 /*
154  * A JSContext encapsulates the thread local state used when using the JS
155  * runtime.
156  */
157 struct JS_PUBLIC_API JSContext : public JS::RootingContext,
158                                  public js::MallocProvider<JSContext> {
159   JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
160   ~JSContext();
161 
162   bool init(js::ContextKind kind);
163 
164  private:
165   js::UnprotectedData<JSRuntime*> runtime_;
166   js::WriteOnceData<js::ContextKind> kind_;
167 
168   friend class js::gc::AutoSuppressNurseryCellAlloc;
169   js::ContextData<size_t> nurserySuppressions_;
170 
171   js::ContextData<JS::ContextOptions> options_;
172 
173   // Free lists for allocating in the current zone.
174   js::ContextData<js::gc::FreeLists*> freeLists_;
175 
176   // This is reset each time we switch zone, then added to the variable in the
177   // zone when we switch away from it.  This would be a js::ThreadData but we
178   // need to take its address.
179   uint32_t allocsThisZoneSinceMinorGC_;
180 
181   // Free lists for parallel allocation in the atoms zone on helper threads.
182   js::ContextData<js::gc::FreeLists*> atomsZoneFreeLists_;
183 
184   js::ContextData<JSFreeOp> defaultFreeOp_;
185 
186   // Thread that the JSContext is currently running on, if in use.
187   js::ThreadId currentThread_;
188 
189   js::ParseTask* parseTask_;
190 
191   // When a helper thread is using a context, it may need to periodically
192   // free unused memory.
193   mozilla::Atomic<bool, mozilla::ReleaseAcquire> freeUnusedMemory;
194 
195  public:
196   // This is used by helper threads to change the runtime their context is
197   // currently operating on.
198   void setRuntime(JSRuntime* rt);
199 
200   void setHelperThread(js::AutoLockHelperThreadState& locked);
201   void clearHelperThread(js::AutoLockHelperThreadState& locked);
202 
contextAvailableJSContext203   bool contextAvailable(js::AutoLockHelperThreadState& locked) {
204     MOZ_ASSERT(kind_ == js::ContextKind::HelperThread);
205     return currentThread_ == js::ThreadId();
206   }
207 
setFreeUnusedMemoryJSContext208   void setFreeUnusedMemory(bool shouldFree) { freeUnusedMemory = shouldFree; }
209 
shouldFreeUnusedMemoryJSContext210   bool shouldFreeUnusedMemory() const {
211     return kind_ == js::ContextKind::HelperThread && freeUnusedMemory;
212   }
213 
isMainThreadContextJSContext214   bool isMainThreadContext() const {
215     return kind_ == js::ContextKind::MainThread;
216   }
217 
isHelperThreadContextJSContext218   bool isHelperThreadContext() const {
219     return kind_ == js::ContextKind::HelperThread;
220   }
221 
freeListsJSContext222   js::gc::FreeLists& freeLists() {
223     MOZ_ASSERT(freeLists_);
224     return *freeLists_;
225   }
226 
atomsZoneFreeListsJSContext227   js::gc::FreeLists& atomsZoneFreeLists() {
228     MOZ_ASSERT(atomsZoneFreeLists_);
229     return *atomsZoneFreeLists_;
230   }
231 
232   template <typename T>
isInsideCurrentZoneJSContext233   bool isInsideCurrentZone(T thing) const {
234     return thing->zoneFromAnyThread() == zone_;
235   }
236 
237   template <typename T>
isInsideCurrentCompartmentJSContext238   inline bool isInsideCurrentCompartment(T thing) const {
239     return thing->compartment() == compartment();
240   }
241 
242   void* onOutOfMemory(js::AllocFunction allocFunc, arena_id_t arena,
243                       size_t nbytes, void* reallocPtr = nullptr) {
244     if (isHelperThreadContext()) {
245       addPendingOutOfMemory();
246       return nullptr;
247     }
248     return runtime_->onOutOfMemory(allocFunc, arena, nbytes, reallocPtr, this);
249   }
250 
251   /* Clear the pending exception (if any) due to OOM. */
252   void recoverFromOutOfMemory();
253 
reportAllocationOverflowJSContext254   void reportAllocationOverflow() { js::ReportAllocationOverflow(this); }
255 
noteTenuredAllocJSContext256   void noteTenuredAlloc() { allocsThisZoneSinceMinorGC_++; }
257 
addressOfTenuredAllocCountJSContext258   uint32_t* addressOfTenuredAllocCount() {
259     return &allocsThisZoneSinceMinorGC_;
260   }
261 
getAndResetAllocsThisZoneSinceMinorGCJSContext262   uint32_t getAndResetAllocsThisZoneSinceMinorGC() {
263     uint32_t allocs = allocsThisZoneSinceMinorGC_;
264     allocsThisZoneSinceMinorGC_ = 0;
265     return allocs;
266   }
267 
268   // Accessors for immutable runtime data.
namesJSContext269   JSAtomState& names() { return *runtime_->commonNames; }
staticStringsJSContext270   js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
sharedImmutableStringsJSContext271   js::SharedImmutableStringsCache& sharedImmutableStrings() {
272     return runtime_->sharedImmutableStrings();
273   }
permanentAtomsPopulatedJSContext274   bool permanentAtomsPopulated() { return runtime_->permanentAtomsPopulated(); }
permanentAtomsJSContext275   const js::FrozenAtomSet& permanentAtoms() {
276     return *runtime_->permanentAtoms();
277   }
wellKnownSymbolsJSContext278   js::WellKnownSymbols& wellKnownSymbols() {
279     return *runtime_->wellKnownSymbols;
280   }
emptyStringJSContext281   js::PropertyName* emptyString() { return runtime_->emptyString; }
defaultFreeOpJSContext282   JSFreeOp* defaultFreeOp() { return &defaultFreeOp_.ref(); }
stackLimitJSContext283   uintptr_t stackLimit(JS::StackKind kind) { return nativeStackLimit[kind]; }
284   uintptr_t stackLimitForJitCode(JS::StackKind kind);
gcSystemPageSizeJSContext285   size_t gcSystemPageSize() { return js::gc::SystemPageSize(); }
286 
287   /*
288    * "Entering" a realm changes cx->realm (which changes cx->global). Note
289    * that this does not push an Activation so it's possible for the caller's
290    * realm to be != cx->realm(). This is not a problem since, in general, most
291    * places in the VM cannot know that they were called from script (e.g.,
292    * they may have been called through the JSAPI via JS_CallFunction) and thus
293    * cannot expect there is a scripted caller.
294    *
295    * Realms should be entered/left in a LIFO fasion. To enter a realm, code
296    * should prefer using AutoRealm over JS::EnterRealm/JS::LeaveRealm.
297    *
298    * Also note that the JIT can enter (same-compartment) realms without going
299    * through these methods - it will update cx->realm_ directly.
300    */
301  private:
302   inline void setRealm(JS::Realm* realm);
303   inline void enterRealm(JS::Realm* realm);
304 
305   inline void enterAtomsZone();
306   inline void leaveAtomsZone(JS::Realm* oldRealm);
307   enum IsAtomsZone { AtomsZone, NotAtomsZone };
308   inline void setZone(js::Zone* zone, IsAtomsZone isAtomsZone);
309 
310   friend class js::AutoAllocInAtomsZone;
311   friend class js::AutoMaybeLeaveAtomsZone;
312   friend class js::AutoRealm;
313 
314  public:
315   inline void enterRealmOf(JSObject* target);
316   inline void enterRealmOf(JSScript* target);
317   inline void enterRealmOf(js::ObjectGroup* target);
318   inline void enterNullRealm();
319 
320   inline void setRealmForJitExceptionHandler(JS::Realm* realm);
321 
322   inline void leaveRealm(JS::Realm* oldRealm);
323 
setParseTaskJSContext324   void setParseTask(js::ParseTask* parseTask) { parseTask_ = parseTask; }
parseTaskJSContext325   js::ParseTask* parseTask() const { return parseTask_; }
326 
isNurseryAllocSuppressedJSContext327   bool isNurseryAllocSuppressed() const { return nurserySuppressions_; }
328 
329   // Threads may freely access any data in their realm, compartment and zone.
compartmentJSContext330   JS::Compartment* compartment() const {
331     return realm_ ? JS::GetCompartmentForRealm(realm_) : nullptr;
332   }
333 
realmJSContext334   JS::Realm* realm() const { return realm_; }
335 
336 #ifdef DEBUG
337   bool inAtomsZone() const;
338 #endif
339 
zoneJSContext340   JS::Zone* zone() const {
341     MOZ_ASSERT_IF(!realm() && zone_, inAtomsZone());
342     MOZ_ASSERT_IF(realm(), js::GetRealmZone(realm()) == zone_);
343     return zoneRaw();
344   }
345 
346   // For use when the context's zone is being read by another thread and the
347   // compartment and zone pointers might not be in sync.
zoneRawJSContext348   JS::Zone* zoneRaw() const { return zone_; }
349 
350   // For JIT use.
offsetOfZoneJSContext351   static size_t offsetOfZone() { return offsetof(JSContext, zone_); }
352 
353   // Zone local methods that can be used freely.
354   inline js::LifoAlloc& typeLifoAlloc();
355 
356   // Current global. This is only safe to use within the scope of the
357   // AutoRealm from which it's called.
358   inline js::Handle<js::GlobalObject*> global() const;
359 
atomsJSContext360   js::AtomsTable& atoms() { return runtime_->atoms(); }
361 
atomsZoneJSContext362   const JS::Zone* atomsZone(const js::AutoAccessAtomsZone& access) {
363     return runtime_->atomsZone(access);
364   }
365 
symbolRegistryJSContext366   js::SymbolRegistry& symbolRegistry() { return runtime_->symbolRegistry(); }
367 
368   // Methods to access runtime data that must be protected by locks.
scriptDataTableJSContext369   js::RuntimeScriptDataTable& scriptDataTable(js::AutoLockScriptData& lock) {
370     return runtime_->scriptDataTable(lock);
371   }
372 
373   // Methods to access other runtime data that checks locking internally.
atomMarkingJSContext374   js::gc::AtomMarkingRuntime& atomMarking() { return runtime_->gc.atomMarking; }
markAtomJSContext375   void markAtom(JSAtom* atom) { atomMarking().markAtom(this, atom); }
markAtomJSContext376   void markAtom(JS::Symbol* symbol) { atomMarking().markAtom(this, symbol); }
markIdJSContext377   void markId(jsid id) { atomMarking().markId(this, id); }
markAtomValueJSContext378   void markAtomValue(const js::Value& value) {
379     atomMarking().markAtomValue(this, value);
380   }
381 
382   // Methods specific to any HelperThread for the context.
383   bool addPendingCompileError(js::CompileError** err);
384   void addPendingOverRecursed();
385   void addPendingOutOfMemory();
386 
387   bool isCompileErrorPending() const;
388 
runtimeJSContext389   JSRuntime* runtime() { return runtime_; }
runtimeJSContext390   const JSRuntime* runtime() const { return runtime_; }
391 
offsetOfRealmJSContext392   static size_t offsetOfRealm() { return offsetof(JSContext, realm_); }
393 
394   friend class JS::AutoSaveExceptionState;
395   friend class js::jit::DebugModeOSRVolatileJitFrameIter;
396   friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
397 
398  private:
399   static JS::Error reportedError;
400   static JS::OOM reportedOOM;
401 
402  public:
403   inline JS::Result<> boolToResult(bool ok);
404 
405   /**
406    * Intentionally awkward signpost method that is stationed on the
407    * boundary between Result-using and non-Result-using code.
408    */
409   template <typename V, typename E>
resultToBoolJSContext410   bool resultToBool(const JS::Result<V, E>& result) {
411     return result.isOk();
412   }
413 
414   template <typename V, typename E>
resultToPtrJSContext415   V* resultToPtr(const JS::Result<V*, E>& result) {
416     return result.isOk() ? result.unwrap() : nullptr;
417   }
418 
419   mozilla::GenericErrorResult<JS::OOM&> alreadyReportedOOM();
420   mozilla::GenericErrorResult<JS::Error&> alreadyReportedError();
421 
422   /*
423    * Points to the most recent JitActivation pushed on the thread.
424    * See JitActivation constructor in vm/Stack.cpp
425    */
426   js::ContextData<js::jit::JitActivation*> jitActivation;
427 
428 #ifdef ENABLE_NEW_REGEXP
429   // Shim for V8 interfaces used by irregexp code
430   js::ContextData<js::irregexp::Isolate*> isolate;
431 #else
432   // Information about the heap allocated backtrack stack used by RegExp JIT
433   // code.
434   js::ContextData<js::irregexp::RegExpStack> regexpStack;
435 #endif
436 
437   /*
438    * Points to the most recent activation running on the thread.
439    * See Activation comment in vm/Stack.h.
440    */
441   js::ContextData<js::Activation*> activation_;
442 
443   /*
444    * Points to the most recent profiling activation running on the
445    * thread.
446    */
447   js::Activation* volatile profilingActivation_;
448 
449  public:
activationJSContext450   js::Activation* activation() const { return activation_; }
offsetOfActivationJSContext451   static size_t offsetOfActivation() {
452     return offsetof(JSContext, activation_);
453   }
454 
profilingActivationJSContext455   js::Activation* profilingActivation() const { return profilingActivation_; }
offsetOfProfilingActivationJSContext456   static size_t offsetOfProfilingActivation() {
457     return offsetof(JSContext, profilingActivation_);
458   }
459 
offsetOfJitActivationJSContext460   static size_t offsetOfJitActivation() {
461     return offsetof(JSContext, jitActivation);
462   }
463 
464 #ifdef DEBUG
offsetOfInUnsafeCallWithABIJSContext465   static size_t offsetOfInUnsafeCallWithABI() {
466     return offsetof(JSContext, inUnsafeCallWithABI);
467   }
468 #endif
469 
470  public:
interpreterStackJSContext471   js::InterpreterStack& interpreterStack() {
472     return runtime()->interpreterStack();
473   }
474 
475   /* Base address of the native stack for the current thread. */
476   uintptr_t nativeStackBase;
477 
478  public:
479   /* If non-null, report JavaScript entry points to this monitor. */
480   js::ContextData<JS::dbg::AutoEntryMonitor*> entryMonitor;
481 
482   /*
483    * Stack of debuggers that currently disallow debuggee execution.
484    *
485    * When we check for NX we are inside the debuggee compartment, and thus a
486    * stack of Debuggers that have prevented execution need to be tracked to
487    * enter the correct Debugger compartment to report the error.
488    */
489   js::ContextData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
490 
491 #ifdef DEBUG
492   js::ContextData<uint32_t> inUnsafeCallWithABI;
493   js::ContextData<bool> hasAutoUnsafeCallWithABI;
494 #endif
495 
496 #ifdef JS_SIMULATOR
497  private:
498   js::ContextData<js::jit::Simulator*> simulator_;
499 
500  public:
501   js::jit::Simulator* simulator() const;
502   uintptr_t* addressOfSimulatorStackLimit();
503 #endif
504 
505 #ifdef JS_TRACE_LOGGING
506   js::UnprotectedData<js::TraceLoggerThread*> traceLogger;
507 #endif
508 
509  public:
510   // State used by util/DoubleToString.cpp.
511   js::ContextData<DtoaState*> dtoaState;
512 
513   /*
514    * When this flag is non-zero, any attempt to GC will be skipped. It is used
515    * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in
516    * debugging facilities that cannot tolerate a GC and would rather OOM
517    * immediately, such as utilities exposed to GDB. Setting this flag is
518    * extremely dangerous and should only be used when in an OOM situation or
519    * in non-exposed debugging facilities.
520    */
521   js::ContextData<int32_t> suppressGC;
522 
523   // clang-format off
524   enum class GCUse {
525     // This thread is not running in the garbage collector.
526     None,
527 
528     // This thread is currently marking GC things. This thread could be the main
529     // thread or a helper thread doing sweep-marking.
530     Marking,
531 
532     // This thread is currently sweeping GC things. This thread could be the
533     // main thread or a helper thread while the main thread is running the
534     // mutator.
535     Sweeping,
536 
537     // Whether this thread is currently finalizing GC things. This thread could
538     // be the main thread or a helper thread doing finalization while the main
539     // thread is running the mutator.
540     Finalizing
541   };
542   // clang-format on
543 
544 #ifdef DEBUG
545   // Which part of the garbage collector this context is running at the moment.
546   js::ContextData<GCUse> gcUse;
547 
548   // The specific zone currently being swept, if any.
549   js::ContextData<JS::Zone*> gcSweepZone;
550 
551   // Whether this thread is currently manipulating possibly-gray GC things.
552   js::ContextData<size_t> isTouchingGrayThings;
553 
554   js::ContextData<size_t> noNurseryAllocationCheck;
555 
556   /*
557    * If this is 0, all cross-compartment proxies must be registered in the
558    * wrapper map. This checking must be disabled temporarily while creating
559    * new wrappers. When non-zero, this records the recursion depth of wrapper
560    * creation.
561    */
562   js::ContextData<uintptr_t> disableStrictProxyCheckingCount;
563 
isNurseryAllocAllowedJSContext564   bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; }
disallowNurseryAllocJSContext565   void disallowNurseryAlloc() { ++noNurseryAllocationCheck; }
allowNurseryAllocJSContext566   void allowNurseryAlloc() {
567     MOZ_ASSERT(!isNurseryAllocAllowed());
568     --noNurseryAllocationCheck;
569   }
570 
isStrictProxyCheckingEnabledJSContext571   bool isStrictProxyCheckingEnabled() {
572     return disableStrictProxyCheckingCount == 0;
573   }
disableStrictProxyCheckingJSContext574   void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; }
enableStrictProxyCheckingJSContext575   void enableStrictProxyChecking() {
576     MOZ_ASSERT(disableStrictProxyCheckingCount > 0);
577     --disableStrictProxyCheckingCount;
578   }
579 #endif
580 
581 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
582   // We are currently running a simulated OOM test.
583   js::ContextData<bool> runningOOMTest;
584 #endif
585 
586   // True if we should assert that
587   //     !comp->validAccessPtr || *comp->validAccessPtr
588   // is true for every |comp| that we run JS code in.
589   js::ContextData<unsigned> enableAccessValidation;
590 
591   /*
592    * Some regions of code are hard for the static rooting hazard analysis to
593    * understand. In those cases, we trade the static analysis for a dynamic
594    * analysis. When this is non-zero, we should assert if we trigger, or
595    * might trigger, a GC.
596    */
597   js::ContextData<int> inUnsafeRegion;
598 
599   // Count of AutoDisableGenerationalGC instances on the thread's stack.
600   js::ContextData<unsigned> generationalDisabled;
601 
602   // Some code cannot tolerate compacting GC so it can be disabled temporarily
603   // with AutoDisableCompactingGC which uses this counter.
604   js::ContextData<unsigned> compactingDisabledCount;
605 
canCollectAtomsJSContext606   bool canCollectAtoms() const {
607     // TODO: We may be able to improve this by collecting if
608     // !isOffThreadParseRunning() (bug 1468422).
609     return !runtime()->hasHelperThreadZones();
610   }
611 
612  private:
613   // Pools used for recycling name maps and vectors when parsing and
614   // emitting bytecode. Purged on GC when there are no active script
615   // compilations.
616   js::ContextData<js::frontend::NameCollectionPool> frontendCollectionPool_;
617 
618  public:
frontendCollectionPoolJSContext619   js::frontend::NameCollectionPool& frontendCollectionPool() {
620     return frontendCollectionPool_.ref();
621   }
622 
verifyIsSafeToGCJSContext623   void verifyIsSafeToGC() {
624     MOZ_DIAGNOSTIC_ASSERT(!inUnsafeRegion,
625                           "[AutoAssertNoGC] possible GC in GC-unsafe region");
626   }
627 
628   /* Whether sampling should be enabled or not. */
629  private:
630   mozilla::Atomic<bool, mozilla::SequentiallyConsistent>
631       suppressProfilerSampling;
632 
633  public:
isProfilerSamplingEnabledJSContext634   bool isProfilerSamplingEnabled() const { return !suppressProfilerSampling; }
disableProfilerSamplingJSContext635   void disableProfilerSampling() { suppressProfilerSampling = true; }
enableProfilerSamplingJSContext636   void enableProfilerSampling() { suppressProfilerSampling = false; }
637 
638   // Used by wasm::EnsureThreadSignalHandlers(cx) to install thread signal
639   // handlers once per JSContext/thread.
640   bool wasmTriedToInstallSignalHandlers;
641   bool wasmHaveSignalHandlers;
642 
643   /* Temporary arena pool used while compiling and decompiling. */
644   static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
645 
646  private:
647   js::ContextData<js::LifoAlloc> tempLifoAlloc_;
648 
649  public:
tempLifoAllocJSContext650   js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
tempLifoAllocJSContext651   const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
tempLifoAllocNoCheckJSContext652   js::LifoAlloc& tempLifoAllocNoCheck() { return tempLifoAlloc_.refNoCheck(); }
653 
654   js::ContextData<uint32_t> debuggerMutations;
655 
656   // Cache for jit::GetPcScript().
657   js::ContextData<js::UniquePtr<js::jit::PcScriptCache>> ionPcScriptCache;
658 
659  private:
660   /* Exception state -- the exception member is a GC root by definition. */
661   js::ContextData<bool> throwing; /* is there a pending exception? */
662   js::ContextData<JS::PersistentRooted<JS::Value>>
663       unwrappedException_; /* most-recently-thrown exception */
664   js::ContextData<JS::PersistentRooted<js::SavedFrame*>>
665       unwrappedExceptionStack_; /* stack when the exception was thrown */
666 
unwrappedExceptionJSContext667   JS::Value& unwrappedException() {
668     if (!unwrappedException_.ref().initialized()) {
669       unwrappedException_.ref().init(this);
670     }
671     return unwrappedException_.ref().get();
672   }
673 
unwrappedExceptionStackJSContext674   js::SavedFrame*& unwrappedExceptionStack() {
675     if (!unwrappedExceptionStack_.ref().initialized()) {
676       unwrappedExceptionStack_.ref().init(this);
677     }
678     return unwrappedExceptionStack_.ref().get();
679   }
680 
681   // True if the exception currently being thrown is by result of
682   // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
683   js::ContextData<bool> overRecursed_;
684 
685   // True if propagating a forced return from an interrupt handler during
686   // debug mode.
687   js::ContextData<bool> propagatingForcedReturn_;
688 
689  public:
690   js::ContextData<int32_t> reportGranularity; /* see vm/Probes.h */
691 
692   js::ContextData<js::AutoResolving*> resolvingList;
693 
694 #ifdef DEBUG
695   js::ContextData<js::AutoEnterPolicy*> enteredPolicy;
696 #endif
697 
698   /* True if generating an error, to prevent runaway recursion. */
699   js::ContextData<bool> generatingError;
700 
701  private:
702   /* State for object and array toSource conversion. */
703   js::ContextData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
704 
705  public:
cycleDetectorVectorJSContext706   js::AutoCycleDetector::Vector& cycleDetectorVector() {
707     return cycleDetectorVector_.ref();
708   }
cycleDetectorVectorJSContext709   const js::AutoCycleDetector::Vector& cycleDetectorVector() const {
710     return cycleDetectorVector_.ref();
711   }
712 
713   /* Client opaque pointer. */
714   js::UnprotectedData<void*> data;
715 
716   void initJitStackLimit();
717   void resetJitStackLimit();
718 
719  public:
optionsJSContext720   JS::ContextOptions& options() { return options_.ref(); }
721 
runtimeMatchesJSContext722   bool runtimeMatches(JSRuntime* rt) const { return runtime_ == rt; }
723 
724  private:
725   /*
726    * Youngest frame of a saved stack that will be picked up as an async stack
727    * by any new Activation, and is nullptr when no async stack should be used.
728    *
729    * The JS::AutoSetAsyncStackForNewCalls class can be used to set this.
730    *
731    * New activations will reset this to nullptr on construction after getting
732    * the current value, and will restore the previous value on destruction.
733    */
734   js::ContextData<JS::PersistentRooted<js::SavedFrame*>>
735       asyncStackForNewActivations_;
736 
737  public:
asyncStackForNewActivationsJSContext738   js::SavedFrame*& asyncStackForNewActivations() {
739     if (!asyncStackForNewActivations_.ref().initialized()) {
740       asyncStackForNewActivations_.ref().init(this);
741     }
742     return asyncStackForNewActivations_.ref().get();
743   }
744 
745   /*
746    * Value of asyncCause to be attached to asyncStackForNewActivations.
747    */
748   js::ContextData<const char*> asyncCauseForNewActivations;
749 
750   /*
751    * True if the async call was explicitly requested, e.g. via
752    * callFunctionWithAsyncStack.
753    */
754   js::ContextData<bool> asyncCallIsExplicit;
755 
currentlyRunningInInterpreterJSContext756   bool currentlyRunningInInterpreter() const {
757     return activation()->isInterpreter();
758   }
currentlyRunningInJitJSContext759   bool currentlyRunningInJit() const { return activation()->isJit(); }
interpreterFrameJSContext760   js::InterpreterFrame* interpreterFrame() const {
761     return activation()->asInterpreter()->current();
762   }
interpreterRegsJSContext763   js::InterpreterRegs& interpreterRegs() const {
764     return activation()->asInterpreter()->regs();
765   }
766 
767   /*
768    * Get the topmost script and optional pc on the stack. By default, this
769    * function only returns a JSScript in the current realm, returning nullptr
770    * if the current script is in a different realm. This behavior can be
771    * overridden by passing AllowCrossRealm::Allow.
772    */
773   enum class AllowCrossRealm { DontAllow = false, Allow = true };
774   inline JSScript* currentScript(
775       jsbytecode** pc = nullptr,
776       AllowCrossRealm allowCrossRealm = AllowCrossRealm::DontAllow) const;
777 
778   inline js::Nursery& nursery();
779   inline void minorGC(JS::GCReason reason);
780 
781  public:
isExceptionPendingJSContext782   bool isExceptionPending() const { return throwing; }
783 
784   MOZ_MUST_USE
785   bool getPendingException(JS::MutableHandleValue rval);
786 
787   js::SavedFrame* getPendingExceptionStack();
788 
789   bool isThrowingOutOfMemory();
790   bool isThrowingDebuggeeWouldRun();
791   bool isClosingGenerator();
792 
793   void setPendingException(JS::HandleValue v, js::HandleSavedFrame stack);
794   void setPendingExceptionAndCaptureStack(JS::HandleValue v);
795 
clearPendingExceptionJSContext796   void clearPendingException() {
797     throwing = false;
798     overRecursed_ = false;
799     unwrappedException().setUndefined();
800     unwrappedExceptionStack() = nullptr;
801   }
802 
isThrowingOverRecursedJSContext803   bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
isPropagatingForcedReturnJSContext804   bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
setPropagatingForcedReturnJSContext805   void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
clearPropagatingForcedReturnJSContext806   void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
807 
808   /*
809    * See JS_SetTrustedPrincipals in jsapi.h.
810    * Note: !cx->realm() is treated as trusted.
811    */
812   inline bool runningWithTrustedPrincipals();
813 
814   size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
815 
816   void trace(JSTracer* trc);
817 
818   inline js::RuntimeCaches& caches();
819 
820  public:
821   using InterruptCallbackVector =
822       js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
823 
824  private:
825   js::ContextData<InterruptCallbackVector> interruptCallbacks_;
826 
827  public:
interruptCallbacksJSContext828   InterruptCallbackVector& interruptCallbacks() {
829     return interruptCallbacks_.ref();
830   }
831 
832   js::ContextData<bool> interruptCallbackDisabled;
833 
834   // Bitfield storing InterruptReason values.
835   mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptBits_;
836 
837   // Any thread can call requestInterrupt() to request that this thread
838   // stop running. To stop this thread, requestInterrupt sets two fields:
839   // interruptBits_ (a bitset of InterruptReasons) and jitStackLimit_ (set to
840   // UINTPTR_MAX). The JS engine must continually poll one of these fields
841   // and call handleInterrupt if either field has the interrupt value.
842   //
843   // The point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code
844   // already needs to guard on jitStackLimit_ in every function prologue to
845   // avoid stack overflow, so we avoid a second branch on interruptBits_ by
846   // setting jitStackLimit_ to a value that is guaranteed to fail the guard.)
847   //
848   // Note that the writes to interruptBits_ and jitStackLimit_ use a Relaxed
849   // Atomic so, while the writes are guaranteed to eventually be visible to
850   // this thread, it can happen in any order. handleInterrupt calls the
851   // interrupt callback if either is set, so it really doesn't matter as long
852   // as the JS engine is continually polling at least one field. In corner
853   // cases, this relaxed ordering could lead to an interrupt handler being
854   // called twice in succession after a single requestInterrupt call, but
855   // that's fine.
856   void requestInterrupt(js::InterruptReason reason);
857   bool handleInterrupt();
858 
hasAnyPendingInterruptJSContext859   MOZ_ALWAYS_INLINE bool hasAnyPendingInterrupt() const {
860     static_assert(sizeof(interruptBits_) == sizeof(uint32_t),
861                   "Assumed by JIT callers");
862     return interruptBits_ != 0;
863   }
hasPendingInterruptJSContext864   bool hasPendingInterrupt(js::InterruptReason reason) const {
865     return interruptBits_ & uint32_t(reason);
866   }
867 
868  public:
addressOfInterruptBitsJSContext869   void* addressOfInterruptBits() { return &interruptBits_; }
addressOfJitStackLimitJSContext870   void* addressOfJitStackLimit() { return &jitStackLimit; }
addressOfJitStackLimitNoInterruptJSContext871   void* addressOfJitStackLimitNoInterrupt() {
872     return &jitStackLimitNoInterrupt;
873   }
addressOfZoneJSContext874   void* addressOfZone() { return &zone_; }
875 
addressOfRealmJSContext876   const void* addressOfRealm() const { return &realm_; }
877 
878   // Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics
879   // object.
880   js::FutexThread fx;
881 
882   // In certain cases, we want to optimize certain opcodes to typed
883   // instructions, to avoid carrying an extra register to feed into an unbox.
884   // Unfortunately, that's not always possible. For example, a GetPropertyCacheT
885   // could return a typed double, but if it takes its out-of-line path, it could
886   // return an object, and trigger invalidation. The invalidation bailout will
887   // consider the return value to be a double, and create a garbage Value.
888   //
889   // To allow the GetPropertyCacheT optimization, we allow the ability for
890   // GetPropertyCache to override the return value at the top of the stack - the
891   // value that will be temporarily corrupt. This special override value is set
892   // only in callVM() targets that are about to return *and* have invalidated
893   // their callee.
894   js::ContextData<js::Value> ionReturnOverride_;
895 
hasIonReturnOverrideJSContext896   bool hasIonReturnOverride() const {
897     return !ionReturnOverride_.ref().isMagic(JS_ARG_POISON);
898   }
takeIonReturnOverrideJSContext899   js::Value takeIonReturnOverride() {
900     js::Value v = ionReturnOverride_;
901     ionReturnOverride_ = js::MagicValue(JS_ARG_POISON);
902     return v;
903   }
setIonReturnOverrideJSContext904   void setIonReturnOverride(const js::Value& v) {
905     MOZ_ASSERT(!hasIonReturnOverride());
906     MOZ_ASSERT(!v.isMagic());
907     ionReturnOverride_ = v;
908   }
909 
910   mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
911 
912   // Like jitStackLimit, but not reset to trigger interrupts.
913   js::ContextData<uintptr_t> jitStackLimitNoInterrupt;
914 
915   // Queue of pending jobs as described in ES2016 section 8.4.
916   //
917   // This is a non-owning pointer to either:
918   // - a JobQueue implementation the embedding provided by calling
919   //   JS::SetJobQueue, owned by the embedding, or
920   // - our internal JobQueue implementation, established by calling
921   //   js::UseInternalJobQueues, owned by JSContext::internalJobQueue below.
922   js::ContextData<JS::JobQueue*> jobQueue;
923 
924   // If the embedding has called js::UseInternalJobQueues, this is the owning
925   // pointer to our internal JobQueue implementation, which JSContext::jobQueue
926   // borrows.
927   js::ContextData<js::UniquePtr<js::InternalJobQueue>> internalJobQueue;
928 
929   // True if jobQueue is empty, or we are running the last job in the queue.
930   // Such conditions permit optimizations around `await` expressions.
931   js::ContextData<bool> canSkipEnqueuingJobs;
932 
933   js::ContextData<JS::PromiseRejectionTrackerCallback>
934       promiseRejectionTrackerCallback;
935   js::ContextData<void*> promiseRejectionTrackerCallbackData;
936 
937   JSObject* getIncumbentGlobal(JSContext* cx);
938   bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
939                          js::HandleObject promise,
940                          js::HandleObject incumbentGlobal);
941   void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
942   void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
943 
944  private:
945   template <class... Args>
946   inline void checkImpl(const Args&... args);
947 
contextChecksEnabledJSContext948   bool contextChecksEnabled() const {
949     // Don't perform these checks when called from a finalizer. The checking
950     // depends on other objects not having been swept yet.
951     return !RuntimeHeapIsCollecting(runtime()->heapState());
952   }
953 
954  public:
955   // Assert the arguments are in this context's realm (for scripts),
956   // compartment (for objects) or zone (for strings, symbols).
957   template <class... Args>
958   inline void check(const Args&... args);
959   template <class... Args>
960   inline void releaseCheck(const Args&... args);
961   template <class... Args>
962   MOZ_ALWAYS_INLINE void debugOnlyCheck(const Args&... args);
963 
964 #ifdef JS_STRUCTURED_SPEW
965  private:
966   // Spewer for this thread
967   js::UnprotectedData<js::StructuredSpewer> structuredSpewer_;
968 
969  public:
spewerJSContext970   js::StructuredSpewer& spewer() { return structuredSpewer_.ref(); }
971 #endif
972 
973   // During debugger evaluations which need to observe native calls, JITs are
974   // completely disabled. This flag indicates whether we are in this state, and
975   // the debugger which initiated the evaluation. This debugger has other
976   // references on the stack and does not need to be traced.
977   js::ContextData<js::Debugger*> insideDebuggerEvaluationWithOnNativeCallHook;
978 
979 }; /* struct JSContext */
980 
boolToResult(bool ok)981 inline JS::Result<> JSContext::boolToResult(bool ok) {
982   if (MOZ_LIKELY(ok)) {
983     MOZ_ASSERT(!isExceptionPending());
984     MOZ_ASSERT(!isPropagatingForcedReturn());
985     return JS::Ok();
986   }
987   return JS::Result<>(reportedError);
988 }
989 
mainContextFromOwnThread()990 inline JSContext* JSRuntime::mainContextFromOwnThread() {
991   MOZ_ASSERT(mainContextFromAnyThread() == js::TlsContext.get());
992   return mainContextFromAnyThread();
993 }
994 
995 namespace js {
996 
997 struct MOZ_RAII AutoResolving {
998  public:
999   enum Kind { LOOKUP, WATCH };
1000 
1001   AutoResolving(JSContext* cx, HandleObject obj, HandleId id,
1002                 Kind kind = LOOKUP MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
contextAutoResolving1003       : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList) {
1004     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1005     MOZ_ASSERT(obj);
1006     cx->resolvingList = this;
1007   }
1008 
~AutoResolvingAutoResolving1009   ~AutoResolving() {
1010     MOZ_ASSERT(context->resolvingList == this);
1011     context->resolvingList = link;
1012   }
1013 
alreadyStartedAutoResolving1014   bool alreadyStarted() const { return link && alreadyStartedSlow(); }
1015 
1016  private:
1017   bool alreadyStartedSlow() const;
1018 
1019   JSContext* const context;
1020   HandleObject object;
1021   HandleId id;
1022   Kind const kind;
1023   AutoResolving* const link;
1024   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1025 };
1026 
1027 /*
1028  * Create and destroy functions for JSContext, which is manually allocated
1029  * and exclusively owned.
1030  */
1031 extern JSContext* NewContext(uint32_t maxBytes, JSRuntime* parentRuntime);
1032 
1033 extern void DestroyContext(JSContext* cx);
1034 
1035 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
1036 extern void ReportUsageErrorASCII(JSContext* cx, HandleObject callee,
1037                                   const char* msg);
1038 
1039 extern void ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
1040 
1041 extern void ReportIsNotDefined(JSContext* cx, HandleId id);
1042 
1043 /*
1044  * Report an attempt to access the property of a null or undefined value (v).
1045  */
1046 extern void ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx,
1047                                                      HandleValue v, int vIndex);
1048 extern void ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx,
1049                                                      HandleValue v, int vIndex,
1050                                                      HandleId key);
1051 
1052 /*
1053  * Report error using js::DecompileValueGenerator(cx, spindex, v, fallback) as
1054  * the first argument for the error message.
1055  */
1056 extern bool ReportValueError(JSContext* cx, const unsigned errorNumber,
1057                              int spindex, HandleValue v, HandleString fallback,
1058                              const char* arg1 = nullptr,
1059                              const char* arg2 = nullptr);
1060 
1061 JSObject* CreateErrorNotesArray(JSContext* cx, JSErrorReport* report);
1062 
1063 } /* namespace js */
1064 
1065 extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
1066 
1067 namespace js {
1068 
1069 /************************************************************************/
1070 
1071 /*
1072  * Encapsulates an external array of values and adds a trace method, for use in
1073  * Rooted.
1074  */
1075 class MOZ_STACK_CLASS ExternalValueArray {
1076  public:
ExternalValueArray(size_t len,Value * vec)1077   ExternalValueArray(size_t len, Value* vec) : array_(vec), length_(len) {}
1078 
begin()1079   Value* begin() { return array_; }
length()1080   size_t length() { return length_; }
1081 
1082   void trace(JSTracer* trc);
1083 
1084  private:
1085   Value* array_;
1086   size_t length_;
1087 };
1088 
1089 /* RootedExternalValueArray roots an external array of Values. */
1090 class MOZ_RAII RootedExternalValueArray
1091     : public JS::Rooted<ExternalValueArray> {
1092  public:
RootedExternalValueArray(JSContext * cx,size_t len,Value * vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1093   RootedExternalValueArray(JSContext* cx, size_t len,
1094                            Value* vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1095       : JS::Rooted<ExternalValueArray>(cx, ExternalValueArray(len, vec)) {
1096     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1097   }
1098 
1099  private:
1100   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1101 };
1102 
1103 class AutoAssertNoPendingException {
1104 #ifdef DEBUG
1105   JSContext* cx_;
1106 
1107  public:
AutoAssertNoPendingException(JSContext * cxArg)1108   explicit AutoAssertNoPendingException(JSContext* cxArg) : cx_(cxArg) {
1109     MOZ_ASSERT(!JS_IsExceptionPending(cx_));
1110   }
1111 
~AutoAssertNoPendingException()1112   ~AutoAssertNoPendingException() { MOZ_ASSERT(!JS_IsExceptionPending(cx_)); }
1113 #else
1114  public:
1115   explicit AutoAssertNoPendingException(JSContext* cxArg) {}
1116 #endif
1117 };
1118 
1119 class MOZ_RAII AutoLockScriptData {
1120   JSRuntime* runtime;
1121 
1122  public:
AutoLockScriptData(JSRuntime * rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1123   explicit AutoLockScriptData(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1124     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1125     MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt) ||
1126                CurrentThreadIsParseThread());
1127     runtime = rt;
1128     if (runtime->hasHelperThreadZones()) {
1129       runtime->scriptDataLock.lock();
1130     } else {
1131       MOZ_ASSERT(!runtime->activeThreadHasScriptDataAccess);
1132 #ifdef DEBUG
1133       runtime->activeThreadHasScriptDataAccess = true;
1134 #endif
1135     }
1136   }
~AutoLockScriptData()1137   ~AutoLockScriptData() {
1138     if (runtime->hasHelperThreadZones()) {
1139       runtime->scriptDataLock.unlock();
1140     } else {
1141       MOZ_ASSERT(runtime->activeThreadHasScriptDataAccess);
1142 #ifdef DEBUG
1143       runtime->activeThreadHasScriptDataAccess = false;
1144 #endif
1145     }
1146   }
1147 
1148   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1149 };
1150 
1151 // A token used to prove you can safely access the atoms zone. This zone is
1152 // accessed by the main thread and by off-thread parsing. There are two
1153 // situations in which it is safe:
1154 //
1155 //  - the current thread holds all atoms table locks (off-thread parsing may be
1156 //    running and must also take one of these locks for access)
1157 //
1158 //  - the GC is running and is collecting the atoms zone (this cannot be started
1159 //    while off-thread parsing is happening)
1160 class MOZ_STACK_CLASS AutoAccessAtomsZone {
1161  public:
AutoAccessAtomsZone(const AutoLockAllAtoms & lock)1162   MOZ_IMPLICIT AutoAccessAtomsZone(const AutoLockAllAtoms& lock) {}
AutoAccessAtomsZone(const gc::AutoCheckCanAccessAtomsDuringGC & canAccess)1163   MOZ_IMPLICIT AutoAccessAtomsZone(
1164       const gc::AutoCheckCanAccessAtomsDuringGC& canAccess) {}
1165 };
1166 
1167 class MOZ_RAII AutoKeepAtoms {
1168   JSContext* cx;
1169   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1170 
1171  public:
1172   explicit AutoKeepAtoms(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
1173   ~AutoKeepAtoms();
1174 };
1175 
1176 class MOZ_RAII AutoNoteDebuggerEvaluationWithOnNativeCallHook {
1177   JSContext* cx;
1178   Debugger* oldValue;
1179 
1180  public:
AutoNoteDebuggerEvaluationWithOnNativeCallHook(JSContext * cx,Debugger * dbg)1181   AutoNoteDebuggerEvaluationWithOnNativeCallHook(JSContext* cx, Debugger* dbg)
1182       : cx(cx), oldValue(cx->insideDebuggerEvaluationWithOnNativeCallHook) {
1183     cx->insideDebuggerEvaluationWithOnNativeCallHook = dbg;
1184   }
1185 
~AutoNoteDebuggerEvaluationWithOnNativeCallHook()1186   ~AutoNoteDebuggerEvaluationWithOnNativeCallHook() {
1187     cx->insideDebuggerEvaluationWithOnNativeCallHook = oldValue;
1188   }
1189 };
1190 
1191 enum UnsafeABIStrictness {
1192   NoExceptions,
1193   AllowPendingExceptions,
1194   AllowThrownExceptions
1195 };
1196 
1197 // Should be used in functions called directly from JIT code (with
1198 // masm.callWithABI) to assert invariants in debug builds.
1199 // In debug mode, masm.callWithABI inserts code to verify that the
1200 // callee function uses AutoUnsafeCallWithABI.
1201 // While this object is live:
1202 // 1. cx->hasAutoUnsafeCallWithABI must be true.
1203 // 2. We can't GC.
1204 // 3. Exceptions should not be pending/thrown.
1205 //
1206 // Note that #3 is a precaution, not a requirement. By default, we
1207 // assert that the function is not called with a pending exception,
1208 // and that it does not throw an exception itself.
1209 class MOZ_RAII AutoUnsafeCallWithABI {
1210 #ifdef DEBUG
1211   JSContext* cx_;
1212   bool nested_;
1213   bool checkForPendingException_;
1214 #endif
1215   JS::AutoCheckCannotGC nogc;
1216 
1217  public:
1218 #ifdef DEBUG
1219   explicit AutoUnsafeCallWithABI(
1220       UnsafeABIStrictness strictness = UnsafeABIStrictness::NoExceptions);
1221   ~AutoUnsafeCallWithABI();
1222 #else
1223   explicit AutoUnsafeCallWithABI(
1224       UnsafeABIStrictness unused_ = UnsafeABIStrictness::NoExceptions) {}
1225 #endif
1226 };
1227 
1228 namespace gc {
1229 
1230 // Set/unset the performing GC flag for the current thread.
1231 class MOZ_RAII AutoSetThreadIsPerformingGC {
1232   JSContext* cx;
1233 
1234  public:
AutoSetThreadIsPerformingGC()1235   AutoSetThreadIsPerformingGC() : cx(TlsContext.get()) {
1236     JSFreeOp* fop = cx->defaultFreeOp();
1237     MOZ_ASSERT(!fop->isCollecting());
1238     fop->isCollecting_ = true;
1239   }
1240 
~AutoSetThreadIsPerformingGC()1241   ~AutoSetThreadIsPerformingGC() {
1242     JSFreeOp* fop = cx->defaultFreeOp();
1243     MOZ_ASSERT(fop->isCollecting());
1244     fop->isCollecting_ = false;
1245   }
1246 };
1247 
1248 struct MOZ_RAII AutoSetThreadGCUse {
1249  protected:
1250 #ifndef DEBUG
1251   explicit AutoSetThreadGCUse(JSContext::GCUse use, Zone* sweepZone = nullptr) {
1252   }
1253 #else
1254   explicit AutoSetThreadGCUse(JSContext::GCUse use, Zone* sweepZone = nullptr)
1255       : cx(TlsContext.get()), prevUse(cx->gcUse), prevZone(cx->gcSweepZone) {
1256     MOZ_ASSERT_IF(sweepZone, use == JSContext::GCUse::Sweeping);
1257     cx->gcUse = use;
1258     cx->gcSweepZone = sweepZone;
1259   }
1260 
1261   ~AutoSetThreadGCUse() {
1262     cx->gcUse = prevUse;
1263     cx->gcSweepZone = prevZone;
1264     MOZ_ASSERT_IF(cx->gcUse == JSContext::GCUse::None, !cx->gcSweepZone);
1265   }
1266 
1267  private:
1268   JSContext* cx;
1269   JSContext::GCUse prevUse;
1270   JS::Zone* prevZone;
1271 #endif
1272 };
1273 
1274 // In debug builds, update the context state to indicate that the current thread
1275 // is being used for GC marking.
1276 struct MOZ_RAII AutoSetThreadIsMarking : public AutoSetThreadGCUse {
AutoSetThreadIsMarkingAutoSetThreadIsMarking1277   explicit AutoSetThreadIsMarking()
1278       : AutoSetThreadGCUse(JSContext::GCUse::Marking) {}
1279 };
1280 
1281 // In debug builds, update the context state to indicate that the current thread
1282 // is being used for GC sweeping.
1283 struct MOZ_RAII AutoSetThreadIsSweeping : public AutoSetThreadGCUse {
1284   explicit AutoSetThreadIsSweeping(Zone* zone = nullptr)
AutoSetThreadGCUseAutoSetThreadIsSweeping1285       : AutoSetThreadGCUse(JSContext::GCUse::Sweeping, zone) {}
1286 };
1287 
1288 // In debug builds, update the context state to indicate that the current thread
1289 // is being used for GC finalization.
1290 struct MOZ_RAII AutoSetThreadIsFinalizing : public AutoSetThreadGCUse {
AutoSetThreadIsFinalizingAutoSetThreadIsFinalizing1291   explicit AutoSetThreadIsFinalizing()
1292       : AutoSetThreadGCUse(JSContext::GCUse::Finalizing) {}
1293 };
1294 
1295 // Note that this class does not suppress buffer allocation/reallocation in the
1296 // nursery, only Cells themselves.
1297 class MOZ_RAII AutoSuppressNurseryCellAlloc {
1298   JSContext* cx_;
1299 
1300  public:
AutoSuppressNurseryCellAlloc(JSContext * cx)1301   explicit AutoSuppressNurseryCellAlloc(JSContext* cx) : cx_(cx) {
1302     cx_->nurserySuppressions_++;
1303   }
~AutoSuppressNurseryCellAlloc()1304   ~AutoSuppressNurseryCellAlloc() { cx_->nurserySuppressions_--; }
1305 };
1306 
1307 }  // namespace gc
1308 
1309 } /* namespace js */
1310 
1311 #define CHECK_THREAD(cx)                            \
1312   MOZ_ASSERT_IF(cx && !cx->isHelperThreadContext(), \
1313                 js::CurrentThreadCanAccessRuntime(cx->runtime()))
1314 
1315 #endif /* vm_JSContext_h */
1316