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 #ifdef _MSC_VER
25 #pragma warning(push)
26 #pragma warning( \
27 disable : 4100) /* Silence unreferenced formal parameter warnings */
28 #endif
29
30 struct DtoaState;
31
32 namespace js {
33
34 class AutoCompartment;
35
36 namespace jit {
37 class JitContext;
38 class DebugModeOSRVolatileJitFrameIter;
39 } // namespace jit
40
41 namespace gc {
42 class AutoSuppressNurseryCellAlloc;
43 }
44
45 typedef HashSet<Shape*> ShapeSet;
46
47 /* Detects cycles when traversing an object graph. */
48 class MOZ_RAII AutoCycleDetector {
49 public:
50 using Vector = GCVector<JSObject*, 8>;
51
AutoCycleDetector(JSContext * cx,HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)52 AutoCycleDetector(JSContext* cx,
53 HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
54 : cx(cx), obj(cx, objArg), cyclic(true) {
55 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
56 }
57
58 ~AutoCycleDetector();
59
60 bool init();
61
foundCycle()62 bool foundCycle() { return cyclic; }
63
64 private:
65 JSContext* cx;
66 RootedObject obj;
67 bool cyclic;
68 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
69 };
70
71 struct AutoResolving;
72
73 struct HelperThread;
74
75 using JobQueue = GCVector<JSObject*, 0, SystemAllocPolicy>;
76
77 class AutoLockForExclusiveAccess;
78 class AutoLockScriptData;
79
80 void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
81
82 /* Thread Local Storage slot for storing the context for a thread. */
83 extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
84
85 enum class ContextKind { Cooperative, Background };
86
87 } /* namespace js */
88
89 /*
90 * A JSContext encapsulates the thread local state used when using the JS
91 * runtime.
92 */
93 struct JSContext : public JS::RootingContext,
94 public js::MallocProvider<JSContext> {
95 JSContext(JSRuntime* runtime, const JS::ContextOptions& options);
96 ~JSContext();
97
98 bool init(js::ContextKind kind);
99
100 private:
101 js::UnprotectedData<JSRuntime*> runtime_;
102 js::WriteOnceData<js::ContextKind> kind_;
103
104 // System handle for the thread this context is associated with.
105 js::WriteOnceData<size_t> threadNative_;
106
107 // The thread on which this context is running, if this is performing a parse
108 // task.
109 js::ThreadLocalData<js::HelperThread*> helperThread_;
110
111 friend class js::gc::AutoSuppressNurseryCellAlloc;
112 js::ThreadLocalData<size_t> nurserySuppressions_;
113
114 js::ThreadLocalData<JS::ContextOptions> options_;
115
116 js::ThreadLocalData<js::gc::ArenaLists*> arenas_;
117
118 public:
119 // This is used by helper threads to change the runtime their context is
120 // currently operating on.
121 void setRuntime(JSRuntime* rt);
122
isCooperativelyScheduledJSContext123 bool isCooperativelyScheduled() const {
124 return kind_ == js::ContextKind::Cooperative;
125 }
threadNativeJSContext126 size_t threadNative() const { return threadNative_; }
127
arenasJSContext128 inline js::gc::ArenaLists* arenas() const { return arenas_; }
129
130 template <typename T>
isInsideCurrentZoneJSContext131 bool isInsideCurrentZone(T thing) const {
132 return thing->zoneFromAnyThread() == zone_;
133 }
134
135 template <typename T>
isInsideCurrentCompartmentJSContext136 inline bool isInsideCurrentCompartment(T thing) const {
137 return thing->compartment() == compartment_;
138 }
139
140 void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes,
141 void* reallocPtr = nullptr) {
142 if (helperThread()) {
143 addPendingOutOfMemory();
144 return nullptr;
145 }
146 return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, this);
147 }
148
149 /* Clear the pending exception (if any) due to OOM. */
150 void recoverFromOutOfMemory();
151
152 void updateMallocCounter(size_t nbytes);
153
reportAllocationOverflowJSContext154 void reportAllocationOverflow() { js::ReportAllocationOverflow(this); }
155
156 // Accessors for immutable runtime data.
namesJSContext157 JSAtomState& names() { return *runtime_->commonNames; }
staticStringsJSContext158 js::StaticStrings& staticStrings() { return *runtime_->staticStrings; }
sharedImmutableStringsJSContext159 js::SharedImmutableStringsCache& sharedImmutableStrings() {
160 return runtime_->sharedImmutableStrings();
161 }
isPermanentAtomsInitializedJSContext162 bool isPermanentAtomsInitialized() { return !!runtime_->permanentAtoms; }
permanentAtomsJSContext163 js::FrozenAtomSet& permanentAtoms() { return *runtime_->permanentAtoms; }
wellKnownSymbolsJSContext164 js::WellKnownSymbols& wellKnownSymbols() {
165 return *runtime_->wellKnownSymbols;
166 }
buildIdOpJSContext167 JS::BuildIdOp buildIdOp() { return runtime_->buildIdOp; }
asmJSCacheOpsJSContext168 const JS::AsmJSCacheOps& asmJSCacheOps() { return runtime_->asmJSCacheOps; }
emptyStringJSContext169 js::PropertyName* emptyString() { return runtime_->emptyString; }
defaultFreeOpJSContext170 js::FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
stackLimitAddressJSContext171 void* stackLimitAddress(JS::StackKind kind) {
172 return &nativeStackLimit[kind];
173 }
174 void* stackLimitAddressForJitCode(JS::StackKind kind);
stackLimitJSContext175 uintptr_t stackLimit(JS::StackKind kind) { return nativeStackLimit[kind]; }
176 uintptr_t stackLimitForJitCode(JS::StackKind kind);
gcSystemPageSizeJSContext177 size_t gcSystemPageSize() { return js::gc::SystemPageSize(); }
jitSupportsFloatingPointJSContext178 bool jitSupportsFloatingPoint() const {
179 return runtime_->jitSupportsFloatingPoint;
180 }
jitSupportsUnalignedAccessesJSContext181 bool jitSupportsUnalignedAccesses() const {
182 return runtime_->jitSupportsUnalignedAccesses;
183 }
jitSupportsSimdJSContext184 bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }
lcovEnabledJSContext185 bool lcovEnabled() const { return runtime_->lcovOutput().isEnabled(); }
186
187 /*
188 * "Entering" a compartment changes cx->compartment (which changes
189 * cx->global). Note that this does not push any InterpreterFrame which means
190 * that it is possible for cx->fp()->compartment() != cx->compartment.
191 * This is not a problem since, in general, most places in the VM cannot
192 * know that they were called from script (e.g., they may have been called
193 * through the JSAPI via JS_CallFunction) and thus cannot expect fp.
194 *
195 * Compartments should be entered/left in a LIFO fasion. The depth of this
196 * enter/leave stack is maintained by enterCompartmentDepth_ and queried by
197 * hasEnteredCompartment.
198 *
199 * To enter a compartment, code should prefer using AutoCompartment over
200 * manually calling cx->enterCompartment/leaveCompartment.
201 */
202 protected:
203 js::ThreadLocalData<unsigned> enterCompartmentDepth_;
204
205 inline void setCompartment(
206 JSCompartment* comp,
207 const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
208
209 public:
hasEnteredCompartmentJSContext210 bool hasEnteredCompartment() const { return enterCompartmentDepth_ > 0; }
211 #ifdef DEBUG
getEnterCompartmentDepthJSContext212 unsigned getEnterCompartmentDepth() const { return enterCompartmentDepth_; }
213 #endif
214
215 private:
216 // We distinguish between entering the atoms compartment and all other
217 // compartments. Entering the atoms compartment requires a lock. Also, we
218 // don't call enterZoneGroup when entering the atoms compartment since that
219 // can induce GC hazards.
220 inline void enterNonAtomsCompartment(JSCompartment* c);
221 inline void enterAtomsCompartment(JSCompartment* c,
222 const js::AutoLockForExclusiveAccess& lock);
223
224 friend class js::AutoCompartment;
225
226 public:
227 template <typename T>
228 inline void enterCompartmentOf(const T& target);
229 inline void enterNullCompartment();
230 inline void leaveCompartment(
231 JSCompartment* oldCompartment,
232 const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
233
234 inline void enterZoneGroup(js::ZoneGroup* group);
235 inline void leaveZoneGroup(js::ZoneGroup* group);
236
237 void setHelperThread(js::HelperThread* helperThread);
helperThreadJSContext238 js::HelperThread* helperThread() const { return helperThread_; }
239
isNurseryAllocSuppressedJSContext240 bool isNurseryAllocSuppressed() const { return nurserySuppressions_; }
241
242 // Threads may freely access any data in their compartment and zone.
compartmentJSContext243 JSCompartment* compartment() const { return compartment_; }
zoneJSContext244 JS::Zone* zone() const {
245 MOZ_ASSERT_IF(!compartment(), !zone_);
246 MOZ_ASSERT_IF(compartment(),
247 js::GetCompartmentZone(compartment()) == zone_);
248 return zoneRaw();
249 }
250
251 // For use when the context's zone is being read by another thread and the
252 // compartment and zone pointers might not be in sync.
zoneRawJSContext253 JS::Zone* zoneRaw() const { return zone_; }
254
255 // For JIT use.
offsetOfZoneJSContext256 static size_t offsetOfZone() { return offsetof(JSContext, zone_); }
257
258 // Zone local methods that can be used freely.
259 inline js::LifoAlloc& typeLifoAlloc();
260
261 // Current global. This is only safe to use within the scope of the
262 // AutoCompartment from which it's called.
263 inline js::Handle<js::GlobalObject*> global() const;
264
265 // Methods to access runtime data that must be protected by locks.
atomsJSContext266 js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
267 return runtime_->atoms(lock);
268 }
atomsCompartmentJSContext269 JSCompartment* atomsCompartment(js::AutoLockForExclusiveAccess& lock) {
270 return runtime_->atomsCompartment(lock);
271 }
symbolRegistryJSContext272 js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
273 return runtime_->symbolRegistry(lock);
274 }
scriptDataTableJSContext275 js::ScriptDataTable& scriptDataTable(js::AutoLockScriptData& lock) {
276 return runtime_->scriptDataTable(lock);
277 }
278
279 // Methods to access other runtime data that checks locking internally.
atomMarkingJSContext280 js::gc::AtomMarkingRuntime& atomMarking() { return runtime_->gc.atomMarking; }
markAtomJSContext281 void markAtom(JSAtom* atom) { atomMarking().markAtom(this, atom); }
markAtomJSContext282 void markAtom(JS::Symbol* symbol) { atomMarking().markAtom(this, symbol); }
markIdJSContext283 void markId(jsid id) { atomMarking().markId(this, id); }
markAtomValueJSContext284 void markAtomValue(const js::Value& value) {
285 atomMarking().markAtomValue(this, value);
286 }
287
288 // Methods specific to any HelperThread for the context.
289 bool addPendingCompileError(js::CompileError** err);
290 void addPendingOverRecursed();
291 void addPendingOutOfMemory();
292
runtimeJSContext293 JSRuntime* runtime() { return runtime_; }
runtimeJSContext294 const JSRuntime* runtime() const { return runtime_; }
295
offsetOfCompartmentJSContext296 static size_t offsetOfCompartment() {
297 return offsetof(JSContext, compartment_);
298 }
299
300 friend class JS::AutoSaveExceptionState;
301 friend class js::jit::DebugModeOSRVolatileJitFrameIter;
302 friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
303
304 // Returns to the embedding to allow other cooperative threads to run. We
305 // may do this if we need access to a ZoneGroup that is in use by another
306 // thread.
yieldToEmbeddingJSContext307 void yieldToEmbedding() { (*yieldCallback_)(this); }
308
setYieldCallbackJSContext309 void setYieldCallback(js::YieldCallback callback) {
310 yieldCallback_ = callback;
311 }
312
313 private:
314 static JS::Error reportedError;
315 static JS::OOM reportedOOM;
316
317 // This callback is used to ask the embedding to allow other cooperative
318 // threads to run. We may do this if we need access to a ZoneGroup that is
319 // in use by another thread.
320 js::ThreadLocalData<js::YieldCallback> yieldCallback_;
321
322 public:
323 inline JS::Result<> boolToResult(bool ok);
324
325 /**
326 * Intentionally awkward signpost method that is stationed on the
327 * boundary between Result-using and non-Result-using code.
328 */
329 template <typename V, typename E>
resultToBoolJSContext330 bool resultToBool(const JS::Result<V, E>& result) {
331 return result.isOk();
332 }
333
334 template <typename V, typename E>
resultToPtrJSContext335 V* resultToPtr(const JS::Result<V*, E>& result) {
336 return result.isOk() ? result.unwrap() : nullptr;
337 }
338
339 mozilla::GenericErrorResult<JS::OOM&> alreadyReportedOOM();
340 mozilla::GenericErrorResult<JS::Error&> alreadyReportedError();
341
342 /*
343 * Points to the most recent JitActivation pushed on the thread.
344 * See JitActivation constructor in vm/Stack.cpp
345 */
346 js::ThreadLocalData<js::jit::JitActivation*> jitActivation;
347
348 // Information about the heap allocated backtrack stack used by RegExp JIT
349 // code.
350 js::ThreadLocalData<js::irregexp::RegExpStack> regexpStack;
351
352 /*
353 * Points to the most recent activation running on the thread.
354 * See Activation comment in vm/Stack.h.
355 */
356 js::ThreadLocalData<js::Activation*> activation_;
357
358 /*
359 * Points to the most recent profiling activation running on the
360 * thread.
361 */
362 js::Activation* volatile profilingActivation_;
363
364 public:
activationJSContext365 js::Activation* activation() const { return activation_; }
offsetOfActivationJSContext366 static size_t offsetOfActivation() {
367 return offsetof(JSContext, activation_);
368 }
369
profilingActivationJSContext370 js::Activation* profilingActivation() const { return profilingActivation_; }
offsetOfProfilingActivationJSContext371 static size_t offsetOfProfilingActivation() {
372 return offsetof(JSContext, profilingActivation_);
373 }
374
offsetOfJitActivationJSContext375 static size_t offsetOfJitActivation() {
376 return offsetof(JSContext, jitActivation);
377 }
378
379 #ifdef DEBUG
offsetOfInUnsafeCallWithABIJSContext380 static size_t offsetOfInUnsafeCallWithABI() {
381 return offsetof(JSContext, inUnsafeCallWithABI);
382 }
383 #endif
384
385 private:
386 /* Space for interpreter frames. */
387 js::ThreadLocalData<js::InterpreterStack> interpreterStack_;
388
389 public:
interpreterStackJSContext390 js::InterpreterStack& interpreterStack() { return interpreterStack_.ref(); }
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::ThreadLocalData<size_t> nativeStackQuota[JS::StackKindCount];
397
398 public:
399 /* If non-null, report JavaScript entry points to this monitor. */
400 js::ThreadLocalData<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::ThreadLocalData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
410
411 js::ThreadLocalData<js::ActivityCallback> activityCallback;
412 js::ThreadLocalData<void*> activityCallbackArg;
413 void triggerActivityCallback(bool active);
414
415 /* The request depth for this thread. */
416 js::ThreadLocalData<unsigned> requestDepth;
417
418 #ifdef DEBUG
419 js::ThreadLocalData<unsigned> checkRequestDepth;
420 js::ThreadLocalData<uint32_t> inUnsafeCallWithABI;
421 js::ThreadLocalData<bool> hasAutoUnsafeCallWithABI;
422 #endif
423
424 #ifdef JS_SIMULATOR
425 private:
426 js::ThreadLocalData<js::jit::Simulator*> simulator_;
427
428 public:
429 js::jit::Simulator* simulator() const;
430 uintptr_t* addressOfSimulatorStackLimit();
431 #endif
432
433 #ifdef JS_TRACE_LOGGING
434 js::ThreadLocalData<js::TraceLoggerThread*> traceLogger;
435 #endif
436
437 private:
438 /* Pointer to the current AutoFlushICache. */
439 js::ThreadLocalData<js::jit::AutoFlushICache*> autoFlushICache_;
440
441 public:
442 js::jit::AutoFlushICache* autoFlushICache() const;
443 void setAutoFlushICache(js::jit::AutoFlushICache* afc);
444
445 // State used by util/DoubleToString.cpp.
446 js::ThreadLocalData<DtoaState*> dtoaState;
447
448 // Any GC activity occurring on this thread.
449 js::ThreadLocalData<JS::HeapState> heapState;
450
451 /*
452 * When this flag is non-zero, any attempt to GC will be skipped. It is used
453 * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in
454 * debugging facilities that cannot tolerate a GC and would rather OOM
455 * immediately, such as utilities exposed to GDB. Setting this flag is
456 * extremely dangerous and should only be used when in an OOM situation or
457 * in non-exposed debugging facilities.
458 */
459 js::ThreadLocalData<int32_t> suppressGC;
460
461 #ifdef DEBUG
462 // Whether this thread is actively Ion compiling.
463 js::ThreadLocalData<bool> ionCompiling;
464
465 // Whether this thread is actively Ion compiling in a context where a minor
466 // GC could happen simultaneously. If this is true, this thread cannot use
467 // any pointers into the nursery.
468 js::ThreadLocalData<bool> ionCompilingSafeForMinorGC;
469
470 // Whether this thread is currently performing GC. This thread could be the
471 // active thread or a helper thread while the active thread is running the
472 // collector.
473 js::ThreadLocalData<bool> performingGC;
474
475 // Whether this thread is currently sweeping GC things. This thread could
476 // be the active thread or a helper thread while the active thread is running
477 // the mutator. This is used to assert that destruction of GCPtr only
478 // happens when we are sweeping.
479 js::ThreadLocalData<bool> gcSweeping;
480
481 // Whether this thread is performing work in the background for a runtime's
482 // GCHelperState.
483 js::ThreadLocalData<bool> gcHelperStateThread;
484
485 // Whether this thread is currently manipulating possibly-gray GC things.
486 js::ThreadLocalData<size_t> isTouchingGrayThings;
487
488 js::ThreadLocalData<size_t> noGCOrAllocationCheck;
489 js::ThreadLocalData<size_t> noNurseryAllocationCheck;
490
491 /*
492 * If this is 0, all cross-compartment proxies must be registered in the
493 * wrapper map. This checking must be disabled temporarily while creating
494 * new wrappers. When non-zero, this records the recursion depth of wrapper
495 * creation.
496 */
497 js::ThreadLocalData<uintptr_t> disableStrictProxyCheckingCount;
498
isAllocAllowedJSContext499 bool isAllocAllowed() { return noGCOrAllocationCheck == 0; }
disallowAllocJSContext500 void disallowAlloc() { ++noGCOrAllocationCheck; }
allowAllocJSContext501 void allowAlloc() {
502 MOZ_ASSERT(!isAllocAllowed());
503 --noGCOrAllocationCheck;
504 }
505
isNurseryAllocAllowedJSContext506 bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; }
disallowNurseryAllocJSContext507 void disallowNurseryAlloc() { ++noNurseryAllocationCheck; }
allowNurseryAllocJSContext508 void allowNurseryAlloc() {
509 MOZ_ASSERT(!isNurseryAllocAllowed());
510 --noNurseryAllocationCheck;
511 }
512
isStrictProxyCheckingEnabledJSContext513 bool isStrictProxyCheckingEnabled() {
514 return disableStrictProxyCheckingCount == 0;
515 }
disableStrictProxyCheckingJSContext516 void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; }
enableStrictProxyCheckingJSContext517 void enableStrictProxyChecking() {
518 MOZ_ASSERT(disableStrictProxyCheckingCount > 0);
519 --disableStrictProxyCheckingCount;
520 }
521 #endif
522
523 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
524 // We are currently running a simulated OOM test.
525 js::ThreadLocalData<bool> runningOOMTest;
526 #endif
527
528 // True if we should assert that
529 // !comp->validAccessPtr || *comp->validAccessPtr
530 // is true for every |comp| that we run JS code in.
531 js::ThreadLocalData<unsigned> enableAccessValidation;
532
533 /*
534 * Some regions of code are hard for the static rooting hazard analysis to
535 * understand. In those cases, we trade the static analysis for a dynamic
536 * analysis. When this is non-zero, we should assert if we trigger, or
537 * might trigger, a GC.
538 */
539 js::ThreadLocalData<int> inUnsafeRegion;
540
541 // Count of AutoDisableGenerationalGC instances on the thread's stack.
542 js::ThreadLocalData<unsigned> generationalDisabled;
543
544 // Some code cannot tolerate compacting GC so it can be disabled temporarily
545 // with AutoDisableCompactingGC which uses this counter.
546 js::ThreadLocalData<unsigned> compactingDisabledCount;
547
548 // Count of AutoKeepAtoms instances on the current thread's stack. When any
549 // instances exist, atoms in the runtime will not be collected. Threads
550 // parsing off the active thread do not increment this value, but the presence
551 // of any such threads also inhibits collection of atoms. We don't scan the
552 // stacks of exclusive threads, so we need to avoid collecting their
553 // objects in another way. The only GC thing pointers they have are to
554 // their exclusive compartment (which is not collected) or to the atoms
555 // compartment. Therefore, we avoid collecting the atoms compartment when
556 // exclusive threads are running.
557 js::ThreadLocalData<unsigned> keepAtoms;
558
canCollectAtomsJSContext559 bool canCollectAtoms() const {
560 return !keepAtoms && !runtime()->hasHelperThreadZones();
561 }
562
563 private:
564 // Pools used for recycling name maps and vectors when parsing and
565 // emitting bytecode. Purged on GC when there are no active script
566 // compilations.
567 js::ThreadLocalData<js::frontend::NameCollectionPool> frontendCollectionPool_;
568
569 public:
frontendCollectionPoolJSContext570 js::frontend::NameCollectionPool& frontendCollectionPool() {
571 return frontendCollectionPool_.ref();
572 }
573
verifyIsSafeToGCJSContext574 void verifyIsSafeToGC() {
575 MOZ_DIAGNOSTIC_ASSERT(!inUnsafeRegion,
576 "[AutoAssertNoGC] possible GC in GC-unsafe region");
577 }
578
579 /* Whether sampling should be enabled or not. */
580 private:
581 mozilla::Atomic<bool, mozilla::SequentiallyConsistent>
582 suppressProfilerSampling;
583
584 public:
isProfilerSamplingEnabledJSContext585 bool isProfilerSamplingEnabled() const { return !suppressProfilerSampling; }
disableProfilerSamplingJSContext586 void disableProfilerSampling() { suppressProfilerSampling = true; }
enableProfilerSamplingJSContext587 void enableProfilerSampling() { suppressProfilerSampling = false; }
588
589 #if defined(XP_DARWIN)
590 js::wasm::MachExceptionHandler wasmMachExceptionHandler;
591 #endif
592
593 /* Temporary arena pool used while compiling and decompiling. */
594 static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
595
596 private:
597 js::ThreadLocalData<js::LifoAlloc> tempLifoAlloc_;
598
599 public:
tempLifoAllocJSContext600 js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
tempLifoAllocJSContext601 const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
602
603 js::ThreadLocalData<uint32_t> debuggerMutations;
604
605 // Cache for jit::GetPcScript().
606 js::ThreadLocalData<js::jit::PcScriptCache*> ionPcScriptCache;
607
608 private:
609 /* Exception state -- the exception member is a GC root by definition. */
610 js::ThreadLocalData<bool> throwing; /* is there a pending exception? */
611 js::ThreadLocalData<JS::PersistentRooted<JS::Value>>
612 unwrappedException_; /* most-recently-thrown exception */
613
unwrappedExceptionJSContext614 JS::Value& unwrappedException() {
615 if (!unwrappedException_.ref().initialized())
616 unwrappedException_.ref().init(this);
617 return unwrappedException_.ref().get();
618 }
619
620 // True if the exception currently being thrown is by result of
621 // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
622 js::ThreadLocalData<bool> overRecursed_;
623
624 // True if propagating a forced return from an interrupt handler during
625 // debug mode.
626 js::ThreadLocalData<bool> propagatingForcedReturn_;
627
628 // A stack of live iterators that need to be updated in case of debug mode
629 // OSR.
630 js::ThreadLocalData<js::jit::DebugModeOSRVolatileJitFrameIter*>
631 liveVolatileJitFrameIter_;
632
633 public:
634 js::ThreadLocalData<int32_t> reportGranularity; /* see vm/Probes.h */
635
636 js::ThreadLocalData<js::AutoResolving*> resolvingList;
637
638 #ifdef DEBUG
639 js::ThreadLocalData<js::AutoEnterPolicy*> enteredPolicy;
640 #endif
641
642 /* True if generating an error, to prevent runaway recursion. */
643 js::ThreadLocalData<bool> generatingError;
644
645 private:
646 /* State for object and array toSource conversion. */
647 js::ThreadLocalData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
648
649 public:
cycleDetectorVectorJSContext650 js::AutoCycleDetector::Vector& cycleDetectorVector() {
651 return cycleDetectorVector_.ref();
652 }
cycleDetectorVectorJSContext653 const js::AutoCycleDetector::Vector& cycleDetectorVector() const {
654 return cycleDetectorVector_.ref();
655 }
656
657 /* Client opaque pointer. */
658 js::UnprotectedData<void*> data;
659
660 void initJitStackLimit();
661 void resetJitStackLimit();
662
663 public:
optionsJSContext664 JS::ContextOptions& options() { return options_.ref(); }
665
runtimeMatchesJSContext666 bool runtimeMatches(JSRuntime* rt) const { return runtime_ == rt; }
667
668 // Number of JS_BeginRequest calls without the corresponding JS_EndRequest.
669 js::ThreadLocalData<unsigned> outstandingRequests;
670
671 js::ThreadLocalData<bool> jitIsBroken;
672
673 void updateJITEnabled();
674
675 private:
676 /*
677 * Youngest frame of a saved stack that will be picked up as an async stack
678 * by any new Activation, and is nullptr when no async stack should be used.
679 *
680 * The JS::AutoSetAsyncStackForNewCalls class can be used to set this.
681 *
682 * New activations will reset this to nullptr on construction after getting
683 * the current value, and will restore the previous value on destruction.
684 */
685 js::ThreadLocalData<JS::PersistentRooted<js::SavedFrame*>>
686 asyncStackForNewActivations_;
687
688 public:
asyncStackForNewActivationsJSContext689 js::SavedFrame*& asyncStackForNewActivations() {
690 if (!asyncStackForNewActivations_.ref().initialized())
691 asyncStackForNewActivations_.ref().init(this);
692 return asyncStackForNewActivations_.ref().get();
693 }
694
695 /*
696 * Value of asyncCause to be attached to asyncStackForNewActivations.
697 */
698 js::ThreadLocalData<const char*> asyncCauseForNewActivations;
699
700 /*
701 * True if the async call was explicitly requested, e.g. via
702 * callFunctionWithAsyncStack.
703 */
704 js::ThreadLocalData<bool> asyncCallIsExplicit;
705
currentlyRunningInInterpreterJSContext706 bool currentlyRunningInInterpreter() const {
707 return activation()->isInterpreter();
708 }
currentlyRunningInJitJSContext709 bool currentlyRunningInJit() const { return activation()->isJit(); }
interpreterFrameJSContext710 js::InterpreterFrame* interpreterFrame() const {
711 return activation()->asInterpreter()->current();
712 }
interpreterRegsJSContext713 js::InterpreterRegs& interpreterRegs() const {
714 return activation()->asInterpreter()->regs();
715 }
716
717 /*
718 * Get the topmost script and optional pc on the stack. By default, this
719 * function only returns a JSScript in the current compartment, returning
720 * nullptr if the current script is in a different compartment. This
721 * behavior can be overridden by passing ALLOW_CROSS_COMPARTMENT.
722 */
723 enum MaybeAllowCrossCompartment {
724 DONT_ALLOW_CROSS_COMPARTMENT = false,
725 ALLOW_CROSS_COMPARTMENT = true
726 };
727 inline JSScript* currentScript(
728 jsbytecode** pc = nullptr,
729 MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
730
731 inline js::Nursery& nursery();
732 inline void minorGC(JS::gcreason::Reason reason);
733
734 public:
isExceptionPendingJSContext735 bool isExceptionPending() const { return throwing; }
736
737 MOZ_MUST_USE
738 bool getPendingException(JS::MutableHandleValue rval);
739
740 bool isThrowingOutOfMemory();
741 bool isThrowingDebuggeeWouldRun();
742 bool isClosingGenerator();
743
744 void setPendingException(const js::Value& v);
745
clearPendingExceptionJSContext746 void clearPendingException() {
747 throwing = false;
748 overRecursed_ = false;
749 unwrappedException().setUndefined();
750 }
751
isThrowingOverRecursedJSContext752 bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
isPropagatingForcedReturnJSContext753 bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
setPropagatingForcedReturnJSContext754 void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
clearPropagatingForcedReturnJSContext755 void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
756
757 /*
758 * See JS_SetTrustedPrincipals in jsapi.h.
759 * Note: !cx->compartment is treated as trusted.
760 */
761 inline bool runningWithTrustedPrincipals();
762
763 JS_FRIEND_API size_t
764 sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
765
766 void trace(JSTracer* trc);
767
768 inline js::RuntimeCaches& caches();
769
770 private:
771 /*
772 * The allocation code calls the function to indicate either OOM failure
773 * when p is null or that a memory pressure counter has reached some
774 * threshold when p is not null. The function takes the pointer and not
775 * a boolean flag to minimize the amount of code in its inlined callers.
776 */
777 JS_FRIEND_API void checkMallocGCPressure(void* p);
778
779 public:
780 using InterruptCallbackVector =
781 js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
782
783 private:
784 js::ThreadLocalData<InterruptCallbackVector> interruptCallbacks_;
785
786 public:
interruptCallbacksJSContext787 InterruptCallbackVector& interruptCallbacks() {
788 return interruptCallbacks_.ref();
789 }
790
791 js::ThreadLocalData<bool> interruptCallbackDisabled;
792
793 mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
794 mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptRegExpJit_;
795
796 enum InterruptMode { RequestInterruptUrgent, RequestInterruptCanWait };
797
798 // Any thread can call requestInterrupt() to request that this thread
799 // stop running and call the interrupt callback (allowing the interrupt
800 // callback to halt execution). To stop this thread, requestInterrupt
801 // sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to
802 // UINTPTR_MAX). The JS engine must continually poll one of these fields
803 // and call handleInterrupt if either field has the interrupt value. (The
804 // point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already
805 // needs to guard on jitStackLimit_ in every function prologue to avoid
806 // stack overflow, so we avoid a second branch on interrupt_ by setting
807 // jitStackLimit_ to a value that is guaranteed to fail the guard.)
808 //
809 // Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed
810 // Atomic so, while the writes are guaranteed to eventually be visible to
811 // this thread, it can happen in any order. handleInterrupt calls the
812 // interrupt callback if either is set, so it really doesn't matter as long
813 // as the JS engine is continually polling at least one field. In corner
814 // cases, this relaxed ordering could lead to an interrupt handler being
815 // called twice in succession after a single requestInterrupt call, but
816 // that's fine.
817 void requestInterrupt(InterruptMode mode);
818 bool handleInterrupt();
819
hasPendingInterruptJSContext820 MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const {
821 static_assert(sizeof(interrupt_) == sizeof(uint32_t),
822 "Assumed by JIT callers");
823 return interrupt_;
824 }
825
826 private:
827 // Set when we're handling an interrupt of JIT/wasm code in
828 // InterruptRunningJitCode.
829 mozilla::Atomic<bool> handlingJitInterrupt_;
830
831 public:
startHandlingJitInterruptJSContext832 bool startHandlingJitInterrupt() {
833 // Return true if we changed handlingJitInterrupt_ from
834 // false to true.
835 return handlingJitInterrupt_.compareExchange(false, true);
836 }
finishHandlingJitInterruptJSContext837 void finishHandlingJitInterrupt() {
838 MOZ_ASSERT(handlingJitInterrupt_);
839 handlingJitInterrupt_ = false;
840 }
handlingJitInterruptJSContext841 bool handlingJitInterrupt() const { return handlingJitInterrupt_; }
842
843 /* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics
844 * object */
845 js::FutexThread fx;
846
847 // Buffer for OSR from baseline to Ion. To avoid holding on to this for
848 // too long, it's also freed in EnterBaseline (after returning from JIT code).
849 js::ThreadLocalData<uint8_t*> osrTempData_;
850
851 uint8_t* allocateOsrTempData(size_t size);
852 void freeOsrTempData();
853
854 // In certain cases, we want to optimize certain opcodes to typed
855 // instructions, to avoid carrying an extra register to feed into an unbox.
856 // Unfortunately, that's not always possible. For example, a GetPropertyCacheT
857 // could return a typed double, but if it takes its out-of-line path, it could
858 // return an object, and trigger invalidation. The invalidation bailout will
859 // consider the return value to be a double, and create a garbage Value.
860 //
861 // To allow the GetPropertyCacheT optimization, we allow the ability for
862 // GetPropertyCache to override the return value at the top of the stack - the
863 // value that will be temporarily corrupt. This special override value is set
864 // only in callVM() targets that are about to return *and* have invalidated
865 // their callee.
866 js::ThreadLocalData<js::Value> ionReturnOverride_;
867
hasIonReturnOverrideJSContext868 bool hasIonReturnOverride() const {
869 return !ionReturnOverride_.ref().isMagic(JS_ARG_POISON);
870 }
takeIonReturnOverrideJSContext871 js::Value takeIonReturnOverride() {
872 js::Value v = ionReturnOverride_;
873 ionReturnOverride_ = js::MagicValue(JS_ARG_POISON);
874 return v;
875 }
setIonReturnOverrideJSContext876 void setIonReturnOverride(const js::Value& v) {
877 MOZ_ASSERT(!hasIonReturnOverride());
878 MOZ_ASSERT(!v.isMagic());
879 ionReturnOverride_ = v;
880 }
881
882 mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
883
884 // Like jitStackLimit, but not reset to trigger interrupts.
885 js::ThreadLocalData<uintptr_t> jitStackLimitNoInterrupt;
886
887 // Promise callbacks.
888 js::ThreadLocalData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
889 js::ThreadLocalData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
890 js::ThreadLocalData<void*> enqueuePromiseJobCallbackData;
891
892 // Queue of pending jobs as described in ES2016 section 8.4.
893 // Only used if internal job queue handling was activated using
894 // `js::UseInternalJobQueues`.
895 js::ThreadLocalData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
896 js::ThreadLocalData<bool> drainingJobQueue;
897 js::ThreadLocalData<bool> stopDrainingJobQueue;
898
899 js::ThreadLocalData<JSPromiseRejectionTrackerCallback>
900 promiseRejectionTrackerCallback;
901 js::ThreadLocalData<void*> promiseRejectionTrackerCallbackData;
902
903 JSObject* getIncumbentGlobal(JSContext* cx);
904 bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
905 js::HandleObject promise,
906 js::HandleObject incumbentGlobal);
907 void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
908 void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
909 }; /* struct JSContext */
910
boolToResult(bool ok)911 inline JS::Result<> JSContext::boolToResult(bool ok) {
912 if (MOZ_LIKELY(ok)) {
913 MOZ_ASSERT(!isExceptionPending());
914 MOZ_ASSERT(!isPropagatingForcedReturn());
915 return JS::Ok();
916 }
917 return JS::Result<>(reportedError);
918 }
919
activeContextFromOwnThread()920 inline JSContext* JSRuntime::activeContextFromOwnThread() {
921 MOZ_ASSERT(activeContext() == js::TlsContext.get());
922 return activeContext();
923 }
924
925 namespace js {
926
927 struct MOZ_RAII AutoResolving {
928 public:
929 enum Kind { LOOKUP, WATCH };
930
931 AutoResolving(JSContext* cx, HandleObject obj, HandleId id,
932 Kind kind = LOOKUP MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
contextAutoResolving933 : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList) {
934 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
935 MOZ_ASSERT(obj);
936 cx->resolvingList = this;
937 }
938
~AutoResolvingAutoResolving939 ~AutoResolving() {
940 MOZ_ASSERT(context->resolvingList == this);
941 context->resolvingList = link;
942 }
943
alreadyStartedAutoResolving944 bool alreadyStarted() const { return link && alreadyStartedSlow(); }
945
946 private:
947 bool alreadyStartedSlow() const;
948
949 JSContext* const context;
950 HandleObject object;
951 HandleId id;
952 Kind const kind;
953 AutoResolving* const link;
954 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
955 };
956
957 /*
958 * Create and destroy functions for JSContext, which is manually allocated
959 * and exclusively owned.
960 */
961 extern JSContext* NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes,
962 JSRuntime* parentRuntime);
963
964 extern JSContext* NewCooperativeContext(JSContext* siblingContext);
965
966 extern void YieldCooperativeContext(JSContext* cx);
967
968 extern void ResumeCooperativeContext(JSContext* cx);
969
970 extern void DestroyContext(JSContext* cx);
971
972 enum ErrorArgumentsType {
973 ArgumentsAreUnicode,
974 ArgumentsAreASCII,
975 ArgumentsAreLatin1,
976 ArgumentsAreUTF8
977 };
978
979 /*
980 * Loads and returns a self-hosted function by name. For performance, define
981 * the property name in vm/CommonPropertyNames.h.
982 *
983 * Defined in SelfHosting.cpp.
984 */
985 JSFunction* SelfHostedFunction(JSContext* cx, HandlePropertyName propName);
986
987 /**
988 * Report an exception, using printf-style APIs to generate the error
989 * message.
990 */
991 #ifdef va_start
992 extern bool ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
993 ErrorArgumentsType argumentsType, va_list ap)
994 MOZ_FORMAT_PRINTF(3, 0);
995
996 extern bool ReportErrorNumberVA(JSContext* cx, unsigned flags,
997 JSErrorCallback callback, void* userRef,
998 const unsigned errorNumber,
999 ErrorArgumentsType argumentsType, va_list ap);
1000
1001 extern bool ReportErrorNumberUCArray(JSContext* cx, unsigned flags,
1002 JSErrorCallback callback, void* userRef,
1003 const unsigned errorNumber,
1004 const char16_t** args);
1005 #endif
1006
1007 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
1008 void* userRef, const unsigned errorNumber,
1009 const char16_t** messageArgs,
1010 ErrorArgumentsType argumentsType,
1011 JSErrorReport* reportp, va_list ap);
1012
1013 extern bool ExpandErrorArgumentsVA(JSContext* cx, JSErrorCallback callback,
1014 void* userRef, const unsigned errorNumber,
1015 const char16_t** messageArgs,
1016 ErrorArgumentsType argumentsType,
1017 JSErrorNotes::Note* notep, va_list ap);
1018
1019 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
1020 extern void ReportUsageErrorASCII(JSContext* cx, HandleObject callee,
1021 const char* msg);
1022
1023 /*
1024 * Prints a full report and returns true if the given report is non-nullptr
1025 * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings
1026 * is true.
1027 * Returns false otherwise.
1028 */
1029 extern bool PrintError(JSContext* cx, FILE* file,
1030 JS::ConstUTF8CharsZ toStringResult,
1031 JSErrorReport* report, bool reportWarnings);
1032
1033 extern bool ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
1034
1035 extern bool ReportIsNotDefined(JSContext* cx, HandleId id);
1036
1037 /*
1038 * Report an attempt to access the property of a null or undefined value (v).
1039 */
1040 extern bool ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v,
1041 HandleString fallback);
1042
1043 extern void ReportMissingArg(JSContext* cx, js::HandleValue v, unsigned arg);
1044
1045 /*
1046 * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
1047 * the first argument for the error message. If the error message has less
1048 * then 3 arguments, use null for arg1 or arg2.
1049 */
1050 extern bool ReportValueErrorFlags(JSContext* cx, unsigned flags,
1051 const unsigned errorNumber, int spindex,
1052 HandleValue v, HandleString fallback,
1053 const char* arg1, const char* arg2);
1054
1055 #define ReportValueError(cx, errorNumber, spindex, v, fallback) \
1056 ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, spindex, v, \
1057 fallback, nullptr, nullptr))
1058
1059 #define ReportValueError2(cx, errorNumber, spindex, v, fallback, arg1) \
1060 ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, spindex, v, \
1061 fallback, arg1, nullptr))
1062
1063 #define ReportValueError3(cx, errorNumber, spindex, v, fallback, arg1, arg2) \
1064 ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, spindex, v, \
1065 fallback, arg1, arg2))
1066
1067 JSObject* CreateErrorNotesArray(JSContext* cx, JSErrorReport* report);
1068
1069 } /* namespace js */
1070
1071 extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
1072
1073 namespace js {
1074
1075 /************************************************************************/
1076
1077 /* AutoArrayRooter roots an external array of Values. */
1078 class MOZ_RAII AutoArrayRooter : private JS::AutoGCRooter {
1079 public:
AutoArrayRooter(JSContext * cx,size_t len,Value * vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1080 AutoArrayRooter(JSContext* cx, size_t len,
1081 Value* vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1082 : JS::AutoGCRooter(cx, len), array(vec) {
1083 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1084 MOZ_ASSERT(tag_ >= 0);
1085 }
1086
changeLength(size_t newLength)1087 void changeLength(size_t newLength) {
1088 tag_ = ptrdiff_t(newLength);
1089 MOZ_ASSERT(tag_ >= 0);
1090 }
1091
changeArray(Value * newArray,size_t newLength)1092 void changeArray(Value* newArray, size_t newLength) {
1093 changeLength(newLength);
1094 array = newArray;
1095 }
1096
start()1097 Value* start() { return array; }
1098
length()1099 size_t length() {
1100 MOZ_ASSERT(tag_ >= 0);
1101 return size_t(tag_);
1102 }
1103
handleAt(size_t i)1104 MutableHandleValue handleAt(size_t i) {
1105 MOZ_ASSERT(i < size_t(tag_));
1106 return MutableHandleValue::fromMarkedLocation(&array[i]);
1107 }
handleAt(size_t i)1108 HandleValue handleAt(size_t i) const {
1109 MOZ_ASSERT(i < size_t(tag_));
1110 return HandleValue::fromMarkedLocation(&array[i]);
1111 }
1112 MutableHandleValue operator[](size_t i) {
1113 MOZ_ASSERT(i < size_t(tag_));
1114 return MutableHandleValue::fromMarkedLocation(&array[i]);
1115 }
1116 HandleValue operator[](size_t i) const {
1117 MOZ_ASSERT(i < size_t(tag_));
1118 return HandleValue::fromMarkedLocation(&array[i]);
1119 }
1120
1121 friend void JS::AutoGCRooter::trace(JSTracer* trc);
1122
1123 private:
1124 Value* array;
1125 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1126 };
1127
1128 class AutoAssertNoException {
1129 #ifdef DEBUG
1130 JSContext* cx;
1131 bool hadException;
1132 #endif
1133
1134 public:
AutoAssertNoException(JSContext * cx)1135 explicit AutoAssertNoException(JSContext* cx)
1136 #ifdef DEBUG
1137 : cx(cx),
1138 hadException(cx->isExceptionPending())
1139 #endif
1140 {
1141 }
1142
~AutoAssertNoException()1143 ~AutoAssertNoException() {
1144 MOZ_ASSERT_IF(!hadException, !cx->isExceptionPending());
1145 }
1146 };
1147
1148 class MOZ_RAII AutoLockForExclusiveAccess {
1149 JSRuntime* runtime;
1150
init(JSRuntime * rt)1151 void init(JSRuntime* rt) {
1152 runtime = rt;
1153 if (runtime->hasHelperThreadZones()) {
1154 runtime->exclusiveAccessLock.lock();
1155 } else {
1156 MOZ_ASSERT(!runtime->activeThreadHasExclusiveAccess);
1157 #ifdef DEBUG
1158 runtime->activeThreadHasExclusiveAccess = true;
1159 #endif
1160 }
1161 }
1162
1163 public:
AutoLockForExclusiveAccess(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1164 explicit AutoLockForExclusiveAccess(
1165 JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1166 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1167 init(cx->runtime());
1168 }
AutoLockForExclusiveAccess(JSRuntime * rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1169 explicit AutoLockForExclusiveAccess(
1170 JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1171 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1172 init(rt);
1173 }
~AutoLockForExclusiveAccess()1174 ~AutoLockForExclusiveAccess() {
1175 if (runtime->hasHelperThreadZones()) {
1176 runtime->exclusiveAccessLock.unlock();
1177 } else {
1178 MOZ_ASSERT(runtime->activeThreadHasExclusiveAccess);
1179 #ifdef DEBUG
1180 runtime->activeThreadHasExclusiveAccess = false;
1181 #endif
1182 }
1183 }
1184
1185 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1186 };
1187
1188 class MOZ_RAII AutoLockScriptData {
1189 JSRuntime* runtime;
1190
1191 public:
AutoLockScriptData(JSRuntime * rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1192 explicit AutoLockScriptData(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1193 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1194 runtime = rt;
1195 if (runtime->hasHelperThreadZones()) {
1196 runtime->scriptDataLock.lock();
1197 } else {
1198 MOZ_ASSERT(!runtime->activeThreadHasScriptDataAccess);
1199 #ifdef DEBUG
1200 runtime->activeThreadHasScriptDataAccess = true;
1201 #endif
1202 }
1203 }
~AutoLockScriptData()1204 ~AutoLockScriptData() {
1205 if (runtime->hasHelperThreadZones()) {
1206 runtime->scriptDataLock.unlock();
1207 } else {
1208 MOZ_ASSERT(runtime->activeThreadHasScriptDataAccess);
1209 #ifdef DEBUG
1210 runtime->activeThreadHasScriptDataAccess = false;
1211 #endif
1212 }
1213 }
1214
1215 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1216 };
1217
1218 class MOZ_RAII AutoKeepAtoms {
1219 JSContext* cx;
1220 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1221
1222 public:
AutoKeepAtoms(JSContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1223 explicit AutoKeepAtoms(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1224 : cx(cx) {
1225 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1226 cx->keepAtoms++;
1227 }
~AutoKeepAtoms()1228 ~AutoKeepAtoms() {
1229 MOZ_ASSERT(cx->keepAtoms);
1230 cx->keepAtoms--;
1231
1232 JSRuntime* rt = cx->runtime();
1233 if (!cx->helperThread()) {
1234 if (rt->gc.fullGCForAtomsRequested() && cx->canCollectAtoms())
1235 rt->gc.triggerFullGCForAtoms(cx);
1236 }
1237 }
1238 };
1239
1240 // Debugging RAII class which marks the current thread as performing an Ion
1241 // compilation, for use by CurrentThreadCan{Read,Write}CompilationData
1242 class MOZ_RAII AutoEnterIonCompilation {
1243 public:
AutoEnterIonCompilation(bool safeForMinorGC MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1244 explicit AutoEnterIonCompilation(
1245 bool safeForMinorGC MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1246 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1247
1248 #ifdef DEBUG
1249 JSContext* cx = TlsContext.get();
1250 MOZ_ASSERT(!cx->ionCompiling);
1251 MOZ_ASSERT(!cx->ionCompilingSafeForMinorGC);
1252 cx->ionCompiling = true;
1253 cx->ionCompilingSafeForMinorGC = safeForMinorGC;
1254 #endif
1255 }
1256
~AutoEnterIonCompilation()1257 ~AutoEnterIonCompilation() {
1258 #ifdef DEBUG
1259 JSContext* cx = TlsContext.get();
1260 MOZ_ASSERT(cx->ionCompiling);
1261 cx->ionCompiling = false;
1262 cx->ionCompilingSafeForMinorGC = false;
1263 #endif
1264 }
1265
1266 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1267 };
1268
1269 // Should be used in functions called directly from JIT code (with
1270 // masm.callWithABI) to assert invariants in debug builds.
1271 class MOZ_RAII AutoUnsafeCallWithABI {
1272 #ifdef DEBUG
1273 JSContext* cx_;
1274 bool nested_;
1275 #endif
1276 JS::AutoCheckCannotGC nogc;
1277
1278 public:
1279 #ifdef DEBUG
1280 AutoUnsafeCallWithABI();
1281 ~AutoUnsafeCallWithABI();
1282 #endif
1283 };
1284
1285 namespace gc {
1286
1287 // In debug builds, set/unset the performing GC flag for the current thread.
1288 struct MOZ_RAII AutoSetThreadIsPerformingGC {
1289 #ifdef DEBUG
AutoSetThreadIsPerformingGCAutoSetThreadIsPerformingGC1290 AutoSetThreadIsPerformingGC() : cx(TlsContext.get()) {
1291 MOZ_ASSERT(!cx->performingGC);
1292 cx->performingGC = true;
1293 }
1294
~AutoSetThreadIsPerformingGCAutoSetThreadIsPerformingGC1295 ~AutoSetThreadIsPerformingGC() {
1296 MOZ_ASSERT(cx->performingGC);
1297 cx->performingGC = false;
1298 }
1299
1300 private:
1301 JSContext* cx;
1302 #else
1303 AutoSetThreadIsPerformingGC() {}
1304 #endif
1305 };
1306
1307 // In debug builds, set/unset the GC sweeping flag for the current thread.
1308 struct MOZ_RAII AutoSetThreadIsSweeping {
1309 #ifdef DEBUG
AutoSetThreadIsSweepingAutoSetThreadIsSweeping1310 AutoSetThreadIsSweeping() : cx(TlsContext.get()) {
1311 MOZ_ASSERT(!cx->gcSweeping);
1312 cx->gcSweeping = true;
1313 }
1314
~AutoSetThreadIsSweepingAutoSetThreadIsSweeping1315 ~AutoSetThreadIsSweeping() {
1316 MOZ_ASSERT(cx->gcSweeping);
1317 cx->gcSweeping = false;
1318 }
1319
1320 private:
1321 JSContext* cx;
1322 #else
1323 AutoSetThreadIsSweeping() {}
1324 #endif
1325 };
1326
1327 } // namespace gc
1328
1329 } /* namespace js */
1330
1331 #ifdef _MSC_VER
1332 #pragma warning(pop)
1333 #endif
1334
1335 #endif /* vm_JSContext_h */
1336