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/TraceableVector.h"
15 #include "js/Utility.h"
16 #include "js/Vector.h"
17 #include "vm/Runtime.h"
18
19 #ifdef _MSC_VER
20 #pragma warning(push)
21 #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
22 #endif
23
24 struct DtoaState;
25
26 namespace js {
27
28 namespace jit {
29 class JitContext;
30 class DebugModeOSRVolatileJitFrameIterator;
31 } // namespace jit
32
33 typedef HashSet<Shape*> ShapeSet;
34
35 /* Detects cycles when traversing an object graph. */
36 class MOZ_RAII AutoCycleDetector
37 {
38 public:
39 using Set = HashSet<JSObject*, MovableCellHasher<JSObject*>>;
40
AutoCycleDetector(JSContext * cx,HandleObject objArg MOZ_GUARD_OBJECT_NOTIFIER_PARAM)41 AutoCycleDetector(JSContext* cx, HandleObject objArg
42 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
43 : cx(cx), obj(cx, objArg), cyclic(true)
44 {
45 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
46 }
47
48 ~AutoCycleDetector();
49
50 bool init();
51
foundCycle()52 bool foundCycle() { return cyclic; }
53
54 private:
55 Generation hashsetGenerationAtInit;
56 JSContext* cx;
57 RootedObject obj;
58 Set::AddPtr hashsetAddPointer;
59 bool cyclic;
60 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
61 };
62
63 /* Updates references in the cycle detection set if the GC moves them. */
64 extern void
65 TraceCycleDetectionSet(JSTracer* trc, AutoCycleDetector::Set& set);
66
67 struct AutoResolving;
68
69 namespace frontend { struct CompileError; }
70
71 /*
72 * Execution Context Overview:
73 *
74 * Several different structures may be used to provide a context for operations
75 * on the VM. Each context is thread local, but varies in what data it can
76 * access and what other threads may be running.
77 *
78 * - ExclusiveContext is used by threads operating in one compartment/zone,
79 * where other threads may operate in other compartments, but *not* the same
80 * compartment or zone which the ExclusiveContext is in. A thread with an
81 * ExclusiveContext may enter the atoms compartment and atomize strings, in
82 * which case a lock is used.
83 *
84 * - JSContext is used only by the runtime's main thread. The context may
85 * operate in any compartment or zone which is not used by an ExclusiveContext,
86 * and will only run in parallel with threads using such contexts.
87 *
88 * A JSContext coerces to an ExclusiveContext.
89 */
90
91 struct HelperThread;
92
93 class ExclusiveContext : public ContextFriendFields,
94 public MallocProvider<ExclusiveContext>
95 {
96 friend class gc::ArenaLists;
97 friend class AutoCompartment;
98 friend class AutoLockForExclusiveAccess;
99 friend struct StackBaseShape;
100 friend void JSScript::initCompartment(ExclusiveContext* cx);
101 friend class jit::JitContext;
102 friend class Activation;
103
104 // The thread on which this context is running, if this is not a JSContext.
105 HelperThread* helperThread_;
106
107 public:
108 enum ContextKind {
109 Context_JS,
110 Context_Exclusive
111 };
112
113 private:
114 ContextKind contextKind_;
115
116 public:
117 PerThreadData* perThreadData;
118
119 ExclusiveContext(JSRuntime* rt, PerThreadData* pt, ContextKind kind);
120
isJSContext()121 bool isJSContext() const {
122 return contextKind_ == Context_JS;
123 }
124
maybeJSContext()125 JSContext* maybeJSContext() const {
126 if (isJSContext())
127 return (JSContext*) this;
128 return nullptr;
129 }
130
asJSContext()131 JSContext* asJSContext() const {
132 // Note: there is no way to perform an unchecked coercion from a
133 // ThreadSafeContext to a JSContext. This ensures that trying to use
134 // the context as a JSContext off the main thread will nullptr crash
135 // rather than race.
136 MOZ_ASSERT(isJSContext());
137 return maybeJSContext();
138 }
139
140 // In some cases we could potentially want to do operations that require a
141 // JSContext while running off the main thread. While this should never
142 // actually happen, the wide enough API for working off the main thread
143 // makes such operations impossible to rule out. Rather than blindly using
144 // asJSContext() and crashing afterwards, this method may be used to watch
145 // for such cases and produce either a soft failure in release builds or
146 // an assertion failure in debug builds.
shouldBeJSContext()147 bool shouldBeJSContext() const {
148 MOZ_ASSERT(isJSContext());
149 return isJSContext();
150 }
151
runtimeMatches(JSRuntime * rt)152 bool runtimeMatches(JSRuntime* rt) const {
153 return runtime_ == rt;
154 }
155
156 protected:
157 js::gc::ArenaLists* arenas_;
158
159 public:
arenas()160 inline js::gc::ArenaLists* arenas() const { return arenas_; }
161
162 template <typename T>
isInsideCurrentZone(T thing)163 bool isInsideCurrentZone(T thing) const {
164 return thing->zoneFromAnyThread() == zone_;
165 }
166
167 template <typename T>
isInsideCurrentCompartment(T thing)168 inline bool isInsideCurrentCompartment(T thing) const {
169 return thing->compartment() == compartment_;
170 }
171
172 void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
173 if (!isJSContext())
174 return nullptr;
175 return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, asJSContext());
176 }
177
178 /* Clear the pending exception (if any) due to OOM. */
179 void recoverFromOutOfMemory();
180
updateMallocCounter(size_t nbytes)181 inline void updateMallocCounter(size_t nbytes) {
182 // Note: this is racy.
183 runtime_->updateMallocCounter(zone_, nbytes);
184 }
185
reportAllocationOverflow()186 void reportAllocationOverflow() {
187 js::ReportAllocationOverflow(this);
188 }
189
190 // Accessors for immutable runtime data.
names()191 JSAtomState& names() { return *runtime_->commonNames; }
staticStrings()192 StaticStrings& staticStrings() { return *runtime_->staticStrings; }
isPermanentAtomsInitialized()193 bool isPermanentAtomsInitialized() { return !!runtime_->permanentAtoms; }
permanentAtoms()194 FrozenAtomSet& permanentAtoms() { return *runtime_->permanentAtoms; }
wellKnownSymbols()195 WellKnownSymbols& wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
asmJSCacheOps()196 const JS::AsmJSCacheOps& asmJSCacheOps() { return runtime_->asmJSCacheOps; }
emptyString()197 PropertyName* emptyString() { return runtime_->emptyString; }
defaultFreeOp()198 FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
runtimeAddressForJit()199 void* runtimeAddressForJit() { return runtime_; }
runtimeAddressOfInterruptUint32()200 void* runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); }
stackLimitAddress(StackKind kind)201 void* stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
202 void* stackLimitAddressForJitCode(StackKind kind);
stackLimit(StackKind kind)203 uintptr_t stackLimit(StackKind kind) { return runtime_->mainThread.nativeStackLimit[kind]; }
gcSystemPageSize()204 size_t gcSystemPageSize() { return gc::SystemPageSize(); }
canUseSignalHandlers()205 bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); }
jitSupportsFloatingPoint()206 bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
jitSupportsSimd()207 bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }
lcovEnabled()208 bool lcovEnabled() const { return runtime_->lcovOutput.isEnabled(); }
209
210 // Thread local data that may be accessed freely.
dtoaState()211 DtoaState* dtoaState() {
212 return perThreadData->dtoaState;
213 }
214
215 /*
216 * "Entering" a compartment changes cx->compartment (which changes
217 * cx->global). Note that this does not push any InterpreterFrame which means
218 * that it is possible for cx->fp()->compartment() != cx->compartment.
219 * This is not a problem since, in general, most places in the VM cannot
220 * know that they were called from script (e.g., they may have been called
221 * through the JSAPI via JS_CallFunction) and thus cannot expect fp.
222 *
223 * Compartments should be entered/left in a LIFO fasion. The depth of this
224 * enter/leave stack is maintained by enterCompartmentDepth_ and queried by
225 * hasEnteredCompartment.
226 *
227 * To enter a compartment, code should prefer using AutoCompartment over
228 * manually calling cx->enterCompartment/leaveCompartment.
229 */
230 protected:
231 unsigned enterCompartmentDepth_;
232 inline void setCompartment(JSCompartment* comp);
233 public:
hasEnteredCompartment()234 bool hasEnteredCompartment() const {
235 return enterCompartmentDepth_ > 0;
236 }
237 #ifdef DEBUG
getEnterCompartmentDepth()238 unsigned getEnterCompartmentDepth() const {
239 return enterCompartmentDepth_;
240 }
241 #endif
242
243 inline void enterCompartment(JSCompartment* c);
244 inline void enterNullCompartment();
245 inline void leaveCompartment(JSCompartment* oldCompartment);
246
247 void setHelperThread(HelperThread* helperThread);
helperThread()248 HelperThread* helperThread() const { return helperThread_; }
249
250 // Threads with an ExclusiveContext may freely access any data in their
251 // compartment and zone.
compartment()252 JSCompartment* compartment() const {
253 MOZ_ASSERT_IF(runtime_->isAtomsCompartment(compartment_),
254 runtime_->currentThreadHasExclusiveAccess());
255 return compartment_;
256 }
zone()257 JS::Zone* zone() const {
258 MOZ_ASSERT_IF(!compartment(), !zone_);
259 MOZ_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_);
260 return zone_;
261 }
262
263 // Zone local methods that can be used freely from an ExclusiveContext.
264 inline js::LifoAlloc& typeLifoAlloc();
265
266 // Current global. This is only safe to use within the scope of the
267 // AutoCompartment from which it's called.
268 inline js::Handle<js::GlobalObject*> global() const;
269
270 // Methods to access runtime data that must be protected by locks.
parseMapPool()271 frontend::ParseMapPool& parseMapPool() {
272 return runtime_->parseMapPool();
273 }
atoms()274 AtomSet& atoms() {
275 return runtime_->atoms();
276 }
atomsCompartment()277 JSCompartment* atomsCompartment() {
278 return runtime_->atomsCompartment();
279 }
symbolRegistry()280 SymbolRegistry& symbolRegistry() {
281 return runtime_->symbolRegistry();
282 }
scriptDataTable()283 ScriptDataTable& scriptDataTable() {
284 return runtime_->scriptDataTable();
285 }
286
287 // Methods specific to any HelperThread for the context.
288 frontend::CompileError& addPendingCompileError();
289 void addPendingOverRecursed();
290 };
291
292 } /* namespace js */
293
294 struct JSContext : public js::ExclusiveContext,
295 public mozilla::LinkedListElement<JSContext>
296 {
297 explicit JSContext(JSRuntime* rt);
298 ~JSContext();
299
runtimeJSContext300 JSRuntime* runtime() const { return runtime_; }
mainThreadJSContext301 js::PerThreadData& mainThread() const { return runtime()->mainThread; }
302
offsetOfRuntimeJSContext303 static size_t offsetOfRuntime() {
304 return offsetof(JSContext, runtime_);
305 }
offsetOfCompartmentJSContext306 static size_t offsetOfCompartment() {
307 return offsetof(JSContext, compartment_);
308 }
309
310 friend class js::ExclusiveContext;
311 friend class JS::AutoSaveExceptionState;
312 friend class js::jit::DebugModeOSRVolatileJitFrameIterator;
313 friend void js::ReportOverRecursed(JSContext*);
314
315 private:
316 /* Exception state -- the exception member is a GC root by definition. */
317 bool throwing; /* is there a pending exception? */
318 JS::PersistentRooted<JS::Value> unwrappedException_; /* most-recently-thrown exception */
319
320 /* Per-context options. */
321 JS::ContextOptions options_;
322
323 // True if the exception currently being thrown is by result of
324 // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
325 bool overRecursed_;
326
327 // True if propagating a forced return from an interrupt handler during
328 // debug mode.
329 bool propagatingForcedReturn_;
330
331 // A stack of live iterators that need to be updated in case of debug mode
332 // OSR.
333 js::jit::DebugModeOSRVolatileJitFrameIterator* liveVolatileJitFrameIterators_;
334
335 public:
336 int32_t reportGranularity; /* see vm/Probes.h */
337
338 js::AutoResolving* resolvingList;
339
340 /* True if generating an error, to prevent runaway recursion. */
341 bool generatingError;
342
343 /* See JS_SaveFrameChain/JS_RestoreFrameChain. */
344 private:
345 struct SavedFrameChain {
SavedFrameChainJSContext::SavedFrameChain346 SavedFrameChain(JSCompartment* comp, unsigned count)
347 : compartment(comp), enterCompartmentCount(count) {}
348 JSCompartment* compartment;
349 unsigned enterCompartmentCount;
350 };
351 typedef js::Vector<SavedFrameChain, 1, js::SystemAllocPolicy> SaveStack;
352 SaveStack savedFrameChains_;
353 public:
354 bool saveFrameChain();
355 void restoreFrameChain();
356
357 public:
358 /* State for object and array toSource conversion. */
359 js::AutoCycleDetector::Set cycleDetectorSet;
360
361 /* Client opaque pointers. */
362 void* data;
363 void* data2;
364
365 public:
366
367 /*
368 * Return:
369 * - The newest scripted frame's version, if there is such a frame.
370 * - The version from the compartment.
371 * - The default version.
372 *
373 * Note: if this ever shows up in a profile, just add caching!
374 */
375 JSVersion findVersion() const;
376
optionsJSContext377 const JS::ContextOptions& options() const {
378 return options_;
379 }
380
optionsJSContext381 JS::ContextOptions& options() {
382 return options_;
383 }
384
tempLifoAllocJSContext385 js::LifoAlloc& tempLifoAlloc() { return runtime()->tempLifoAlloc; }
386
387 unsigned outstandingRequests;/* number of JS_BeginRequest calls
388 without the corresponding
389 JS_EndRequest. */
390
391 bool jitIsBroken;
392
393 void updateJITEnabled();
394
395 /* Whether this context has JS frames on the stack. */
396 bool currentlyRunning() const;
397
currentlyRunningInInterpreterJSContext398 bool currentlyRunningInInterpreter() const {
399 return runtime_->activation()->isInterpreter();
400 }
currentlyRunningInJitJSContext401 bool currentlyRunningInJit() const {
402 return runtime_->activation()->isJit();
403 }
interpreterFrameJSContext404 js::InterpreterFrame* interpreterFrame() const {
405 return runtime_->activation()->asInterpreter()->current();
406 }
interpreterRegsJSContext407 js::InterpreterRegs& interpreterRegs() const {
408 return runtime_->activation()->asInterpreter()->regs();
409 }
410
411 /*
412 * Get the topmost script and optional pc on the stack. By default, this
413 * function only returns a JSScript in the current compartment, returning
414 * nullptr if the current script is in a different compartment. This
415 * behavior can be overridden by passing ALLOW_CROSS_COMPARTMENT.
416 */
417 enum MaybeAllowCrossCompartment {
418 DONT_ALLOW_CROSS_COMPARTMENT = false,
419 ALLOW_CROSS_COMPARTMENT = true
420 };
421 inline JSScript* currentScript(jsbytecode** pc = nullptr,
422 MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
423
424 // The generational GC nursery may only be used on the main thread.
nurseryJSContext425 inline js::Nursery& nursery() {
426 return runtime_->gc.nursery;
427 }
428
minorGCJSContext429 void minorGC(JS::gcreason::Reason reason) {
430 runtime_->gc.minorGC(this, reason);
431 }
432
433 public:
isExceptionPendingJSContext434 bool isExceptionPending() {
435 return throwing;
436 }
437
438 MOZ_WARN_UNUSED_RESULT
439 bool getPendingException(JS::MutableHandleValue rval);
440
441 bool isThrowingOutOfMemory();
442 bool isClosingGenerator();
443
444 void setPendingException(js::Value v);
445
clearPendingExceptionJSContext446 void clearPendingException() {
447 throwing = false;
448 overRecursed_ = false;
449 unwrappedException_.setUndefined();
450 }
451
isThrowingOverRecursedJSContext452 bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
isPropagatingForcedReturnJSContext453 bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
setPropagatingForcedReturnJSContext454 void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
clearPropagatingForcedReturnJSContext455 void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
456
457 /*
458 * See JS_SetTrustedPrincipals in jsapi.h.
459 * Note: !cx->compartment is treated as trusted.
460 */
461 inline bool runningWithTrustedPrincipals() const;
462
463 JS_FRIEND_API(size_t) sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
464
465 void mark(JSTracer* trc);
466
467 private:
468 /*
469 * The allocation code calls the function to indicate either OOM failure
470 * when p is null or that a memory pressure counter has reached some
471 * threshold when p is not null. The function takes the pointer and not
472 * a boolean flag to minimize the amount of code in its inlined callers.
473 */
474 JS_FRIEND_API(void) checkMallocGCPressure(void* p);
475 }; /* struct JSContext */
476
477 namespace js {
478
479 struct MOZ_RAII AutoResolving {
480 public:
481 enum Kind {
482 LOOKUP,
483 WATCH
484 };
485
486 AutoResolving(JSContext* cx, HandleObject obj, HandleId id, Kind kind = LOOKUP
487 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
contextAutoResolving488 : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList)
489 {
490 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
491 MOZ_ASSERT(obj);
492 cx->resolvingList = this;
493 }
494
~AutoResolvingAutoResolving495 ~AutoResolving() {
496 MOZ_ASSERT(context->resolvingList == this);
497 context->resolvingList = link;
498 }
499
alreadyStartedAutoResolving500 bool alreadyStarted() const {
501 return link && alreadyStartedSlow();
502 }
503
504 private:
505 bool alreadyStartedSlow() const;
506
507 JSContext* const context;
508 HandleObject object;
509 HandleId id;
510 Kind const kind;
511 AutoResolving* const link;
512 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
513 };
514
515 /*
516 * Enumerate all contexts in a runtime.
517 */
518 class ContextIter
519 {
520 JSContext* iter;
521
522 public:
ContextIter(JSRuntime * rt)523 explicit ContextIter(JSRuntime* rt) {
524 iter = rt->contextList.getFirst();
525 }
526
done()527 bool done() const {
528 return !iter;
529 }
530
next()531 void next() {
532 MOZ_ASSERT(!done());
533 iter = iter->getNext();
534 }
535
get()536 JSContext* get() const {
537 MOZ_ASSERT(!done());
538 return iter;
539 }
540
541 operator JSContext*() const {
542 return get();
543 }
544
545 JSContext* operator ->() const {
546 return get();
547 }
548 };
549
550 /*
551 * Create and destroy functions for JSContext, which is manually allocated
552 * and exclusively owned.
553 */
554 extern JSContext*
555 NewContext(JSRuntime* rt, size_t stackChunkSize);
556
557 enum DestroyContextMode {
558 DCM_NO_GC,
559 DCM_FORCE_GC,
560 DCM_NEW_FAILED
561 };
562
563 extern void
564 DestroyContext(JSContext* cx, DestroyContextMode mode);
565
566 enum ErrorArgumentsType {
567 ArgumentsAreUnicode,
568 ArgumentsAreASCII
569 };
570
571 /*
572 * Loads and returns a self-hosted function by name. For performance, define
573 * the property name in vm/CommonPropertyNames.h.
574 *
575 * Defined in SelfHosting.cpp.
576 */
577 JSFunction*
578 SelfHostedFunction(JSContext* cx, HandlePropertyName propName);
579
580 #ifdef va_start
581 extern bool
582 ReportErrorVA(JSContext* cx, unsigned flags, const char* format, va_list ap);
583
584 extern bool
585 ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback,
586 void* userRef, const unsigned errorNumber,
587 ErrorArgumentsType argumentsType, va_list ap);
588
589 extern bool
590 ReportErrorNumberUCArray(JSContext* cx, unsigned flags, JSErrorCallback callback,
591 void* userRef, const unsigned errorNumber,
592 const char16_t** args);
593 #endif
594
595 extern bool
596 ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
597 void* userRef, const unsigned errorNumber,
598 char** message, JSErrorReport* reportp,
599 ErrorArgumentsType argumentsType, va_list ap);
600
601 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
602 extern void
603 ReportUsageError(JSContext* cx, HandleObject callee, const char* msg);
604
605 /*
606 * Prints a full report and returns true if the given report is non-nullptr
607 * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings
608 * is true.
609 * Returns false otherwise, printing just the message if the report is nullptr.
610 */
611 extern bool
612 PrintError(JSContext* cx, FILE* file, const char* message, JSErrorReport* report,
613 bool reportWarnings);
614
615 /*
616 * Send a JSErrorReport to the errorReporter callback.
617 */
618 void
619 CallErrorReporter(JSContext* cx, const char* message, JSErrorReport* report);
620
621 extern bool
622 ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
623
624 extern bool
625 ReportIsNotDefined(JSContext* cx, HandleId id);
626
627 /*
628 * Report an attempt to access the property of a null or undefined value (v).
629 */
630 extern bool
631 ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v, HandleString fallback);
632
633 extern void
634 ReportMissingArg(JSContext* cx, js::HandleValue v, unsigned arg);
635
636 /*
637 * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
638 * the first argument for the error message. If the error message has less
639 * then 3 arguments, use null for arg1 or arg2.
640 */
641 extern bool
642 ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNumber,
643 int spindex, HandleValue v, HandleString fallback,
644 const char* arg1, const char* arg2);
645
646 #define ReportValueError(cx,errorNumber,spindex,v,fallback) \
647 ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
648 spindex, v, fallback, nullptr, nullptr))
649
650 #define ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1) \
651 ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
652 spindex, v, fallback, arg1, nullptr))
653
654 #define ReportValueError3(cx,errorNumber,spindex,v,fallback,arg1,arg2) \
655 ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
656 spindex, v, fallback, arg1, arg2))
657
658 } /* namespace js */
659
660 extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
661
662 namespace js {
663
664 MOZ_ALWAYS_INLINE bool
CheckForInterrupt(JSContext * cx)665 CheckForInterrupt(JSContext* cx)
666 {
667 // Add an inline fast-path since we have to check for interrupts in some hot
668 // C++ loops of library builtins.
669 JSRuntime* rt = cx->runtime();
670 if (MOZ_UNLIKELY(rt->hasPendingInterrupt()))
671 return rt->handleInterrupt(cx);
672 return true;
673 }
674
675 /************************************************************************/
676
677 typedef JS::AutoVectorRooter<PropertyName*> AutoPropertyNameVector;
678
679 using ShapeVector = js::TraceableVector<Shape*>;
680 using StringVector = js::TraceableVector<JSString*>;
681
682 /* AutoArrayRooter roots an external array of Values. */
683 class MOZ_RAII AutoArrayRooter : private JS::AutoGCRooter
684 {
685 public:
AutoArrayRooter(JSContext * cx,size_t len,Value * vec MOZ_GUARD_OBJECT_NOTIFIER_PARAM)686 AutoArrayRooter(JSContext* cx, size_t len, Value* vec
687 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
688 : JS::AutoGCRooter(cx, len), array(vec)
689 {
690 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
691 MOZ_ASSERT(tag_ >= 0);
692 }
693
changeLength(size_t newLength)694 void changeLength(size_t newLength) {
695 tag_ = ptrdiff_t(newLength);
696 MOZ_ASSERT(tag_ >= 0);
697 }
698
changeArray(Value * newArray,size_t newLength)699 void changeArray(Value* newArray, size_t newLength) {
700 changeLength(newLength);
701 array = newArray;
702 }
703
start()704 Value* start() {
705 return array;
706 }
707
length()708 size_t length() {
709 MOZ_ASSERT(tag_ >= 0);
710 return size_t(tag_);
711 }
712
handleAt(size_t i)713 MutableHandleValue handleAt(size_t i) {
714 MOZ_ASSERT(i < size_t(tag_));
715 return MutableHandleValue::fromMarkedLocation(&array[i]);
716 }
handleAt(size_t i)717 HandleValue handleAt(size_t i) const {
718 MOZ_ASSERT(i < size_t(tag_));
719 return HandleValue::fromMarkedLocation(&array[i]);
720 }
721 MutableHandleValue operator[](size_t i) {
722 MOZ_ASSERT(i < size_t(tag_));
723 return MutableHandleValue::fromMarkedLocation(&array[i]);
724 }
725 HandleValue operator[](size_t i) const {
726 MOZ_ASSERT(i < size_t(tag_));
727 return HandleValue::fromMarkedLocation(&array[i]);
728 }
729
730 friend void JS::AutoGCRooter::trace(JSTracer* trc);
731
732 private:
733 Value* array;
734 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
735 };
736
737 class AutoAssertNoException
738 {
739 #ifdef DEBUG
740 JSContext* cx;
741 bool hadException;
742 #endif
743
744 public:
AutoAssertNoException(JSContext * cx)745 explicit AutoAssertNoException(JSContext* cx)
746 #ifdef DEBUG
747 : cx(cx),
748 hadException(cx->isExceptionPending())
749 #endif
750 {
751 }
752
~AutoAssertNoException()753 ~AutoAssertNoException()
754 {
755 MOZ_ASSERT_IF(!hadException, !cx->isExceptionPending());
756 }
757 };
758
759 /* Exposed intrinsics for the JITs. */
760 bool intrinsic_IsSuspendedStarGenerator(JSContext* cx, unsigned argc, Value* vp);
761
762 class MOZ_RAII AutoLockForExclusiveAccess
763 {
764 JSRuntime* runtime;
765
init(JSRuntime * rt)766 void init(JSRuntime* rt) {
767 runtime = rt;
768 if (runtime->numExclusiveThreads) {
769 runtime->assertCanLock(ExclusiveAccessLock);
770 PR_Lock(runtime->exclusiveAccessLock);
771 #ifdef DEBUG
772 runtime->exclusiveAccessOwner = PR_GetCurrentThread();
773 #endif
774 } else {
775 MOZ_ASSERT(!runtime->mainThreadHasExclusiveAccess);
776 runtime->mainThreadHasExclusiveAccess = true;
777 }
778 }
779
780 public:
AutoLockForExclusiveAccess(ExclusiveContext * cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)781 explicit AutoLockForExclusiveAccess(ExclusiveContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
782 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
783 init(cx->runtime_);
784 }
AutoLockForExclusiveAccess(JSRuntime * rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)785 explicit AutoLockForExclusiveAccess(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
786 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
787 init(rt);
788 }
~AutoLockForExclusiveAccess()789 ~AutoLockForExclusiveAccess() {
790 if (runtime->numExclusiveThreads) {
791 MOZ_ASSERT(runtime->exclusiveAccessOwner == PR_GetCurrentThread());
792 runtime->exclusiveAccessOwner = nullptr;
793 PR_Unlock(runtime->exclusiveAccessLock);
794 } else {
795 MOZ_ASSERT(runtime->mainThreadHasExclusiveAccess);
796 runtime->mainThreadHasExclusiveAccess = false;
797 }
798 }
799
800 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
801 };
802
803 } /* namespace js */
804
805 #ifdef _MSC_VER
806 #pragma warning(pop)
807 #endif
808
809 #endif /* jscntxt_h */
810