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