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