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