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