summaryrefslogtreecommitdiff
path: root/js/src/jscntxt.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/src/jscntxt.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloaduxp-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/src/jscntxt.h')
-rw-r--r--js/src/jscntxt.h856
1 files changed, 856 insertions, 0 deletions
diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h
new file mode 100644
index 0000000000..0a28412425
--- /dev/null
+++ b/js/src/jscntxt.h
@@ -0,0 +1,856 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* JS execution context. */
+
+#ifndef jscntxt_h
+#define jscntxt_h
+
+#include "mozilla/MemoryReporting.h"
+
+#include "js/CharacterEncoding.h"
+#include "js/GCVector.h"
+#include "js/Utility.h"
+#include "js/Vector.h"
+#include "vm/Caches.h"
+#include "vm/Runtime.h"
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
+#endif
+
+struct DtoaState;
+
+namespace js {
+
+namespace jit {
+class JitContext;
+class DebugModeOSRVolatileJitFrameIterator;
+} // namespace jit
+
+typedef HashSet<Shape*> ShapeSet;
+
+/* Detects cycles when traversing an object graph. */
+class MOZ_RAII AutoCycleDetector
+{
+ public:
+ using Set = HashSet<JSObject*, MovableCellHasher<JSObject*>, SystemAllocPolicy>;
+
+ AutoCycleDetector(JSContext* cx, HandleObject objArg
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : cx(cx), obj(cx, objArg), cyclic(true)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ }
+
+ ~AutoCycleDetector();
+
+ bool init();
+
+ bool foundCycle() { return cyclic; }
+
+ private:
+ Generation hashsetGenerationAtInit;
+ JSContext* cx;
+ RootedObject obj;
+ Set::AddPtr hashsetAddPointer;
+ bool cyclic;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/* Updates references in the cycle detection set if the GC moves them. */
+extern void
+TraceCycleDetectionSet(JSTracer* trc, AutoCycleDetector::Set& set);
+
+struct AutoResolving;
+
+namespace frontend { class CompileError; }
+
+/*
+ * Execution Context Overview:
+ *
+ * Several different structures may be used to provide a context for operations
+ * on the VM. Each context is thread local, but varies in what data it can
+ * access and what other threads may be running.
+ *
+ * - ExclusiveContext is used by threads operating in one compartment/zone,
+ * where other threads may operate in other compartments, but *not* the same
+ * compartment or zone which the ExclusiveContext is in. A thread with an
+ * ExclusiveContext may enter the atoms compartment and atomize strings, in
+ * which case a lock is used.
+ *
+ * - JSContext is used only by the runtime's main thread. The context may
+ * operate in any compartment or zone which is not used by an ExclusiveContext,
+ * and will only run in parallel with threads using such contexts.
+ *
+ * A JSContext coerces to an ExclusiveContext.
+ */
+
+struct HelperThread;
+
+class ExclusiveContext : public ContextFriendFields,
+ public MallocProvider<ExclusiveContext>
+{
+ friend class gc::ArenaLists;
+ friend class AutoCompartment;
+ friend class AutoLockForExclusiveAccess;
+ friend struct StackBaseShape;
+ friend void JSScript::initCompartment(ExclusiveContext* cx);
+ friend class jit::JitContext;
+
+ // runtime_ is private to hide it from JSContext. JSContext inherits from
+ // JSRuntime, so it's more efficient to use the base class.
+ JSRuntime* const runtime_;
+
+ // The thread on which this context is running, if this is not a JSContext.
+ HelperThread* helperThread_;
+
+ public:
+ enum ContextKind {
+ Context_JS,
+ Context_Exclusive
+ };
+
+ private:
+ ContextKind contextKind_;
+
+ protected:
+ // Background threads get a read-only copy of the main thread's
+ // ContextOptions.
+ JS::ContextOptions options_;
+
+ public:
+ PerThreadData* perThreadData;
+
+ ExclusiveContext(JSRuntime* rt, PerThreadData* pt, ContextKind kind,
+ const JS::ContextOptions& options);
+
+ bool isJSContext() const {
+ return contextKind_ == Context_JS;
+ }
+
+ JSContext* maybeJSContext() const {
+ if (isJSContext())
+ return (JSContext*) this;
+ return nullptr;
+ }
+
+ JSContext* asJSContext() const {
+ // Note: there is no way to perform an unchecked coercion from a
+ // ThreadSafeContext to a JSContext. This ensures that trying to use
+ // the context as a JSContext off the main thread will nullptr crash
+ // rather than race.
+ MOZ_ASSERT(isJSContext());
+ return maybeJSContext();
+ }
+
+ // In some cases we could potentially want to do operations that require a
+ // JSContext while running off the main thread. While this should never
+ // actually happen, the wide enough API for working off the main thread
+ // makes such operations impossible to rule out. Rather than blindly using
+ // asJSContext() and crashing afterwards, this method may be used to watch
+ // for such cases and produce either a soft failure in release builds or
+ // an assertion failure in debug builds.
+ bool shouldBeJSContext() const {
+ MOZ_ASSERT(isJSContext());
+ return isJSContext();
+ }
+
+ const JS::ContextOptions& options() const {
+ return options_;
+ }
+
+ bool runtimeMatches(JSRuntime* rt) const {
+ return runtime_ == rt;
+ }
+
+ protected:
+ js::gc::ArenaLists* arenas_;
+
+ public:
+ inline js::gc::ArenaLists* arenas() const { return arenas_; }
+
+ template <typename T>
+ bool isInsideCurrentZone(T thing) const {
+ return thing->zoneFromAnyThread() == zone_;
+ }
+
+ template <typename T>
+ inline bool isInsideCurrentCompartment(T thing) const {
+ return thing->compartment() == compartment_;
+ }
+
+ void* onOutOfMemory(js::AllocFunction allocFunc, size_t nbytes, void* reallocPtr = nullptr) {
+ if (!isJSContext()) {
+ addPendingOutOfMemory();
+ return nullptr;
+ }
+ return runtime_->onOutOfMemory(allocFunc, nbytes, reallocPtr, asJSContext());
+ }
+
+ /* Clear the pending exception (if any) due to OOM. */
+ void recoverFromOutOfMemory();
+
+ inline void updateMallocCounter(size_t nbytes) {
+ // Note: this is racy.
+ runtime_->updateMallocCounter(zone_, nbytes);
+ }
+
+ void reportAllocationOverflow() {
+ js::ReportAllocationOverflow(this);
+ }
+
+ // Accessors for immutable runtime data.
+ JSAtomState& names() { return *runtime_->commonNames; }
+ StaticStrings& staticStrings() { return *runtime_->staticStrings; }
+ SharedImmutableStringsCache& sharedImmutableStrings() {
+ return runtime_->sharedImmutableStrings();
+ }
+ bool isPermanentAtomsInitialized() { return !!runtime_->permanentAtoms; }
+ FrozenAtomSet& permanentAtoms() { return *runtime_->permanentAtoms; }
+ WellKnownSymbols& wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
+ JS::BuildIdOp buildIdOp() { return runtime_->buildIdOp; }
+ const JS::AsmJSCacheOps& asmJSCacheOps() { return runtime_->asmJSCacheOps; }
+ PropertyName* emptyString() { return runtime_->emptyString; }
+ FreeOp* defaultFreeOp() { return runtime_->defaultFreeOp(); }
+ void* contextAddressForJit() { return runtime_->unsafeContextFromAnyThread(); }
+ void* runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); }
+ void* stackLimitAddress(StackKind kind) { return &nativeStackLimit[kind]; }
+ void* stackLimitAddressForJitCode(StackKind kind);
+ uintptr_t stackLimit(StackKind kind) { return nativeStackLimit[kind]; }
+ uintptr_t stackLimitForJitCode(StackKind kind);
+ size_t gcSystemPageSize() { return gc::SystemPageSize(); }
+ bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
+ bool jitSupportsUnalignedAccesses() const { return runtime_->jitSupportsUnalignedAccesses; }
+ bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }
+ bool lcovEnabled() const { return runtime_->lcovOutput.isEnabled(); }
+
+ // Thread local data that may be accessed freely.
+ DtoaState* dtoaState() {
+ return perThreadData->dtoaState;
+ }
+
+ frontend::NameCollectionPool& frontendCollectionPool() {
+ return perThreadData->frontendCollectionPool;
+ }
+
+ /*
+ * "Entering" a compartment changes cx->compartment (which changes
+ * cx->global). Note that this does not push any InterpreterFrame which means
+ * that it is possible for cx->fp()->compartment() != cx->compartment.
+ * This is not a problem since, in general, most places in the VM cannot
+ * know that they were called from script (e.g., they may have been called
+ * through the JSAPI via JS_CallFunction) and thus cannot expect fp.
+ *
+ * Compartments should be entered/left in a LIFO fasion. The depth of this
+ * enter/leave stack is maintained by enterCompartmentDepth_ and queried by
+ * hasEnteredCompartment.
+ *
+ * To enter a compartment, code should prefer using AutoCompartment over
+ * manually calling cx->enterCompartment/leaveCompartment.
+ */
+ protected:
+ unsigned enterCompartmentDepth_;
+
+ inline void setCompartment(JSCompartment* comp,
+ const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
+ public:
+ bool hasEnteredCompartment() const {
+ return enterCompartmentDepth_ > 0;
+ }
+#ifdef DEBUG
+ unsigned getEnterCompartmentDepth() const {
+ return enterCompartmentDepth_;
+ }
+#endif
+
+ // If |c| or |oldCompartment| is the atoms compartment, the
+ // |exclusiveAccessLock| must be held.
+ inline void enterCompartment(JSCompartment* c,
+ const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
+ inline void enterNullCompartment();
+ inline void leaveCompartment(JSCompartment* oldCompartment,
+ const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
+
+ void setHelperThread(HelperThread* helperThread);
+ HelperThread* helperThread() const { return helperThread_; }
+
+ // Threads with an ExclusiveContext may freely access any data in their
+ // compartment and zone.
+ JSCompartment* compartment() const {
+ return compartment_;
+ }
+ JS::Zone* zone() const {
+ MOZ_ASSERT_IF(!compartment(), !zone_);
+ MOZ_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_);
+ return zone_;
+ }
+
+ // Zone local methods that can be used freely from an ExclusiveContext.
+ inline js::LifoAlloc& typeLifoAlloc();
+
+ // Current global. This is only safe to use within the scope of the
+ // AutoCompartment from which it's called.
+ inline js::Handle<js::GlobalObject*> global() const;
+
+ // Methods to access runtime data that must be protected by locks.
+ AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
+ return runtime_->atoms(lock);
+ }
+ JSCompartment* atomsCompartment(js::AutoLockForExclusiveAccess& lock) {
+ return runtime_->atomsCompartment(lock);
+ }
+ SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
+ return runtime_->symbolRegistry(lock);
+ }
+ ScriptDataTable& scriptDataTable(AutoLockForExclusiveAccess& lock) {
+ return runtime_->scriptDataTable(lock);
+ }
+
+ // Methods specific to any HelperThread for the context.
+ bool addPendingCompileError(frontend::CompileError** err);
+ void addPendingOverRecursed();
+ void addPendingOutOfMemory();
+};
+
+void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
+
+} /* namespace js */
+
+struct JSContext : public js::ExclusiveContext,
+ public JSRuntime
+{
+ explicit JSContext(JSRuntime* parentRuntime);
+ ~JSContext();
+
+ bool init(uint32_t maxBytes, uint32_t maxNurseryBytes);
+
+ // For names that exist in both ExclusiveContext and JSRuntime, pick the
+ // ExclusiveContext version.
+ using ExclusiveContext::atomsCompartment;
+ using ExclusiveContext::buildIdOp;
+ using ExclusiveContext::emptyString;
+ using ExclusiveContext::jitSupportsSimd;
+ using ExclusiveContext::make_pod_array;
+ using ExclusiveContext::make_unique;
+ using ExclusiveContext::new_;
+ using ExclusiveContext::permanentAtoms;
+ using ExclusiveContext::pod_calloc;
+ using ExclusiveContext::pod_malloc;
+ using ExclusiveContext::staticStrings;
+ using ExclusiveContext::updateMallocCounter;
+ using ExclusiveContext::wellKnownSymbols;
+
+ JSRuntime* runtime() { return this; }
+ js::PerThreadData& mainThread() { return this->JSRuntime::mainThread; }
+
+ static size_t offsetOfActivation() {
+ return offsetof(JSContext, activation_);
+ }
+ static size_t offsetOfWasmActivation() {
+ return offsetof(JSContext, wasmActivationStack_);
+ }
+ static size_t offsetOfProfilingActivation() {
+ return offsetof(JSContext, profilingActivation_);
+ }
+ static size_t offsetOfCompartment() {
+ return offsetof(JSContext, compartment_);
+ }
+
+ friend class js::ExclusiveContext;
+ friend class JS::AutoSaveExceptionState;
+ friend class js::jit::DebugModeOSRVolatileJitFrameIterator;
+ friend void js::ReportOverRecursed(JSContext*, unsigned errorNumber);
+
+ private:
+ /* Exception state -- the exception member is a GC root by definition. */
+ bool throwing; /* is there a pending exception? */
+ JS::PersistentRooted<JS::Value> unwrappedException_; /* most-recently-thrown exception */
+
+ // True if the exception currently being thrown is by result of
+ // ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
+ bool overRecursed_;
+
+ // True if propagating a forced return from an interrupt handler during
+ // debug mode.
+ bool propagatingForcedReturn_;
+
+ // A stack of live iterators that need to be updated in case of debug mode
+ // OSR.
+ js::jit::DebugModeOSRVolatileJitFrameIterator* liveVolatileJitFrameIterators_;
+
+ public:
+ js::ContextCaches caches;
+
+ int32_t reportGranularity; /* see vm/Probes.h */
+
+ js::AutoResolving* resolvingList;
+
+ /* True if generating an error, to prevent runaway recursion. */
+ bool generatingError;
+
+ /* State for object and array toSource conversion. */
+ js::AutoCycleDetector::Set cycleDetectorSet;
+
+ /* Client opaque pointer. */
+ void* data;
+
+ void resetJitStackLimit();
+
+ public:
+
+ /*
+ * Return:
+ * - The newest scripted frame's version, if there is such a frame.
+ * - The version from the compartment.
+ * - The default version.
+ *
+ * Note: if this ever shows up in a profile, just add caching!
+ */
+ JSVersion findVersion() const;
+
+ void initJitStackLimit();
+
+ JS::ContextOptions& options() {
+ return options_;
+ }
+
+ js::LifoAlloc& tempLifoAlloc() { return runtime()->tempLifoAlloc; }
+
+ unsigned outstandingRequests;/* number of JS_BeginRequest calls
+ without the corresponding
+ JS_EndRequest. */
+
+ bool jitIsBroken;
+
+ void updateJITEnabled();
+
+ /*
+ * Youngest frame of a saved stack that will be picked up as an async stack
+ * by any new Activation, and is nullptr when no async stack should be used.
+ *
+ * The JS::AutoSetAsyncStackForNewCalls class can be used to set this.
+ *
+ * New activations will reset this to nullptr on construction after getting
+ * the current value, and will restore the previous value on destruction.
+ */
+ JS::PersistentRooted<js::SavedFrame*> asyncStackForNewActivations;
+
+ /*
+ * Value of asyncCause to be attached to asyncStackForNewActivations.
+ */
+ const char* asyncCauseForNewActivations;
+
+ /*
+ * True if the async call was explicitly requested, e.g. via
+ * callFunctionWithAsyncStack.
+ */
+ bool asyncCallIsExplicit;
+
+ /* Whether this context has JS frames on the stack. */
+ bool currentlyRunning() const;
+
+ bool currentlyRunningInInterpreter() const {
+ return activation()->isInterpreter();
+ }
+ bool currentlyRunningInJit() const {
+ return activation()->isJit();
+ }
+ js::InterpreterFrame* interpreterFrame() const {
+ return activation()->asInterpreter()->current();
+ }
+ js::InterpreterRegs& interpreterRegs() const {
+ return activation()->asInterpreter()->regs();
+ }
+
+ /*
+ * Get the topmost script and optional pc on the stack. By default, this
+ * function only returns a JSScript in the current compartment, returning
+ * nullptr if the current script is in a different compartment. This
+ * behavior can be overridden by passing ALLOW_CROSS_COMPARTMENT.
+ */
+ enum MaybeAllowCrossCompartment {
+ DONT_ALLOW_CROSS_COMPARTMENT = false,
+ ALLOW_CROSS_COMPARTMENT = true
+ };
+ inline JSScript* currentScript(jsbytecode** pc = nullptr,
+ MaybeAllowCrossCompartment = DONT_ALLOW_CROSS_COMPARTMENT) const;
+
+ // The generational GC nursery may only be used on the main thread.
+ inline js::Nursery& nursery() {
+ return gc.nursery;
+ }
+
+ void minorGC(JS::gcreason::Reason reason) {
+ gc.minorGC(reason);
+ }
+
+ public:
+ bool isExceptionPending() {
+ return throwing;
+ }
+
+ MOZ_MUST_USE
+ bool getPendingException(JS::MutableHandleValue rval);
+
+ bool isThrowingOutOfMemory();
+ bool isThrowingDebuggeeWouldRun();
+ bool isClosingGenerator();
+
+ void setPendingException(const js::Value& v);
+
+ void clearPendingException() {
+ throwing = false;
+ overRecursed_ = false;
+ unwrappedException_.setUndefined();
+ }
+
+ bool isThrowingOverRecursed() const { return throwing && overRecursed_; }
+ bool isPropagatingForcedReturn() const { return propagatingForcedReturn_; }
+ void setPropagatingForcedReturn() { propagatingForcedReturn_ = true; }
+ void clearPropagatingForcedReturn() { propagatingForcedReturn_ = false; }
+
+ /*
+ * See JS_SetTrustedPrincipals in jsapi.h.
+ * Note: !cx->compartment is treated as trusted.
+ */
+ inline bool runningWithTrustedPrincipals() const;
+
+ JS_FRIEND_API(size_t) sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+
+ void mark(JSTracer* trc);
+
+ private:
+ /*
+ * The allocation code calls the function to indicate either OOM failure
+ * when p is null or that a memory pressure counter has reached some
+ * threshold when p is not null. The function takes the pointer and not
+ * a boolean flag to minimize the amount of code in its inlined callers.
+ */
+ JS_FRIEND_API(void) checkMallocGCPressure(void* p);
+}; /* struct JSContext */
+
+namespace js {
+
+struct MOZ_RAII AutoResolving {
+ public:
+ enum Kind {
+ LOOKUP,
+ WATCH
+ };
+
+ AutoResolving(JSContext* cx, HandleObject obj, HandleId id, Kind kind = LOOKUP
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : context(cx), object(obj), id(id), kind(kind), link(cx->resolvingList)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ MOZ_ASSERT(obj);
+ cx->resolvingList = this;
+ }
+
+ ~AutoResolving() {
+ MOZ_ASSERT(context->resolvingList == this);
+ context->resolvingList = link;
+ }
+
+ bool alreadyStarted() const {
+ return link && alreadyStartedSlow();
+ }
+
+ private:
+ bool alreadyStartedSlow() const;
+
+ JSContext* const context;
+ HandleObject object;
+ HandleId id;
+ Kind const kind;
+ AutoResolving* const link;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/*
+ * Create and destroy functions for JSContext, which is manually allocated
+ * and exclusively owned.
+ */
+extern JSContext*
+NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime);
+
+extern void
+DestroyContext(JSContext* cx);
+
+enum ErrorArgumentsType {
+ ArgumentsAreUnicode,
+ ArgumentsAreASCII,
+ ArgumentsAreLatin1,
+ ArgumentsAreUTF8
+};
+
+/*
+ * Loads and returns a self-hosted function by name. For performance, define
+ * the property name in vm/CommonPropertyNames.h.
+ *
+ * Defined in SelfHosting.cpp.
+ */
+JSFunction*
+SelfHostedFunction(JSContext* cx, HandlePropertyName propName);
+
+#ifdef va_start
+extern bool
+ReportErrorVA(JSContext* cx, unsigned flags, const char* format,
+ ErrorArgumentsType argumentsType, va_list ap);
+
+extern bool
+ReportErrorNumberVA(JSContext* cx, unsigned flags, JSErrorCallback callback,
+ void* userRef, const unsigned errorNumber,
+ ErrorArgumentsType argumentsType, va_list ap);
+
+extern bool
+ReportErrorNumberUCArray(JSContext* cx, unsigned flags, JSErrorCallback callback,
+ void* userRef, const unsigned errorNumber,
+ const char16_t** args);
+#endif
+
+extern bool
+ExpandErrorArgumentsVA(ExclusiveContext* cx, JSErrorCallback callback,
+ void* userRef, const unsigned errorNumber,
+ const char16_t** messageArgs,
+ ErrorArgumentsType argumentsType,
+ JSErrorReport* reportp, va_list ap);
+
+/* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */
+extern void
+ReportUsageErrorASCII(JSContext* cx, HandleObject callee, const char* msg);
+
+/*
+ * Prints a full report and returns true if the given report is non-nullptr
+ * and the report doesn't have the JSREPORT_WARNING flag set or reportWarnings
+ * is true.
+ * Returns false otherwise.
+ */
+extern bool
+PrintError(JSContext* cx, FILE* file, JS::ConstUTF8CharsZ toStringResult,
+ JSErrorReport* report, bool reportWarnings);
+
+/*
+ * Send a JSErrorReport to the warningReporter callback.
+ */
+void
+CallWarningReporter(JSContext* cx, JSErrorReport* report);
+
+extern bool
+ReportIsNotDefined(JSContext* cx, HandlePropertyName name);
+
+extern bool
+ReportIsNotDefined(JSContext* cx, HandleId id);
+
+/*
+ * Report an attempt to access the property of a null or undefined value (v).
+ */
+extern bool
+ReportIsNullOrUndefined(JSContext* cx, int spindex, HandleValue v, HandleString fallback);
+
+extern void
+ReportMissingArg(JSContext* cx, js::HandleValue v, unsigned arg);
+
+/*
+ * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as
+ * the first argument for the error message. If the error message has less
+ * then 3 arguments, use null for arg1 or arg2.
+ */
+extern bool
+ReportValueErrorFlags(JSContext* cx, unsigned flags, const unsigned errorNumber,
+ int spindex, HandleValue v, HandleString fallback,
+ const char* arg1, const char* arg2);
+
+#define ReportValueError(cx,errorNumber,spindex,v,fallback) \
+ ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
+ spindex, v, fallback, nullptr, nullptr))
+
+#define ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1) \
+ ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
+ spindex, v, fallback, arg1, nullptr))
+
+#define ReportValueError3(cx,errorNumber,spindex,v,fallback,arg1,arg2) \
+ ((void)ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
+ spindex, v, fallback, arg1, arg2))
+
+} /* namespace js */
+
+extern const JSErrorFormatString js_ErrorFormatString[JSErr_Limit];
+
+namespace js {
+
+MOZ_ALWAYS_INLINE bool
+CheckForInterrupt(JSContext* cx)
+{
+ MOZ_ASSERT(!cx->isExceptionPending());
+ // Add an inline fast-path since we have to check for interrupts in some hot
+ // C++ loops of library builtins.
+ JSRuntime* rt = cx->runtime();
+ if (MOZ_UNLIKELY(rt->hasPendingInterrupt()))
+ return rt->handleInterrupt(cx);
+ return true;
+}
+
+/************************************************************************/
+
+/* AutoArrayRooter roots an external array of Values. */
+class MOZ_RAII AutoArrayRooter : private JS::AutoGCRooter
+{
+ public:
+ AutoArrayRooter(JSContext* cx, size_t len, Value* vec
+ MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+ : JS::AutoGCRooter(cx, len), array(vec)
+ {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ MOZ_ASSERT(tag_ >= 0);
+ }
+
+ void changeLength(size_t newLength) {
+ tag_ = ptrdiff_t(newLength);
+ MOZ_ASSERT(tag_ >= 0);
+ }
+
+ void changeArray(Value* newArray, size_t newLength) {
+ changeLength(newLength);
+ array = newArray;
+ }
+
+ Value* start() {
+ return array;
+ }
+
+ size_t length() {
+ MOZ_ASSERT(tag_ >= 0);
+ return size_t(tag_);
+ }
+
+ MutableHandleValue handleAt(size_t i) {
+ MOZ_ASSERT(i < size_t(tag_));
+ return MutableHandleValue::fromMarkedLocation(&array[i]);
+ }
+ HandleValue handleAt(size_t i) const {
+ MOZ_ASSERT(i < size_t(tag_));
+ return HandleValue::fromMarkedLocation(&array[i]);
+ }
+ MutableHandleValue operator[](size_t i) {
+ MOZ_ASSERT(i < size_t(tag_));
+ return MutableHandleValue::fromMarkedLocation(&array[i]);
+ }
+ HandleValue operator[](size_t i) const {
+ MOZ_ASSERT(i < size_t(tag_));
+ return HandleValue::fromMarkedLocation(&array[i]);
+ }
+
+ friend void JS::AutoGCRooter::trace(JSTracer* trc);
+
+ private:
+ Value* array;
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class AutoAssertNoException
+{
+#ifdef DEBUG
+ JSContext* cx;
+ bool hadException;
+#endif
+
+ public:
+ explicit AutoAssertNoException(JSContext* cx)
+#ifdef DEBUG
+ : cx(cx),
+ hadException(cx->isExceptionPending())
+#endif
+ {
+ }
+
+ ~AutoAssertNoException()
+ {
+ MOZ_ASSERT_IF(!hadException, !cx->isExceptionPending());
+ }
+};
+
+/* Exposed intrinsics for the JITs. */
+bool intrinsic_IsSuspendedStarGenerator(JSContext* cx, unsigned argc, Value* vp);
+
+class MOZ_RAII AutoLockForExclusiveAccess
+{
+ JSRuntime* runtime;
+
+ void init(JSRuntime* rt) {
+ runtime = rt;
+ if (runtime->numExclusiveThreads) {
+ runtime->exclusiveAccessLock.lock();
+ } else {
+ MOZ_ASSERT(!runtime->mainThreadHasExclusiveAccess);
+#ifdef DEBUG
+ runtime->mainThreadHasExclusiveAccess = true;
+#endif
+ }
+ }
+
+ public:
+ explicit AutoLockForExclusiveAccess(ExclusiveContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ init(cx->runtime_);
+ }
+ explicit AutoLockForExclusiveAccess(JSRuntime* rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ init(rt);
+ }
+ explicit AutoLockForExclusiveAccess(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
+ MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+ init(cx->runtime());
+ }
+ ~AutoLockForExclusiveAccess() {
+ if (runtime->numExclusiveThreads) {
+ runtime->exclusiveAccessLock.unlock();
+ } else {
+ MOZ_ASSERT(runtime->mainThreadHasExclusiveAccess);
+#ifdef DEBUG
+ runtime->mainThreadHasExclusiveAccess = false;
+#endif
+ }
+ }
+
+ MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+/*
+ * ExclusiveContext variants of encoding functions, for off-main-thread use.
+ * Refer to CharacterEncoding.h for details.
+ */
+extern JS::TwoByteCharsZ
+LossyUTF8CharsToNewTwoByteCharsZ(ExclusiveContext* cx, const JS::UTF8Chars utf8, size_t* outlen);
+
+extern JS::TwoByteCharsZ
+LossyUTF8CharsToNewTwoByteCharsZ(ExclusiveContext* cx, const JS::ConstUTF8CharsZ& utf8, size_t* outlen);
+
+extern JS::Latin1CharsZ
+LossyUTF8CharsToNewLatin1CharsZ(ExclusiveContext* cx, const JS::UTF8Chars utf8, size_t* outlen);
+
+} /* namespace js */
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+inline JSContext*
+JSRuntime::unsafeContextFromAnyThread()
+{
+ return static_cast<JSContext*>(this);
+}
+
+inline JSContext*
+JSRuntime::contextFromMainThread()
+{
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
+ return unsafeContextFromAnyThread();
+}
+
+#endif /* jscntxt_h */