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