Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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 "js/CharacterEncoding.h"
15 : #include "js/GCVector.h"
16 : #include "js/Result.h"
17 : #include "js/Utility.h"
18 : #include "js/Vector.h"
19 : #include "threading/ProtectedData.h"
20 : #include "vm/ErrorReporting.h"
21 : #include "vm/MallocProvider.h"
22 : #include "vm/Runtime.h"
23 :
24 : struct DtoaState;
25 :
26 : namespace js {
27 :
28 : class AutoAtomsZone;
29 : class AutoRealm;
30 :
31 : namespace jit {
32 : class JitContext;
33 : class DebugModeOSRVolatileJitFrameIter;
34 : } // namespace jit
35 :
36 : namespace gc {
37 : class AutoSuppressNurseryCellAlloc;
38 : }
39 :
40 : typedef HashSet<Shape*> ShapeSet;
41 :
42 : /* Detects cycles when traversing an object graph. */
43 : class MOZ_RAII AutoCycleDetector
44 : {
45 : public:
46 : using Vector = GCVector<JSObject*, 8>;
47 :
48 : AutoCycleDetector(JSContext* cx, HandleObject objArg
49 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
50 0 : : cx(cx), obj(cx, objArg), cyclic(true)
51 : {
52 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
53 : }
54 :
55 : ~AutoCycleDetector();
56 :
57 : bool init();
58 :
59 : bool foundCycle() { return cyclic; }
60 :
61 : private:
62 : JSContext* cx;
63 : RootedObject obj;
64 : bool cyclic;
65 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
66 : };
67 :
68 : struct AutoResolving;
69 :
70 : struct HelperThread;
71 :
72 : using JobQueue = GCVector<JSObject*, 0, SystemAllocPolicy>;
73 :
74 : class AutoLockForExclusiveAccess;
75 : class AutoLockScriptData;
76 :
77 : void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
78 :
79 : /* Thread Local Storage slot for storing the context for a thread. */
80 : extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
81 :
82 : enum class ContextKind
83 : {
84 : // Context for the main thread of a JSRuntime.
85 : MainThread,
86 :
87 : // Context for a helper thread.
88 : HelperThread
89 : };
90 :
91 : #ifdef DEBUG
92 : bool
93 : CurrentThreadIsParseThread();
94 : #endif
95 :
96 : enum class InterruptReason : uint32_t
97 : {
98 : GC = 1 << 0,
99 : AttachIonCompilations = 1 << 1,
100 : CallbackUrgent = 1 << 2,
101 : CallbackCanWait = 1 << 3,
102 : };
103 :
104 : } /* namespace js */
105 :
106 : /*
107 : * A JSContext encapsulates the thread local state used when using the JS
108 : * runtime.
109 : */
110 : struct JSContext : public JS::RootingContext,
111 : public js::MallocProvider<JSContext>
112 : {
113 : JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
114 : ~JSContext();
115 :
116 : bool init(js::ContextKind kind);
117 :
118 : private:
119 : js::UnprotectedData<JSRuntime*> runtime_;
120 : js::WriteOnceData<js::ContextKind> kind_;
121 :
122 : // The thread on which this context is running if this is not the main thread.
123 : js::ThreadData<js::HelperThread*> helperThread_;
124 :
125 : friend class js::gc::AutoSuppressNurseryCellAlloc;
126 : js::ThreadData<size_t> nurserySuppressions_;
127 :
128 : js::ThreadData<JS::ContextOptions> options_;
129 :
130 : js::ThreadData<js::gc::ArenaLists*> arenas_;
131 :
132 : public:
133 : // This is used by helper threads to change the runtime their context is
134 : // currently operating on.
135 : void setRuntime(JSRuntime* rt);
136 :
137 0 : bool isMainThreadContext() const { return kind_ == js::ContextKind::MainThread; }
138 :
139 0 : inline js::gc::ArenaLists* arenas() const { return arenas_; }
140 :
141 : template <typename T>
142 : bool isInsideCurrentZone(T thing) const {
143 0 : return thing->zoneFromAnyThread() == zone_;
144 : }
145 :
146 : template <typename T>
147 : inline bool isInsideCurrentCompartment(T thing) const {
148 0 : return thing->compartment() == compartment();
149 : }
150 :
151 0 : void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
152 0 : if (helperThread()) {
153 0 : addPendingOutOfMemory();
154 0 : return nullptr;
155 : }
156 0 : return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, this);
157 : }
158 :
159 : /* Clear the pending exception (if any) due to OOM. */
160 : void recoverFromOutOfMemory();
161 :
162 : void updateMallocCounter(size_t nbytes);
163 :
164 : void reportAllocationOverflow() {
165 0 : js::ReportAllocationOverflow(this);
166 : }
167 :
168 : // Accessors for immutable runtime data.
169 0 : JSAtomState& names() { return *runtime_->commonNames; }
170 0 : js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
171 : js::SharedImmutableStringsCache& sharedImmutableStrings() {
172 : return runtime_->sharedImmutableStrings();
173 : }
174 0 : bool isPermanentAtomsInitialized() { return !!runtime_->permanentAtoms; }
175 0 : js::FrozenAtomSet& permanentAtoms() { return *runtime_->permanentAtoms; }
176 0 : js::WellKnownSymbols& wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
177 0 : JS::BuildIdOp buildIdOp() { return runtime_->buildIdOp; }
178 0 : const JS::AsmJSCacheOps& asmJSCacheOps() { return runtime_->asmJSCacheOps; }
179 0 : js::PropertyName* emptyString() { return runtime_->emptyString; }
180 0 : js::FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
181 0 : void* stackLimitAddress(JS::StackKind kind) { return &nativeStackLimit[kind]; }
182 : void* stackLimitAddressForJitCode(JS::StackKind kind);
183 0 : uintptr_t stackLimit(JS::StackKind kind) { return nativeStackLimit[kind]; }
184 : uintptr_t stackLimitForJitCode(JS::StackKind kind);
185 : size_t gcSystemPageSize() { return js::gc::SystemPageSize(); }
186 0 : bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
187 0 : bool jitSupportsUnalignedAccesses() const { return runtime_->jitSupportsUnalignedAccesses; }
188 0 : bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }
189 0 : bool lcovEnabled() const { return runtime_->lcovOutput().isEnabled(); }
190 :
191 : /*
192 : * "Entering" a realm changes cx->realm (which changes cx->global). Note
193 : * that this does not push an Activation so it's possible for the caller's
194 : * realm to be != cx->realm(). This is not a problem since, in general, most
195 : * places in the VM cannot know that they were called from script (e.g.,
196 : * they may have been called through the JSAPI via JS_CallFunction) and thus
197 : * cannot expect there is a scripted caller.
198 : *
199 : * Realms should be entered/left in a LIFO fasion. To enter a realm, code
200 : * should prefer using AutoRealm over JS::EnterRealm/JS::LeaveRealm.
201 : *
202 : * Also note that the JIT can enter (same-compartment) realms without going
203 : * through these methods - it will update cx->realm_ directly.
204 : */
205 : private:
206 : inline void setRealm(JS::Realm* realm);
207 : inline void enterRealm(JS::Realm* realm);
208 : inline void enterAtomsZone(const js::AutoLockForExclusiveAccess& lock);
209 :
210 : friend class js::AutoAtomsZone;
211 : friend class js::AutoRealm;
212 :
213 : public:
214 : template <typename T>
215 : inline void enterRealmOf(const T& target);
216 : inline void enterNullRealm();
217 :
218 : inline void leaveRealm(JS::Realm* oldRealm);
219 : inline void leaveAtomsZone(JS::Realm* oldRealm,
220 : const js::AutoLockForExclusiveAccess& lock);
221 :
222 : void setHelperThread(js::HelperThread* helperThread);
223 3876739 : js::HelperThread* helperThread() const { return helperThread_; }
224 :
225 : bool isNurseryAllocSuppressed() const {
226 675634 : return nurserySuppressions_;
227 : }
228 :
229 : // Threads may freely access any data in their realm, compartment and zone.
230 : JS::Compartment* compartment() const {
231 2856417 : return realm_ ? JS::GetCompartmentForRealm(realm_) : nullptr;
232 : }
233 :
234 : JS::Realm* realm() const {
235 8390240 : return realm_;
236 : }
237 :
238 : #ifdef DEBUG
239 : bool inAtomsZone() const;
240 : #endif
241 :
242 0 : JS::Zone* zone() const {
243 3511112 : MOZ_ASSERT_IF(!realm() && zone_, inAtomsZone());
244 3511112 : MOZ_ASSERT_IF(realm(), js::GetRealmZone(realm()) == zone_);
245 3511278 : return zoneRaw();
246 : }
247 :
248 : // For use when the context's zone is being read by another thread and the
249 : // compartment and zone pointers might not be in sync.
250 : JS::Zone* zoneRaw() const {
251 3511278 : return zone_;
252 : }
253 :
254 : // For JIT use.
255 : static size_t offsetOfZone() {
256 : return offsetof(JSContext, zone_);
257 : }
258 :
259 : // Zone local methods that can be used freely.
260 : inline js::LifoAlloc& typeLifoAlloc();
261 :
262 : // Current global. This is only safe to use within the scope of the
263 : // AutoRealm from which it's called.
264 : inline js::Handle<js::GlobalObject*> global() const;
265 :
266 : // Methods to access runtime data that must be protected by locks.
267 : js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
268 : return runtime_->atoms(lock);
269 : }
270 : const JS::Zone* atomsZone(js::AutoLockForExclusiveAccess& lock) {
271 72 : return runtime_->atomsZone(lock);
272 : }
273 : js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
274 0 : return runtime_->symbolRegistry(lock);
275 : }
276 : js::ScriptDataTable& scriptDataTable(js::AutoLockScriptData& lock) {
277 79098 : return runtime_->scriptDataTable(lock);
278 : }
279 :
280 : // Methods to access other runtime data that checks locking internally.
281 : js::gc::AtomMarkingRuntime& atomMarking() {
282 405272 : return runtime_->gc.atomMarking;
283 : }
284 102704 : void markAtom(JSAtom* atom) {
285 102704 : atomMarking().markAtom(this, atom);
286 0 : }
287 24 : void markAtom(JS::Symbol* symbol) {
288 24 : atomMarking().markAtom(this, symbol);
289 0 : }
290 31266 : void markId(jsid id) {
291 31266 : atomMarking().markId(this, id);
292 0 : }
293 2011 : void markAtomValue(const js::Value& value) {
294 2011 : atomMarking().markAtomValue(this, value);
295 2011 : }
296 :
297 : // Methods specific to any HelperThread for the context.
298 : bool addPendingCompileError(js::CompileError** err);
299 : void addPendingOverRecursed();
300 : void addPendingOutOfMemory();
301 :
302 0 : JSRuntime* runtime() { return runtime_; }
303 0 : const JSRuntime* runtime() const { return runtime_; }
304 :
305 : static size_t offsetOfRealm() {
306 : return offsetof(JSContext, realm_);
307 : }
308 :
309 : friend class JS::AutoSaveExceptionState;
310 : friend class js::jit::DebugModeOSRVolatileJitFrameIter;
311 : friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
312 :
313 : private:
314 : static JS::Error reportedError;
315 : static JS::OOM reportedOOM;
316 :
317 : public:
318 : inline JS::Result<> boolToResult(bool ok);
319 :
320 : /**
321 : * Intentionally awkward signpost method that is stationed on the
322 : * boundary between Result-using and non-Result-using code.
323 : */
324 : template <typename V, typename E>
325 : bool resultToBool(const JS::Result<V, E>& result) {
326 0 : return result.isOk();
327 : }
328 :
329 : template <typename V, typename E>
330 : V* resultToPtr(const JS::Result<V*, E>& result) {
331 : return result.isOk() ? result.unwrap() : nullptr;
332 : }
333 :
334 : mozilla::GenericErrorResult<JS::OOM&> alreadyReportedOOM();
335 : mozilla::GenericErrorResult<JS::Error&> alreadyReportedError();
336 :
337 : /*
338 : * Points to the most recent JitActivation pushed on the thread.
339 : * See JitActivation constructor in vm/Stack.cpp
340 : */
341 : js::ThreadData<js::jit::JitActivation*> jitActivation;
342 :
343 : // Information about the heap allocated backtrack stack used by RegExp JIT code.
344 : js::ThreadData<js::irregexp::RegExpStack> regexpStack;
345 :
346 : /*
347 : * Points to the most recent activation running on the thread.
348 : * See Activation comment in vm/Stack.h.
349 : */
350 : js::ThreadData<js::Activation*> activation_;
351 :
352 : /*
353 : * Points to the most recent profiling activation running on the
354 : * thread.
355 : */
356 : js::Activation* volatile profilingActivation_;
357 :
358 : public:
359 : js::Activation* activation() const {
360 175590 : return activation_;
361 : }
362 : static size_t offsetOfActivation() {
363 : return offsetof(JSContext, activation_);
364 : }
365 :
366 : js::Activation* profilingActivation() const {
367 0 : return profilingActivation_;
368 : }
369 : static size_t offsetOfProfilingActivation() {
370 : return offsetof(JSContext, profilingActivation_);
371 : }
372 :
373 : static size_t offsetOfJitActivation() {
374 : return offsetof(JSContext, jitActivation);
375 : }
376 :
377 : #ifdef DEBUG
378 : static size_t offsetOfInUnsafeCallWithABI() {
379 : return offsetof(JSContext, inUnsafeCallWithABI);
380 : }
381 : #endif
382 :
383 : private:
384 : /* Space for interpreter frames. */
385 : js::ThreadData<js::InterpreterStack> interpreterStack_;
386 :
387 : public:
388 : js::InterpreterStack& interpreterStack() {
389 44266 : return interpreterStack_.ref();
390 : }
391 :
392 : /* Base address of the native stack for the current thread. */
393 : const uintptr_t nativeStackBase;
394 :
395 : /* The native stack size limit that runtime should not exceed. */
396 : js::ThreadData<size_t> nativeStackQuota[JS::StackKindCount];
397 :
398 : public:
399 : /* If non-null, report JavaScript entry points to this monitor. */
400 : js::ThreadData<JS::dbg::AutoEntryMonitor*> entryMonitor;
401 :
402 : /*
403 : * Stack of debuggers that currently disallow debuggee execution.
404 : *
405 : * When we check for NX we are inside the debuggee compartment, and thus a
406 : * stack of Debuggers that have prevented execution need to be tracked to
407 : * enter the correct Debugger compartment to report the error.
408 : */
409 : js::ThreadData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
410 :
411 : js::ThreadData<js::ActivityCallback> activityCallback;
412 : js::ThreadData<void*> activityCallbackArg;
413 : void triggerActivityCallback(bool active);
414 :
415 : /* The request depth for this thread. */
416 : js::ThreadData<unsigned> requestDepth;
417 :
418 : #ifdef DEBUG
419 : js::ThreadData<unsigned> checkRequestDepth;
420 : js::ThreadData<uint32_t> inUnsafeCallWithABI;
421 : js::ThreadData<bool> hasAutoUnsafeCallWithABI;
422 : #endif
423 :
424 : #ifdef JS_SIMULATOR
425 : private:
426 : js::ThreadData<js::jit::Simulator*> simulator_;
427 : public:
428 : js::jit::Simulator* simulator() const;
429 : uintptr_t* addressOfSimulatorStackLimit();
430 : #endif
431 :
432 : #ifdef JS_TRACE_LOGGING
433 : js::ThreadData<js::TraceLoggerThread*> traceLogger;
434 : #endif
435 :
436 : private:
437 : /* Pointer to the current AutoFlushICache. */
438 : js::ThreadData<js::jit::AutoFlushICache*> autoFlushICache_;
439 : public:
440 :
441 : js::jit::AutoFlushICache* autoFlushICache() const;
442 : void setAutoFlushICache(js::jit::AutoFlushICache* afc);
443 :
444 : // State used by util/DoubleToString.cpp.
445 : js::ThreadData<DtoaState*> dtoaState;
446 :
447 : /*
448 : * When this flag is non-zero, any attempt to GC will be skipped. It is used
449 : * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in
450 : * debugging facilities that cannot tolerate a GC and would rather OOM
451 : * immediately, such as utilities exposed to GDB. Setting this flag is
452 : * extremely dangerous and should only be used when in an OOM situation or
453 : * in non-exposed debugging facilities.
454 : */
455 : js::ThreadData<int32_t> suppressGC;
456 :
457 : #ifdef DEBUG
458 : // Whether this thread is actively Ion compiling.
459 : js::ThreadData<bool> ionCompiling;
460 :
461 : // Whether this thread is actively Ion compiling in a context where a minor
462 : // GC could happen simultaneously. If this is true, this thread cannot use
463 : // any pointers into the nursery.
464 : js::ThreadData<bool> ionCompilingSafeForMinorGC;
465 :
466 : // Whether this thread is currently performing GC. This thread could be the
467 : // main thread or a helper thread while the main thread is running the
468 : // collector.
469 : js::ThreadData<bool> performingGC;
470 :
471 : // Whether this thread is currently sweeping GC things. This thread could
472 : // be the main thread or a helper thread while the main thread is running
473 : // the mutator. This is used to assert that destruction of GCPtr only
474 : // happens when we are sweeping.
475 : js::ThreadData<bool> gcSweeping;
476 :
477 : // Whether this thread is performing work in the background for a runtime's
478 : // GCHelperState.
479 : js::ThreadData<bool> gcHelperStateThread;
480 :
481 : // Whether this thread is currently manipulating possibly-gray GC things.
482 : js::ThreadData<size_t> isTouchingGrayThings;
483 :
484 : js::ThreadData<size_t> noGCOrAllocationCheck;
485 : js::ThreadData<size_t> noNurseryAllocationCheck;
486 :
487 : /*
488 : * If this is 0, all cross-compartment proxies must be registered in the
489 : * wrapper map. This checking must be disabled temporarily while creating
490 : * new wrappers. When non-zero, this records the recursion depth of wrapper
491 : * creation.
492 : */
493 : js::ThreadData<uintptr_t> disableStrictProxyCheckingCount;
494 :
495 : bool isAllocAllowed() { return noGCOrAllocationCheck == 0; }
496 : void disallowAlloc() { ++noGCOrAllocationCheck; }
497 : void allowAlloc() {
498 868877 : MOZ_ASSERT(!isAllocAllowed());
499 : --noGCOrAllocationCheck;
500 : }
501 :
502 : bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; }
503 : void disallowNurseryAlloc() { ++noNurseryAllocationCheck; }
504 : void allowNurseryAlloc() {
505 208022 : MOZ_ASSERT(!isNurseryAllocAllowed());
506 0 : --noNurseryAllocationCheck;
507 0 : }
508 0 :
509 0 : bool isStrictProxyCheckingEnabled() { return disableStrictProxyCheckingCount == 0; }
510 0 : void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; }
511 : void enableStrictProxyChecking() {
512 1876 : MOZ_ASSERT(disableStrictProxyCheckingCount > 0);
513 0 : --disableStrictProxyCheckingCount;
514 57681 : }
515 115362 : #endif
516 115362 :
517 57681 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
518 : // We are currently running a simulated OOM test.
519 : js::ThreadData<bool> runningOOMTest;
520 : #endif
521 :
522 : // True if we should assert that
523 : // !comp->validAccessPtr || *comp->validAccessPtr
524 : // is true for every |comp| that we run JS code in.
525 : js::ThreadData<unsigned> enableAccessValidation;
526 :
527 : /*
528 : * Some regions of code are hard for the static rooting hazard analysis to
529 : * understand. In those cases, we trade the static analysis for a dynamic
530 : * analysis. When this is non-zero, we should assert if we trigger, or
531 : * might trigger, a GC.
532 : */
533 : js::ThreadData<int> inUnsafeRegion;
534 :
535 : // Count of AutoDisableGenerationalGC instances on the thread's stack.
536 : js::ThreadData<unsigned> generationalDisabled;
537 :
538 : // Some code cannot tolerate compacting GC so it can be disabled temporarily
539 : // with AutoDisableCompactingGC which uses this counter.
540 : js::ThreadData<unsigned> compactingDisabledCount;
541 :
542 : bool canCollectAtoms() const {
543 : return !runtime()->hasHelperThreadZones();
544 : }
545 0 :
546 0 : private:
547 : // Pools used for recycling name maps and vectors when parsing and
548 : // emitting bytecode. Purged on GC when there are no active script
549 : // compilations.
550 : js::ThreadData<js::frontend::NameCollectionPool> frontendCollectionPool_;
551 : public:
552 :
553 : js::frontend::NameCollectionPool& frontendCollectionPool() {
554 : return frontendCollectionPool_.ref();
555 : }
556 :
557 209748 : void verifyIsSafeToGC() {
558 : MOZ_DIAGNOSTIC_ASSERT(!inUnsafeRegion,
559 : "[AutoAssertNoGC] possible GC in GC-unsafe region");
560 297320 : }
561 594636 :
562 : /* Whether sampling should be enabled or not. */
563 297316 : private:
564 : mozilla::Atomic<bool, mozilla::SequentiallyConsistent> suppressProfilerSampling;
565 :
566 : public:
567 : bool isProfilerSamplingEnabled() const {
568 : return !suppressProfilerSampling;
569 : }
570 : void disableProfilerSampling() {
571 0 : suppressProfilerSampling = true;
572 : }
573 : void enableProfilerSampling() {
574 1704 : suppressProfilerSampling = false;
575 : }
576 :
577 1704 : #if defined(XP_DARWIN)
578 : js::wasm::MachExceptionHandler wasmMachExceptionHandler;
579 : #endif
580 :
581 : /* Temporary arena pool used while compiling and decompiling. */
582 : static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
583 : private:
584 : js::ThreadData<js::LifoAlloc> tempLifoAlloc_;
585 : public:
586 : js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
587 : const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
588 :
589 0 : js::ThreadData<uint32_t> debuggerMutations;
590 0 :
591 : // Cache for jit::GetPcScript().
592 : js::ThreadData<js::jit::PcScriptCache*> ionPcScriptCache;
593 :
594 : private:
595 : /* Exception state -- the exception member is a GC root by definition. */
596 : js::ThreadData<bool> throwing; /* is there a pending exception? */
597 : js::ThreadData<JS::PersistentRooted<JS::Value>> unwrappedException_; /* most-recently-thrown exception */
598 :
599 : JS::Value& unwrappedException() {
600 : if (!unwrappedException_.ref().initialized())
601 : unwrappedException_.ref().init(this);
602 3659 : return unwrappedException_.ref().get();
603 0 : }
604 3 :
605 3659 : // True if the exception currently being thrown is by result of
606 : // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
607 : js::ThreadData<bool> overRecursed_;
608 :
609 : // True if propagating a forced return from an interrupt handler during
610 : // debug mode.
611 : js::ThreadData<bool> propagatingForcedReturn_;
612 :
613 : // A stack of live iterators that need to be updated in case of debug mode
614 : // OSR.
615 : js::ThreadData<js::jit::DebugModeOSRVolatileJitFrameIter*>
616 : liveVolatileJitFrameIter_;
617 :
618 : public:
619 : js::ThreadData<int32_t> reportGranularity; /* see vm/Probes.h */
620 :
621 : js::ThreadData<js::AutoResolving*> resolvingList;
622 :
623 : #ifdef DEBUG
624 : js::ThreadData<js::AutoEnterPolicy*> enteredPolicy;
625 : #endif
626 :
627 : /* True if generating an error, to prevent runaway recursion. */
628 : js::ThreadData<bool> generatingError;
629 :
630 : private:
631 : /* State for object and array toSource conversion. */
632 : js::ThreadData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
633 :
634 : public:
635 : js::AutoCycleDetector::Vector& cycleDetectorVector() {
636 : return cycleDetectorVector_.ref();
637 : }
638 : const js::AutoCycleDetector::Vector& cycleDetectorVector() const {
639 2568 : return cycleDetectorVector_.ref();
640 : }
641 :
642 0 : /* Client opaque pointer. */
643 : js::UnprotectedData<void*> data;
644 :
645 : void initJitStackLimit();
646 : void resetJitStackLimit();
647 :
648 : public:
649 : JS::ContextOptions& options() {
650 : return options_.ref();
651 : }
652 :
653 199471 : bool runtimeMatches(JSRuntime* rt) const {
654 : return runtime_ == rt;
655 : }
656 :
657 : // Number of JS_BeginRequest calls without the corresponding JS_EndRequest.
658 : js::ThreadData<unsigned> outstandingRequests;
659 :
660 : js::ThreadData<bool> jitIsBroken;
661 :
662 : void updateJITEnabled();
663 :
664 : private:
665 : /*
666 : * Youngest frame of a saved stack that will be picked up as an async stack
667 : * by any new Activation, and is nullptr when no async stack should be used.
668 : *
669 : * The JS::AutoSetAsyncStackForNewCalls class can be used to set this.
670 : *
671 : * New activations will reset this to nullptr on construction after getting
672 : * the current value, and will restore the previous value on destruction.
673 : */
674 : js::ThreadData<JS::PersistentRooted<js::SavedFrame*>> asyncStackForNewActivations_;
675 : public:
676 :
677 : js::SavedFrame*& asyncStackForNewActivations() {
678 : if (!asyncStackForNewActivations_.ref().initialized())
679 : asyncStackForNewActivations_.ref().init(this);
680 83547 : return asyncStackForNewActivations_.ref().get();
681 167093 : }
682 4 :
683 83546 : /*
684 : * Value of asyncCause to be attached to asyncStackForNewActivations.
685 : */
686 : js::ThreadData<const char*> asyncCauseForNewActivations;
687 :
688 : /*
689 : * True if the async call was explicitly requested, e.g. via
690 : * callFunctionWithAsyncStack.
691 : */
692 : js::ThreadData<bool> asyncCallIsExplicit;
693 :
694 : bool currentlyRunningInInterpreter() const {
695 : return activation()->isInterpreter();
696 : }
697 : bool currentlyRunningInJit() const {
698 : return activation()->isJit();
699 : }
700 : js::InterpreterFrame* interpreterFrame() const {
701 29 : return activation()->asInterpreter()->current();
702 : }
703 15001 : js::InterpreterRegs& interpreterRegs() const {
704 30002 : return activation()->asInterpreter()->regs();
705 : }
706 :
707 0 : /*
708 : * Get the topmost script and optional pc on the stack. By default, this
709 : * function only returns a JSScript in the current compartment, returning
710 : * nullptr if the current script is in a different compartment. This
711 : * behavior can be overridden by passing ALLOW_CROSS_COMPARTMENT.
712 : */
713 : enum MaybeAllowCrossCompartment {
714 : DONT_ALLOW_CROSS_COMPARTMENT = false,
715 : ALLOW_CROSS_COMPARTMENT = true
716 : };
717 : inline JSScript* currentScript(jsbytecode** pc = nullptr,
718 : MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
719 :
720 : inline js::Nursery& nursery();
721 : inline void minorGC(JS::gcreason::Reason reason);
722 :
723 : public:
724 : bool isExceptionPending() const {
725 : return throwing;
726 : }
727 :
728 998118 : MOZ_MUST_USE
729 : bool getPendingException(JS::MutableHandleValue rval);
730 :
731 : bool isThrowingOutOfMemory();
732 : bool isThrowingDebuggeeWouldRun();
733 : bool isClosingGenerator();
734 :
735 : void setPendingException(const js::Value& v);
736 :
737 : void clearPendingException() {
738 : throwing = false;
739 : overRecursed_ = false;
740 588 : unwrappedException().setUndefined();
741 1176 : }
742 1176 :
743 1176 : bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
744 588 : bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
745 : void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
746 22 : void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
747 186 :
748 0 : /*
749 0 : * See JS_SetTrustedPrincipals in jsapi.h.
750 : * Note: !cx->compartment is treated as trusted.
751 : */
752 : inline bool runningWithTrustedPrincipals();
753 :
754 : JS_FRIEND_API(size_t) sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
755 :
756 : void trace(JSTracer* trc);
757 :
758 : inline js::RuntimeCaches& caches();
759 :
760 : private:
761 : /*
762 : * The allocation code calls the function to indicate either OOM failure
763 : * when p is null or that a memory pressure counter has reached some
764 : * threshold when p is not null. The function takes the pointer and not
765 : * a boolean flag to minimize the amount of code in its inlined callers.
766 : */
767 : JS_FRIEND_API(void) checkMallocGCPressure(void* p);
768 :
769 : public:
770 : using InterruptCallbackVector = js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
771 :
772 : private:
773 : js::ThreadData<InterruptCallbackVector> interruptCallbacks_;
774 : public:
775 : InterruptCallbackVector& interruptCallbacks() { return interruptCallbacks_.ref(); }
776 :
777 : js::ThreadData<bool> interruptCallbackDisabled;
778 4 :
779 : // Bitfield storing InterruptReason values.
780 : mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptBits_;
781 :
782 : // Any thread can call requestInterrupt() to request that this thread
783 : // stop running. To stop this thread, requestInterrupt sets two fields:
784 : // interruptBits_ (a bitset of InterruptReasons) and jitStackLimit_ (set to
785 : // UINTPTR_MAX). The JS engine must continually poll one of these fields
786 : // and call handleInterrupt if either field has the interrupt value.
787 : //
788 : // The point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code
789 : // already needs to guard on jitStackLimit_ in every function prologue to
790 : // avoid stack overflow, so we avoid a second branch on interruptBits_ by
791 : // setting jitStackLimit_ to a value that is guaranteed to fail the guard.)
792 : //
793 : // Note that the writes to interruptBits_ and jitStackLimit_ use a Relaxed
794 : // Atomic so, while the writes are guaranteed to eventually be visible to
795 : // this thread, it can happen in any order. handleInterrupt calls the
796 : // interrupt callback if either is set, so it really doesn't matter as long
797 : // as the JS engine is continually polling at least one field. In corner
798 : // cases, this relaxed ordering could lead to an interrupt handler being
799 : // called twice in succession after a single requestInterrupt call, but
800 : // that's fine.
801 : void requestInterrupt(js::InterruptReason reason);
802 : bool handleInterrupt();
803 :
804 : MOZ_ALWAYS_INLINE bool hasAnyPendingInterrupt() const {
805 : static_assert(sizeof(interruptBits_) == sizeof(uint32_t), "Assumed by JIT callers");
806 : return interruptBits_ != 0;
807 : }
808 : bool hasPendingInterrupt(js::InterruptReason reason) const {
809 699724 : return interruptBits_ & uint32_t(reason);
810 : }
811 :
812 200 : public:
813 : void* addressOfInterruptBits() {
814 : return &interruptBits_;
815 : }
816 : void* addressOfJitStackLimit() {
817 981 : return &jitStackLimit;
818 : }
819 : void* addressOfJitStackLimitNoInterrupt() {
820 858 : return &jitStackLimitNoInterrupt;
821 : }
822 :
823 149 : /* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics object */
824 : js::FutexThread fx;
825 :
826 : // Buffer for OSR from baseline to Ion. To avoid holding on to this for
827 : // too long, it's also freed in EnterBaseline (after returning from JIT code).
828 : js::ThreadData<uint8_t*> osrTempData_;
829 :
830 : uint8_t* allocateOsrTempData(size_t size);
831 : void freeOsrTempData();
832 :
833 : // In certain cases, we want to optimize certain opcodes to typed instructions,
834 : // to avoid carrying an extra register to feed into an unbox. Unfortunately,
835 : // that's not always possible. For example, a GetPropertyCacheT could return a
836 : // typed double, but if it takes its out-of-line path, it could return an
837 : // object, and trigger invalidation. The invalidation bailout will consider the
838 : // return value to be a double, and create a garbage Value.
839 : //
840 : // To allow the GetPropertyCacheT optimization, we allow the ability for
841 : // GetPropertyCache to override the return value at the top of the stack - the
842 : // value that will be temporarily corrupt. This special override value is set
843 : // only in callVM() targets that are about to return *and* have invalidated
844 : // their callee.
845 : js::ThreadData<js::Value> ionReturnOverride_;
846 :
847 : bool hasIonReturnOverride() const {
848 : return !ionReturnOverride_.ref().isMagic(JS_ARG_POISON);
849 : }
850 15720 : js::Value takeIonReturnOverride() {
851 15720 : js::Value v = ionReturnOverride_;
852 : ionReturnOverride_ = js::MagicValue(JS_ARG_POISON);
853 0 : return v;
854 0 : }
855 0 : void setIonReturnOverride(const js::Value& v) {
856 0 : MOZ_ASSERT(!hasIonReturnOverride());
857 : MOZ_ASSERT(!v.isMagic());
858 0 : ionReturnOverride_ = v;
859 0 : }
860 0 :
861 0 : mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
862 0 :
863 : // Like jitStackLimit, but not reset to trigger interrupts.
864 : js::ThreadData<uintptr_t> jitStackLimitNoInterrupt;
865 :
866 : // Promise callbacks.
867 : js::ThreadData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
868 : js::ThreadData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
869 : js::ThreadData<void*> enqueuePromiseJobCallbackData;
870 :
871 : // Queue of pending jobs as described in ES2016 section 8.4.
872 : // Only used if internal job queue handling was activated using
873 : // `js::UseInternalJobQueues`.
874 : js::ThreadData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
875 : js::ThreadData<bool> drainingJobQueue;
876 : js::ThreadData<bool> stopDrainingJobQueue;
877 :
878 : js::ThreadData<JSPromiseRejectionTrackerCallback> promiseRejectionTrackerCallback;
879 : js::ThreadData<void*> promiseRejectionTrackerCallbackData;
880 :
881 : JSObject* getIncumbentGlobal(JSContext* cx);
882 : bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise,
883 : js::HandleObject incumbentGlobal);
884 : void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
885 : void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
886 : }; /* struct JSContext */
887 :
888 : inline JS::Result<>
889 : JSContext::boolToResult(bool ok)
890 : {
891 : if (MOZ_LIKELY(ok)) {
892 : MOZ_ASSERT(!isExceptionPending());
893 : MOZ_ASSERT(!isPropagatingForcedReturn());
894 : return JS::Ok();
895 : }
896 : return JS::Result<>(reportedError);
897 : }
898 :
899 : inline JSContext*
900 : JSRuntime::mainContextFromOwnThread()
901 : {
902 : MOZ_ASSERT(mainContextFromAnyThread() == js::TlsContext.get());
903 114 : return mainContextFromAnyThread();
904 : }
905 228 :
906 114 : namespace js {
907 :
908 : struct MOZ_RAII AutoResolving {
909 : public:
910 : enum Kind {
911 : LOOKUP,
912 : WATCH
913 : };
914 :
915 : AutoResolving(JSContext* cx, HandleObject obj, HandleId id, Kind kind = LOOKUP
916 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
917 : : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList)
918 18040 : {
919 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
920 54120 : MOZ_ASSERT(obj);
921 : cx->resolvingList = this;
922 36080 : }
923 18040 :
924 36080 : ~AutoResolving() {
925 18040 : MOZ_ASSERT(context->resolvingList == this);
926 : context->resolvingList = link;
927 36079 : }
928 36079 :
929 0 : bool alreadyStarted() const {
930 18039 : return link && alreadyStartedSlow();
931 : }
932 :
933 18040 : private:
934 : bool alreadyStartedSlow() const;
935 :
936 : JSContext* const context;
937 : HandleObject object;
938 : HandleId id;
939 : Kind const kind;
940 : AutoResolving* const link;
941 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
942 : };
943 :
944 : /*
945 : * Create and destroy functions for JSContext, which is manually allocated
946 : * and exclusively owned.
947 : */
948 : extern JSContext*
949 : NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime);
950 :
951 : extern void
952 : DestroyContext(JSContext* cx);
953 :
954 : enum ErrorArgumentsType {
955 : ArgumentsAreUnicode,
956 : ArgumentsAreASCII,
957 : ArgumentsAreLatin1,
958 : ArgumentsAreUTF8
959 : };
960 :
961 : /**
962 : * Report an exception, using printf-style APIs to generate the error
963 : * message.
964 : */
965 : #ifdef va_start
966 : extern bool
967 : ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
968 : ErrorArgumentsType argumentsType, va_list ap) MOZ_FORMAT_PRINTF(3, 0);
969 :
970 : extern bool
971 : ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback,
972 : void* userRef, const unsigned errorNumber,
973 : ErrorArgumentsType argumentsType, va_list ap);
974 :
975 : extern bool
976 : ReportErrorNumberUCArray(JSContext* cx, unsigned flags, JSErrorCallback callback,
977 : void* userRef, const unsigned errorNumber,
978 : const char16_t** args);
979 : #endif
980 :
981 : extern bool
982 : ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
983 : void* userRef, const unsigned errorNumber,
984 : const char16_t** messageArgs,
985 : ErrorArgumentsType argumentsType,
986 : JSErrorReport* reportp, va_list ap);
987 :
988 : extern bool
989 : ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
990 : void* userRef, const unsigned errorNumber,
991 : const char16_t** messageArgs,
992 : ErrorArgumentsType argumentsType,
993 : JSErrorNotes::Note* notep, va_list ap);
994 :
995 : /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
996 : extern void
997 : ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg);
998 :
999 : /*
1000 : * Prints a full report and returns true if the given report is non-nullptr
1001 : * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings
1002 : * is true.
1003 : * Returns false otherwise.
1004 : */
1005 : extern bool
1006 : PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
1007 : JSErrorReport* report, bool reportWarnings);
1008 :
1009 : extern void
1010 : ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
1011 :
1012 : extern void
1013 : ReportIsNotDefined(JSContext* cx, HandleId id);
1014 :
1015 : /*
1016 : * Report an attempt to access the property of a null or undefined value (v).
1017 : */
1018 : extern void
1019 : ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v);
1020 :
1021 : extern void
1022 : ReportMissingArg(JSContext* cx, js::HandleValue v, unsigned arg);
1023 :
1024 : /*
1025 : * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
1026 : * the first argument for the error message. If the error message has less
1027 : * then 3 arguments, use null for arg1 or arg2.
1028 : */
1029 : extern bool
1030 : ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNumber,
1031 : int spindex, HandleValue v, HandleString fallback,
1032 : const char* arg1, const char* arg2);
1033 :
1034 : inline void
1035 : ReportValueError(JSContext* cx, const unsigned errorNumber, int spindex, HandleValue v,
1036 : HandleString fallback, const char* arg1 = nullptr, const char* arg2 = nullptr)
1037 : {
1038 : ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, spindex, v, fallback, arg1, arg2);
1039 : }
1040 :
1041 : JSObject*
1042 : CreateErrorNotesArray(JSContext* cx, JSErrorReport* report);
1043 :
1044 : } /* namespace js */
1045 :
1046 : extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
1047 :
1048 : namespace js {
1049 :
1050 : /************************************************************************/
1051 :
1052 : /* AutoArrayRooter roots an external array of Values. */
1053 : class MOZ_RAII AutoArrayRooter : private JS::AutoGCRooter
1054 : {
1055 : public:
1056 : AutoArrayRooter(JSContext* cx, size_t len, Value* vec
1057 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1058 : : JS::AutoGCRooter(cx, JS::AutoGCRooter::Tag::Array), array_(vec), length_(len)
1059 : {
1060 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1061 20326 : }
1062 :
1063 : Value* begin() {
1064 : return array_;
1065 : }
1066 60978 :
1067 : size_t length() {
1068 40652 : return length_;
1069 : }
1070 :
1071 : friend void JS::AutoGCRooter::trace(JSTracer* trc);
1072 :
1073 : private:
1074 : Value* array_;
1075 : size_t length_;
1076 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1077 : };
1078 :
1079 : class AutoAssertNoException
1080 : {
1081 : #ifdef DEBUG
1082 : JSContext* cx;
1083 : bool hadException;
1084 : #endif
1085 :
1086 : public:
1087 : explicit AutoAssertNoException(JSContext* cx)
1088 : #ifdef DEBUG
1089 : : cx(cx),
1090 : hadException(cx->isExceptionPending())
1091 : #endif
1092 : {
1093 : }
1094 :
1095 : ~AutoAssertNoException()
1096 : {
1097 63140 : MOZ_ASSERT_IF(!hadException, !cx->isExceptionPending());
1098 126280 : }
1099 : };
1100 :
1101 : class MOZ_RAII AutoLockForExclusiveAccess
1102 : {
1103 63140 : JSRuntime* runtime;
1104 63140 :
1105 126280 : void init(JSRuntime* rt) {
1106 63140 : MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt) || CurrentThreadIsParseThread());
1107 : runtime = rt;
1108 : if (runtime->hasHelperThreadZones()) {
1109 : runtime->exclusiveAccessLock.lock();
1110 : } else {
1111 : MOZ_ASSERT(!runtime->activeThreadHasExclusiveAccess);
1112 : #ifdef DEBUG
1113 66669 : runtime->activeThreadHasExclusiveAccess = true;
1114 66669 : #endif
1115 66669 : }
1116 133338 : }
1117 5928 :
1118 : public:
1119 60741 : explicit AutoLockForExclusiveAccess(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1120 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1121 60741 : init(cx->runtime());
1122 : }
1123 : explicit AutoLockForExclusiveAccess(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1124 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1125 : init(rt);
1126 : }
1127 133320 : ~AutoLockForExclusiveAccess() {
1128 133320 : if (runtime->hasHelperThreadZones()) {
1129 0 : runtime->exclusiveAccessLock.unlock();
1130 : } else {
1131 0 : MOZ_ASSERT(runtime->activeThreadHasExclusiveAccess);
1132 0 : #ifdef DEBUG
1133 9 : runtime->activeThreadHasExclusiveAccess = false;
1134 : #endif
1135 133338 : }
1136 133338 : }
1137 5928 :
1138 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1139 0 : };
1140 :
1141 0 : class MOZ_RAII AutoLockScriptData
1142 : {
1143 : JSRuntime* runtime;
1144 66669 :
1145 : public:
1146 : explicit AutoLockScriptData(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1147 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1148 : MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt) || CurrentThreadIsParseThread());
1149 : runtime = rt;
1150 : if (runtime->hasHelperThreadZones()) {
1151 : runtime->scriptDataLock.lock();
1152 : } else {
1153 : MOZ_ASSERT(!runtime->activeThreadHasScriptDataAccess);
1154 0 : #ifdef DEBUG
1155 0 : runtime->activeThreadHasScriptDataAccess = true;
1156 13491 : #endif
1157 0 : }
1158 0 : }
1159 0 : ~AutoLockScriptData() {
1160 : if (runtime->hasHelperThreadZones()) {
1161 0 : runtime->scriptDataLock.unlock();
1162 : } else {
1163 0 : MOZ_ASSERT(runtime->activeThreadHasScriptDataAccess);
1164 : #ifdef DEBUG
1165 : runtime->activeThreadHasScriptDataAccess = false;
1166 13491 : #endif
1167 0 : }
1168 26982 : }
1169 1954 :
1170 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1171 11537 : };
1172 :
1173 11537 : class MOZ_RAII AutoKeepAtoms
1174 : {
1175 : JSContext* cx;
1176 13491 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1177 :
1178 : public:
1179 : explicit inline AutoKeepAtoms(JSContext* cx
1180 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
1181 : inline ~AutoKeepAtoms();
1182 : };
1183 :
1184 : // Debugging RAII class which marks the current thread as performing an Ion
1185 : // compilation, for use by CurrentThreadCan{Read,Write}CompilationData
1186 : class MOZ_RAII AutoEnterIonCompilation
1187 : {
1188 : public:
1189 : explicit AutoEnterIonCompilation(bool safeForMinorGC
1190 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1191 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1192 :
1193 : #ifdef DEBUG
1194 : JSContext* cx = TlsContext.get();
1195 : MOZ_ASSERT(!cx->ionCompiling);
1196 : MOZ_ASSERT(!cx->ionCompilingSafeForMinorGC);
1197 0 : cx->ionCompiling = true;
1198 100 : cx->ionCompilingSafeForMinorGC = safeForMinorGC;
1199 0 : #endif
1200 : }
1201 :
1202 0 : ~AutoEnterIonCompilation() {
1203 100 : #ifdef DEBUG
1204 100 : JSContext* cx = TlsContext.get();
1205 100 : MOZ_ASSERT(cx->ionCompiling);
1206 100 : cx->ionCompiling = false;
1207 : cx->ionCompilingSafeForMinorGC = false;
1208 50 : #endif
1209 : }
1210 100 :
1211 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1212 50 : };
1213 100 :
1214 100 : // Should be used in functions called directly from JIT code (with
1215 0 : // masm.callWithABI) to assert invariants in debug builds.
1216 : class MOZ_RAII AutoUnsafeCallWithABI
1217 0 : {
1218 : #ifdef DEBUG
1219 : JSContext* cx_;
1220 : bool nested_;
1221 : #endif
1222 : JS::AutoCheckCannotGC nogc;
1223 :
1224 : public:
1225 : #ifdef DEBUG
1226 : AutoUnsafeCallWithABI();
1227 : ~AutoUnsafeCallWithABI();
1228 : #endif
1229 : };
1230 :
1231 : namespace gc {
1232 :
1233 : // In debug builds, set/unset the performing GC flag for the current thread.
1234 : struct MOZ_RAII AutoSetThreadIsPerformingGC
1235 : {
1236 : #ifdef DEBUG
1237 : AutoSetThreadIsPerformingGC()
1238 : : cx(TlsContext.get())
1239 : {
1240 : MOZ_ASSERT(!cx->performingGC);
1241 : cx->performingGC = true;
1242 : }
1243 :
1244 : ~AutoSetThreadIsPerformingGC() {
1245 0 : MOZ_ASSERT(cx->performingGC);
1246 0 : cx->performingGC = false;
1247 : }
1248 0 :
1249 50 : private:
1250 0 : JSContext* cx;
1251 : #else
1252 0 : AutoSetThreadIsPerformingGC() {}
1253 0 : #endif
1254 0 : };
1255 0 :
1256 : // In debug builds, set/unset the GC sweeping flag for the current thread.
1257 : struct MOZ_RAII AutoSetThreadIsSweeping
1258 : {
1259 : #ifdef DEBUG
1260 : AutoSetThreadIsSweeping()
1261 : : cx(TlsContext.get())
1262 : {
1263 : MOZ_ASSERT(!cx->gcSweeping);
1264 : cx->gcSweeping = true;
1265 : }
1266 :
1267 : ~AutoSetThreadIsSweeping() {
1268 0 : MOZ_ASSERT(cx->gcSweeping);
1269 0 : cx->gcSweeping = false;
1270 : }
1271 0 :
1272 0 : private:
1273 0 : JSContext* cx;
1274 : #else
1275 0 : AutoSetThreadIsSweeping() {}
1276 0 : #endif
1277 0 : };
1278 0 :
1279 : } // namespace gc
1280 :
1281 : } /* namespace js */
1282 :
1283 : #endif /* vm_JSContext_h */
|