summaryrefslogtreecommitdiffstats
path: root/js/src/vm/Runtime.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm/Runtime.h')
-rw-r--r--js/src/vm/Runtime.h1221
1 files changed, 1221 insertions, 0 deletions
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
new file mode 100644
index 0000000000..fa8ad7f371
--- /dev/null
+++ b/js/src/vm/Runtime.h
@@ -0,0 +1,1221 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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/. */
+
+#ifndef vm_Runtime_h
+#define vm_Runtime_h
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/Atomics.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/DoublyLinkedList.h"
+#include "mozilla/LinkedList.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/MaybeOneOf.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/ThreadLocal.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/Vector.h"
+
+#include <algorithm>
+#include <setjmp.h>
+
+#include "jsapi.h"
+
+#include "builtin/AtomicsObject.h"
+#ifdef JS_HAS_INTL_API
+# include "builtin/intl/SharedIntlData.h"
+#endif
+#include "frontend/NameCollections.h"
+#include "gc/GCRuntime.h"
+#include "gc/Tracer.h"
+#include "js/AllocationRecording.h"
+#include "js/BuildId.h" // JS::BuildIdOp
+#include "js/Debug.h"
+#include "js/experimental/CTypes.h" // JS::CTypesActivityCallback
+#include "js/experimental/SourceHook.h" // js::SourceHook
+#include "js/friend/StackLimits.h" // js::ReportOverRecursed
+#include "js/friend/UsageStatistics.h" // JSAccumulateTelemetryDataCallback
+#include "js/GCVector.h"
+#include "js/HashTable.h"
+#include "js/Modules.h" // JS::Module{DynamicImport,Metadata,Resolve}Hook
+#ifdef DEBUG
+# include "js/Proxy.h" // For AutoEnterPolicy
+#endif
+#include "js/Stream.h" // JS::AbortSignalIsAborted
+#include "js/Symbol.h"
+#include "js/UniquePtr.h"
+#include "js/Utility.h"
+#include "js/Vector.h"
+#include "js/Warnings.h" // JS::WarningReporter
+#include "threading/Thread.h"
+#include "vm/Caches.h"
+#include "vm/CodeCoverage.h"
+#include "vm/CommonPropertyNames.h"
+#include "vm/GeckoProfiler.h"
+#include "vm/JSAtom.h"
+#include "vm/JSAtomState.h"
+#include "vm/JSScript.h"
+#include "vm/OffThreadPromiseRuntimeState.h" // js::OffThreadPromiseRuntimeState
+#include "vm/Scope.h"
+#include "vm/SharedImmutableStringsCache.h"
+#include "vm/SharedStencil.h" // js::SharedImmutableScriptDataTable
+#include "vm/Stack.h"
+#include "vm/SymbolType.h"
+#include "wasm/WasmTypes.h"
+
+struct JSClass;
+
+namespace js {
+
+class AutoAssertNoContentJS;
+class EnterDebuggeeNoExecute;
+#ifdef JS_TRACE_LOGGING
+class TraceLoggerThread;
+#endif
+
+} // namespace js
+
+struct DtoaState;
+struct JSLocaleCallbacks;
+
+#ifdef JS_SIMULATOR_ARM64
+namespace vixl {
+class Simulator;
+}
+#endif
+
+namespace js {
+
+extern MOZ_COLD void ReportOutOfMemory(JSContext* cx);
+
+/* Different signature because the return type has MOZ_MUST_USE_TYPE. */
+extern MOZ_COLD mozilla::GenericErrorResult<OOM> ReportOutOfMemoryResult(
+ JSContext* cx);
+
+extern MOZ_COLD void ReportAllocationOverflow(JSContext* maybecx);
+
+class Activation;
+class ActivationIterator;
+
+namespace jit {
+class JitRuntime;
+class JitActivation;
+struct PcScriptCache;
+class CompileRuntime;
+
+#ifdef JS_SIMULATOR_ARM64
+typedef vixl::Simulator Simulator;
+#elif defined(JS_SIMULATOR)
+class Simulator;
+#endif
+} // namespace jit
+
+namespace frontend {
+class WellKnownParserAtoms;
+} // namespace frontend
+
+// [SMDOC] JS Engine Threading
+//
+// Threads interacting with a runtime are divided into two categories:
+//
+// - The main thread is capable of running JS. There's at most one main thread
+// per runtime.
+//
+// - Helper threads do not run JS, and are controlled or triggered by activity
+// on the main thread (or main threads, since all runtimes in a process share
+// helper threads). Helper threads may have exclusive access to zones created
+// for them, for parsing and similar tasks, but their activities do not cause
+// observable changes in script behaviors. Activity on helper threads may be
+// referred to as happening 'off thread' or on a background thread in some
+// parts of the VM.
+
+} /* namespace js */
+
+namespace JS {
+struct RuntimeSizes;
+} // namespace JS
+
+namespace js {
+
+/*
+ * Storage for well-known symbols. It's a separate struct from the Runtime so
+ * that it can be shared across multiple runtimes. As in JSAtomState, each
+ * field is a smart pointer that's immutable once initialized.
+ * `rt->wellKnownSymbols->iterator` is convertible to Handle<Symbol*>.
+ *
+ * Well-known symbols are never GC'd. The description() of each well-known
+ * symbol is a permanent atom.
+ */
+struct WellKnownSymbols {
+#define DECLARE_SYMBOL(name) js::ImmutableSymbolPtr name;
+ JS_FOR_EACH_WELL_KNOWN_SYMBOL(DECLARE_SYMBOL)
+#undef DECLARE_SYMBOL
+
+ const ImmutableSymbolPtr& get(size_t u) const {
+ MOZ_ASSERT(u < JS::WellKnownSymbolLimit);
+ const ImmutableSymbolPtr* symbols =
+ reinterpret_cast<const ImmutableSymbolPtr*>(this);
+ return symbols[u];
+ }
+
+ const ImmutableSymbolPtr& get(JS::SymbolCode code) const {
+ return get(size_t(code));
+ }
+
+ WellKnownSymbols() = default;
+ WellKnownSymbols(const WellKnownSymbols&) = delete;
+ WellKnownSymbols& operator=(const WellKnownSymbols&) = delete;
+};
+
+// There are several coarse locks in the enum below. These may be either
+// per-runtime or per-process. When acquiring more than one of these locks,
+// the acquisition must be done in the order below to avoid deadlocks.
+enum RuntimeLock { HelperThreadStateLock, GCLock };
+
+inline bool CanUseExtraThreads() {
+ extern bool gCanUseExtraThreads;
+ return gCanUseExtraThreads;
+}
+
+void DisableExtraThreads();
+
+using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>;
+
+class AutoLockScriptData;
+
+// Self-hosted lazy functions do not maintain a BaseScript as we can clone from
+// the copy in the self-hosting zone. To allow these functions to be called by
+// the JITs, we need a minimal script object. There is one instance per runtime.
+struct SelfHostedLazyScript {
+ SelfHostedLazyScript() = default;
+
+ // Pointer to interpreter trampoline. This field is stored at same location as
+ // in BaseScript::jitCodeRaw_.
+ uint8_t* jitCodeRaw_ = nullptr;
+
+ // Warm-up count of zero. This field is stored at the same offset as
+ // BaseScript::warmUpData_.
+ ScriptWarmUpData warmUpData_ = {};
+
+ static constexpr size_t offsetOfJitCodeRaw() {
+ return offsetof(SelfHostedLazyScript, jitCodeRaw_);
+ }
+ static constexpr size_t offsetOfWarmUpData() {
+ return offsetof(SelfHostedLazyScript, warmUpData_);
+ }
+};
+
+} // namespace js
+
+struct JSTelemetrySender;
+
+struct JSRuntime {
+ private:
+ friend class js::Activation;
+ friend class js::ActivationIterator;
+ friend class js::jit::JitActivation;
+ friend class js::jit::CompileRuntime;
+
+ /* Space for interpreter frames. */
+ js::MainThreadData<js::InterpreterStack> interpreterStack_;
+
+ public:
+ js::InterpreterStack& interpreterStack() { return interpreterStack_.ref(); }
+
+ /*
+ * If non-null, another runtime guaranteed to outlive this one and whose
+ * permanent data may be used by this one where possible.
+ */
+ JSRuntime* const parentRuntime;
+
+#ifdef DEBUG
+ /* The number of child runtimes that have this runtime as their parent. */
+ mozilla::Atomic<size_t> childRuntimeCount;
+
+ class AutoUpdateChildRuntimeCount {
+ JSRuntime* parent_;
+
+ public:
+ explicit AutoUpdateChildRuntimeCount(JSRuntime* parent) : parent_(parent) {
+ if (parent_) {
+ parent_->childRuntimeCount++;
+ }
+ }
+
+ ~AutoUpdateChildRuntimeCount() {
+ if (parent_) {
+ parent_->childRuntimeCount--;
+ }
+ }
+ };
+
+ AutoUpdateChildRuntimeCount updateChildRuntimeCount;
+#endif
+
+ private:
+#ifdef DEBUG
+ js::WriteOnceData<bool> initialized_;
+#endif
+
+ // The JSContext* for the runtime's main thread. Immutable after this is set
+ // in JSRuntime::init.
+ JSContext* mainContext_;
+
+ public:
+ JSContext* mainContextFromAnyThread() const { return mainContext_; }
+ const void* addressOfMainContext() { return &mainContext_; }
+ js::Fprinter parserWatcherFile;
+
+ inline JSContext* mainContextFromOwnThread();
+
+ /*
+ * The start of the range stored in the profiler sample buffer, as measured
+ * after the most recent sample.
+ * All JitcodeGlobalTable entries referenced from a given sample are
+ * assigned the buffer position of the START of the sample. The buffer
+ * entries that reference the JitcodeGlobalTable entries will only ever be
+ * read from the buffer while the entire sample is still inside the buffer;
+ * if some buffer entries at the start of the sample have left the buffer,
+ * the entire sample will be considered inaccessible.
+ * This means that, once profilerSampleBufferRangeStart_ advances beyond
+ * the sample position that's stored on a JitcodeGlobalTable entry, the
+ * buffer entries that reference this JitcodeGlobalTable entry will be
+ * considered inaccessible, and those JitcodeGlobalTable entry can be
+ * disposed of.
+ */
+ mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire>
+ profilerSampleBufferRangeStart_;
+
+ mozilla::Maybe<uint64_t> profilerSampleBufferRangeStart() {
+ if (beingDestroyed_ || !geckoProfiler().enabled()) {
+ return mozilla::Nothing();
+ }
+ uint64_t rangeStart = profilerSampleBufferRangeStart_;
+ return mozilla::Some(rangeStart);
+ }
+ void setProfilerSampleBufferRangeStart(uint64_t rangeStart) {
+ profilerSampleBufferRangeStart_ = rangeStart;
+ }
+
+ /* Call this to accumulate telemetry data. May be called from any thread; the
+ * embedder is responsible for locking. */
+ JSAccumulateTelemetryDataCallback telemetryCallback;
+
+ /* Call this to accumulate use counter data. */
+ js::MainThreadData<JSSetUseCounterCallback> useCounterCallback;
+
+ js::MainThreadData<JSGetElementCallback> getElementCallback;
+
+ public:
+ // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
+ // histogram. |key| provides an additional key to identify the histogram.
+ // |sample| is the data to add to the histogram.
+ void addTelemetry(int id, uint32_t sample, const char* key = nullptr);
+
+ JSTelemetrySender getTelemetrySender() const;
+
+ void setTelemetryCallback(JSRuntime* rt,
+ JSAccumulateTelemetryDataCallback callback);
+
+ void setElementCallback(JSRuntime* rt, JSGetElementCallback callback);
+
+ // Sets the use counter for a specific feature, measuring the presence or
+ // absence of usage of a feature on a specific web page and document which
+ // the passed JSObject belongs to.
+ void setUseCounter(JSObject* obj, JSUseCounter counter);
+
+ void setUseCounterCallback(JSRuntime* rt, JSSetUseCounterCallback callback);
+
+ public:
+ js::UnprotectedData<js::OffThreadPromiseRuntimeState> offThreadPromiseState;
+ js::UnprotectedData<JS::ConsumeStreamCallback> consumeStreamCallback;
+ js::UnprotectedData<JS::ReportStreamErrorCallback> reportStreamErrorCallback;
+
+ js::GlobalObject* getIncumbentGlobal(JSContext* cx);
+ bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job,
+ js::HandleObject promise,
+ js::Handle<js::GlobalObject*> incumbentGlobal);
+ void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
+ void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
+
+ /* Had an out-of-memory error which did not populate an exception. */
+ mozilla::Atomic<bool, mozilla::SequentiallyConsistent> hadOutOfMemory;
+
+ /*
+ * Allow relazifying functions in compartments that are active. This is
+ * only used by the relazifyFunctions() testing function.
+ */
+ js::MainThreadData<bool> allowRelazificationForTesting;
+
+ /* Zone destroy callback. */
+ js::MainThreadData<JSDestroyZoneCallback> destroyZoneCallback;
+
+ /* Compartment destroy callback. */
+ js::MainThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
+
+ /* Compartment memory reporting callback. */
+ js::MainThreadData<JSSizeOfIncludingThisCompartmentCallback>
+ sizeOfIncludingThisCompartmentCallback;
+
+ /* Callback for creating ubi::Nodes representing DOM node objects. Set by
+ * JS::ubi::SetConstructUbiNodeForDOMObjectCallback. Refer to
+ * js/public/UbiNode.h.
+ */
+ void (*constructUbiNodeForDOMObjectCallback)(void*, JSObject*) = nullptr;
+
+ /* Realm destroy callback. */
+ js::MainThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
+
+ /* Call this to get the name of a realm. */
+ js::MainThreadData<JS::RealmNameCallback> realmNameCallback;
+
+ js::MainThreadData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
+
+ js::MainThreadData<const JSSecurityCallbacks*> securityCallbacks;
+ js::MainThreadData<const js::DOMCallbacks*> DOMcallbacks;
+ js::MainThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
+ js::MainThreadData<JSReadPrincipalsOp> readPrincipals;
+
+ /* Optional warning reporter. */
+ js::MainThreadData<JS::WarningReporter> warningReporter;
+
+ // Lazy self-hosted functions use a shared SelfHostedLazyScript instance
+ // instead instead of a BaseScript. This contains the minimal pointers to
+ // trampolines for the scripts to support direct jitCodeRaw calls.
+ js::UnprotectedData<js::SelfHostedLazyScript> selfHostedLazyScript;
+
+ private:
+ /* Gecko profiling metadata */
+ js::UnprotectedData<js::GeckoProfilerRuntime> geckoProfiler_;
+
+ public:
+ js::GeckoProfilerRuntime& geckoProfiler() { return geckoProfiler_.ref(); }
+
+ // Heap GC roots for PersistentRooted pointers.
+ js::MainThreadData<mozilla::EnumeratedArray<
+ JS::RootKind, JS::RootKind::Limit,
+ mozilla::LinkedList<JS::PersistentRooted<JS::detail::RootListEntry*>>>>
+ heapRoots;
+
+ void tracePersistentRoots(JSTracer* trc);
+ void finishPersistentRoots();
+
+ void finishRoots();
+
+ private:
+ js::UnprotectedData<const JSPrincipals*> trustedPrincipals_;
+
+ public:
+ void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; }
+ const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; }
+
+ js::MainThreadData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
+ js::MainThreadData<js::PreserveWrapperCallback> preserveWrapperCallback;
+ js::MainThreadData<js::HasReleasedWrapperCallback> hasReleasedWrapperCallback;
+
+ js::MainThreadData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
+
+ js::MainThreadData<JS::CTypesActivityCallback> ctypesActivityCallback;
+
+ private:
+ js::WriteOnceData<const JSClass*> windowProxyClass_;
+
+ public:
+ const JSClass* maybeWindowProxyClass() const { return windowProxyClass_; }
+ void setWindowProxyClass(const JSClass* clasp) { windowProxyClass_ = clasp; }
+
+ private:
+ js::WriteOnceData<const JSClass*> abortSignalClass_;
+ js::WriteOnceData<JS::AbortSignalIsAborted> abortSignalIsAborted_;
+
+ public:
+ void initPipeToHandling(const JSClass* abortSignalClass,
+ JS::AbortSignalIsAborted isAborted) {
+ MOZ_ASSERT(abortSignalClass != nullptr,
+ "doesn't make sense for an embedder to provide a null class "
+ "when specifying pipeTo handling");
+ MOZ_ASSERT(isAborted != nullptr, "must pass a valid function pointer");
+
+ abortSignalClass_ = abortSignalClass;
+ abortSignalIsAborted_ = isAborted;
+ }
+
+ const JSClass* maybeAbortSignalClass() const { return abortSignalClass_; }
+
+ bool abortSignalIsAborted(JSObject* obj) {
+ MOZ_ASSERT(abortSignalIsAborted_ != nullptr,
+ "must call initPipeToHandling first");
+ return abortSignalIsAborted_(obj);
+ }
+
+ private:
+ // List of non-ephemeron weak containers to sweep during
+ // beginSweepingSweepGroup.
+ js::MainThreadData<mozilla::LinkedList<JS::detail::WeakCacheBase>>
+ weakCaches_;
+
+ public:
+ mozilla::LinkedList<JS::detail::WeakCacheBase>& weakCaches() {
+ return weakCaches_.ref();
+ }
+ void registerWeakCache(JS::detail::WeakCacheBase* cachep) {
+ weakCaches().insertBack(cachep);
+ }
+
+ template <typename T>
+ struct GlobalObjectWatchersLinkAccess {
+ static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
+ return aThis->onNewGlobalObjectWatchersLink;
+ }
+ };
+
+ template <typename T>
+ struct GarbageCollectionWatchersLinkAccess {
+ static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
+ return aThis->onGarbageCollectionWatchersLink;
+ }
+ };
+
+ using OnNewGlobalWatchersList =
+ mozilla::DoublyLinkedList<js::Debugger,
+ GlobalObjectWatchersLinkAccess<js::Debugger>>;
+ using OnGarbageCollectionWatchersList = mozilla::DoublyLinkedList<
+ js::Debugger, GarbageCollectionWatchersLinkAccess<js::Debugger>>;
+
+ private:
+ /*
+ * List of all enabled Debuggers that have onNewGlobalObject handler
+ * methods established.
+ */
+ js::MainThreadData<OnNewGlobalWatchersList> onNewGlobalObjectWatchers_;
+
+ /*
+ * List of all enabled Debuggers that have onGarbageCollection handler
+ * methods established.
+ */
+ js::MainThreadData<OnGarbageCollectionWatchersList>
+ onGarbageCollectionWatchers_;
+
+ public:
+ OnNewGlobalWatchersList& onNewGlobalObjectWatchers() {
+ return onNewGlobalObjectWatchers_.ref();
+ }
+
+ OnGarbageCollectionWatchersList& onGarbageCollectionWatchers() {
+ return onGarbageCollectionWatchers_.ref();
+ }
+
+ private:
+ /* Linked list of all Debugger objects in the runtime. */
+ js::MainThreadData<mozilla::LinkedList<js::Debugger>> debuggerList_;
+
+ public:
+ mozilla::LinkedList<js::Debugger>& debuggerList() {
+ return debuggerList_.ref();
+ }
+
+ private:
+ /*
+ * Lock used to protect the script data table, which can be used by
+ * off-thread parsing.
+ *
+ * Locking this only occurs if there is actually a thread other than the
+ * main thread which could access this.
+ */
+ js::Mutex scriptDataLock;
+#ifdef DEBUG
+ bool activeThreadHasScriptDataAccess;
+#endif
+
+ // Number of off-thread ParseTasks that are using this runtime. This is only
+ // updated on main-thread. If this is non-zero we must use `scriptDataLock` to
+ // protect access to the bytecode table;
+ mozilla::Atomic<size_t, mozilla::SequentiallyConsistent> numParseTasks;
+
+ // Number of zones which may be operated on by helper threads.
+ mozilla::Atomic<size_t, mozilla::SequentiallyConsistent>
+ numActiveHelperThreadZones;
+
+ friend class js::AutoLockScriptData;
+
+ public:
+ void setUsedByHelperThread(JS::Zone* zone);
+ void clearUsedByHelperThread(JS::Zone* zone);
+
+ bool hasParseTasks() const { return numParseTasks > 0; }
+ bool hasHelperThreadZones() const { return numActiveHelperThreadZones > 0; }
+
+ void addParseTaskRef() { numParseTasks++; }
+ void decParseTaskRef() { numParseTasks--; }
+
+#ifdef DEBUG
+ void assertCurrentThreadHasScriptDataAccess() const {
+ if (!hasParseTasks()) {
+ MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(this) &&
+ activeThreadHasScriptDataAccess);
+ return;
+ }
+
+ scriptDataLock.assertOwnedByCurrentThread();
+ }
+
+ bool currentThreadHasAtomsTableAccess() const {
+ return js::CurrentThreadCanAccessRuntime(this) &&
+ atoms_->mainThreadHasAllLocks();
+ }
+#endif
+
+ JS::HeapState heapState() const { return gc.heapState(); }
+
+ // How many realms there are across all zones. This number includes
+ // off-thread context realms, so it isn't necessarily equal to the
+ // number of realms visited by RealmsIter.
+ js::MainThreadData<size_t> numRealms;
+
+ // The Gecko Profiler may want to sample the allocations happening across the
+ // browser. This callback can be registered to record the allocation.
+ js::MainThreadData<JS::RecordAllocationsCallback> recordAllocationCallback;
+ js::MainThreadData<double> allocationSamplingProbability;
+
+ private:
+ // Number of debuggee realms in the runtime.
+ js::MainThreadData<size_t> numDebuggeeRealms_;
+
+ // Number of debuggee realms in the runtime observing code coverage.
+ js::MainThreadData<size_t> numDebuggeeRealmsObservingCoverage_;
+
+ public:
+ void incrementNumDebuggeeRealms();
+ void decrementNumDebuggeeRealms();
+
+ size_t numDebuggeeRealms() const { return numDebuggeeRealms_; }
+
+ void incrementNumDebuggeeRealmsObservingCoverage();
+ void decrementNumDebuggeeRealmsObservingCoverage();
+
+ void startRecordingAllocations(double probability,
+ JS::RecordAllocationsCallback callback);
+ void stopRecordingAllocations();
+ void ensureRealmIsRecordingAllocations(JS::Handle<js::GlobalObject*> global);
+
+ /* Locale-specific callbacks for string conversion. */
+ js::MainThreadData<const JSLocaleCallbacks*> localeCallbacks;
+
+ /* Default locale for Internationalization API */
+ js::MainThreadData<js::UniqueChars> defaultLocale;
+
+ /* If true, new scripts must be created with PC counter information. */
+ js::MainThreadOrIonCompileData<bool> profilingScripts;
+
+ /* Strong references on scripts held for PCCount profiling API. */
+ js::MainThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*>
+ scriptAndCountsVector;
+
+ private:
+ /* Code coverage output. */
+ js::UnprotectedData<js::coverage::LCovRuntime> lcovOutput_;
+
+ public:
+ js::coverage::LCovRuntime& lcovOutput() { return lcovOutput_.ref(); }
+
+ private:
+ js::UnprotectedData<js::jit::JitRuntime*> jitRuntime_;
+
+ /*
+ * Self-hosting state cloned on demand into other compartments. Shared with
+ * the parent runtime if there is one.
+ */
+ js::WriteOnceData<js::NativeObject*> selfHostingGlobal_;
+
+ // Optional reference to an array which contains the XDR content to be used
+ // instead of parsing the self-hosted source text. It is cleared once the
+ // self-hosted global is initialized.
+ JS::TranscodeRange selfHostedXDR = {};
+
+ // Callback to copy the XDR content of the self-hosted code.
+ using TranscodeBufferWriter = bool (*)(JSContext* cx,
+ const JS::TranscodeBuffer&);
+ TranscodeBufferWriter selfHostedXDRWriter = nullptr;
+
+ static js::GlobalObject* createSelfHostingGlobal(JSContext* cx);
+
+ // Used internally to initialize the self-hosted global using XDR content.
+ bool initSelfHostingFromXDR(JSContext* cx, const JS::CompileOptions& options,
+ js::frontend::CompilationStencilSet& stencilSet,
+ js::MutableHandle<JSScript*> scriptOut);
+
+ public:
+ void getUnclonedSelfHostedValue(js::PropertyName* name, JS::Value* vp);
+ JSFunction* getUnclonedSelfHostedFunction(js::PropertyName* name);
+
+ MOZ_MUST_USE bool createJitRuntime(JSContext* cx);
+ js::jit::JitRuntime* jitRuntime() const { return jitRuntime_.ref(); }
+ bool hasJitRuntime() const { return !!jitRuntime_; }
+
+ private:
+ // Used to generate random keys for hash tables.
+ mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomKeyGenerator_;
+ mozilla::non_crypto::XorShift128PlusRNG& randomKeyGenerator();
+
+ // Used to generate random hash codes for symbols.
+ mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG>
+ randomHashCodeGenerator_;
+
+ public:
+ mozilla::HashCodeScrambler randomHashCodeScrambler();
+ mozilla::non_crypto::XorShift128PlusRNG forkRandomKeyGenerator();
+
+ js::HashNumber randomHashCode();
+
+ //-------------------------------------------------------------------------
+ // Self-hosting support
+ //-------------------------------------------------------------------------
+
+ // Optional XDR compiled data for self-hosting. If set this, will be used to
+ // parse the self-hosting code instead of from source code.
+ //
+ // This field is cleared internally after self-hosting is initialized.
+ void setSelfHostedXDR(JS::TranscodeRange enctext) {
+ MOZ_RELEASE_ASSERT(!hasInitializedSelfHosting());
+ MOZ_RELEASE_ASSERT(enctext.length() > 0);
+ new (&selfHostedXDR) mozilla::Range(enctext);
+ }
+
+ // Register a callback which would be used to return a buffer if the
+ // self-hosted code should be serialized and stored in the returned buffer.
+ void setSelfHostedXDRWriterCallback(TranscodeBufferWriter writer) {
+ MOZ_RELEASE_ASSERT(!hasInitializedSelfHosting());
+ MOZ_RELEASE_ASSERT(!selfHostedXDRWriter);
+ selfHostedXDRWriter = writer;
+ }
+
+ bool hasInitializedSelfHosting() const { return selfHostingGlobal_; }
+
+ bool initSelfHosting(JSContext* cx);
+ void finishSelfHosting();
+ void traceSelfHostingGlobal(JSTracer* trc);
+ bool isSelfHostingGlobal(JSObject* global) {
+ return global == selfHostingGlobal_;
+ }
+ js::GeneratorKind getSelfHostedFunctionGeneratorKind(JSAtom* name);
+ bool createLazySelfHostedFunctionClone(JSContext* cx,
+ js::HandlePropertyName selfHostedName,
+ js::HandleAtom name, unsigned nargs,
+ js::NewObjectKind newKind,
+ js::MutableHandleFunction fun);
+ bool cloneSelfHostedFunctionScript(JSContext* cx,
+ js::Handle<js::PropertyName*> name,
+ js::Handle<JSFunction*> targetFun);
+ bool cloneSelfHostedValue(JSContext* cx, js::Handle<js::PropertyName*> name,
+ js::MutableHandleValue vp);
+ void assertSelfHostedFunctionHasCanonicalName(JSContext* cx,
+ js::HandlePropertyName name);
+#if DEBUG
+ bool isSelfHostingZone(const JS::Zone* zone) const {
+ return selfHostingGlobal_ && selfHostingGlobal_->zone() == zone;
+ }
+#endif
+
+ //-------------------------------------------------------------------------
+ // Locale information
+ //-------------------------------------------------------------------------
+
+ /*
+ * Set the default locale for the ECMAScript Internationalization API
+ * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
+ * Note that the Internationalization API encourages clients to
+ * specify their own locales.
+ * The locale string remains owned by the caller.
+ */
+ bool setDefaultLocale(const char* locale);
+
+ /* Reset the default locale to OS defaults. */
+ void resetDefaultLocale();
+
+ /* Gets current default locale. String remains owned by context. */
+ const char* getDefaultLocale();
+
+ /* Garbage collector state. */
+ js::gc::GCRuntime gc;
+
+ /* Garbage collector state has been successfully initialized. */
+ js::WriteOnceData<bool> gcInitialized;
+
+ bool hasZealMode(js::gc::ZealMode mode) { return gc.hasZealMode(mode); }
+
+ void lockGC() { gc.lockGC(); }
+
+ void unlockGC() { gc.unlockGC(); }
+
+ js::WriteOnceData<js::PropertyName*> emptyString;
+
+ private:
+ js::MainThreadOrGCTaskData<JSFreeOp*> defaultFreeOp_;
+
+ public:
+ JSFreeOp* defaultFreeOp() {
+ MOZ_ASSERT(defaultFreeOp_);
+ return defaultFreeOp_;
+ }
+
+#if !JS_HAS_INTL_API
+ /* Number localization, used by jsnum.cpp. */
+ js::WriteOnceData<const char*> thousandsSeparator;
+ js::WriteOnceData<const char*> decimalSeparator;
+ js::WriteOnceData<const char*> numGrouping;
+#endif
+
+ private:
+ mozilla::Maybe<js::SharedImmutableStringsCache> sharedImmutableStrings_;
+
+ public:
+ // If this particular JSRuntime has a SharedImmutableStringsCache, return a
+ // pointer to it, otherwise return nullptr.
+ js::SharedImmutableStringsCache* maybeThisRuntimeSharedImmutableStrings() {
+ return sharedImmutableStrings_.isSome() ? &*sharedImmutableStrings_
+ : nullptr;
+ }
+
+ // Get a reference to this JSRuntime's or its parent's
+ // SharedImmutableStringsCache.
+ js::SharedImmutableStringsCache& sharedImmutableStrings() {
+ MOZ_ASSERT_IF(parentRuntime, !sharedImmutableStrings_);
+ MOZ_ASSERT_IF(!parentRuntime, sharedImmutableStrings_);
+ return parentRuntime ? parentRuntime->sharedImmutableStrings()
+ : *sharedImmutableStrings_;
+ }
+
+ private:
+ js::WriteOnceData<bool> beingDestroyed_;
+
+ public:
+ bool isBeingDestroyed() const { return beingDestroyed_; }
+
+ private:
+ bool allowContentJS_;
+
+ public:
+ bool allowContentJS() const { return allowContentJS_; }
+
+ friend class js::AutoAssertNoContentJS;
+
+ private:
+ // Table of all atoms other than those in permanentAtoms and staticStrings.
+ js::WriteOnceData<js::AtomsTable*> atoms_;
+
+ // Set of all live symbols produced by Symbol.for(). All such symbols are
+ // allocated in the atoms zone. Reading or writing the symbol registry
+ // can only be done from the main thread.
+ js::MainThreadOrGCTaskData<js::SymbolRegistry> symbolRegistry_;
+
+ js::WriteOnceData<js::AtomSet*> permanentAtomsDuringInit_;
+ js::WriteOnceData<js::FrozenAtomSet*> permanentAtoms_;
+
+ public:
+ bool initializeAtoms(JSContext* cx);
+ bool initializeParserAtoms(JSContext* cx);
+ void finishAtoms();
+ void finishParserAtoms();
+ bool atomsAreFinished() const {
+ return !atoms_ && !permanentAtomsDuringInit_;
+ }
+
+ js::AtomsTable* atomsForSweeping() {
+ MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
+ return atoms_;
+ }
+
+ js::AtomsTable& atoms() {
+ MOZ_ASSERT(atoms_);
+ return *atoms_;
+ }
+
+ const JS::Zone* atomsZone(const js::AutoAccessAtomsZone& access) const {
+ return gc.atomsZone;
+ }
+ JS::Zone* atomsZone(const js::AutoAccessAtomsZone& access) {
+ return gc.atomsZone;
+ }
+ JS::Zone* unsafeAtomsZone() { return gc.atomsZone; }
+
+#ifdef DEBUG
+ bool isAtomsZone(const JS::Zone* zone) const { return zone == gc.atomsZone; }
+#endif
+
+ bool activeGCInAtomsZone();
+
+ js::SymbolRegistry& symbolRegistry() { return symbolRegistry_.ref(); }
+
+ // Permanent atoms are fixed during initialization of the runtime and are
+ // not modified or collected until the runtime is destroyed. These may be
+ // shared with another, longer living runtime through |parentRuntime| and
+ // can be freely accessed with no locking necessary.
+
+ // Permanent atoms pre-allocated for general use.
+ js::WriteOnceData<js::StaticStrings*> staticStrings;
+
+ // Cached pointers to various permanent property names.
+ js::WriteOnceData<JSAtomState*> commonNames;
+ js::WriteOnceData<js::frontend::WellKnownParserAtoms*> commonParserNames;
+
+ // All permanent atoms in the runtime, other than those in staticStrings.
+ // Access to this does not require a lock because it is frozen and thus
+ // read-only.
+ const js::FrozenAtomSet* permanentAtoms() const {
+ MOZ_ASSERT(permanentAtomsPopulated());
+ return permanentAtoms_.ref();
+ }
+
+ // The permanent atoms table is populated during initialization.
+ bool permanentAtomsPopulated() const { return permanentAtoms_; }
+
+ // For internal use, return the permanent atoms table while it is being
+ // populated.
+ js::AtomSet* permanentAtomsDuringInit() const {
+ MOZ_ASSERT(!permanentAtoms_);
+ return permanentAtomsDuringInit_.ref();
+ }
+
+ bool initMainAtomsTables(JSContext* cx);
+ void tracePermanentAtoms(JSTracer* trc);
+
+ // Cached well-known symbols (ES6 rev 24 6.1.5.1). Like permanent atoms,
+ // these are shared with the parentRuntime, if any.
+ js::WriteOnceData<js::WellKnownSymbols*> wellKnownSymbols;
+
+#ifdef JS_HAS_INTL_API
+ /* Shared Intl data for this runtime. */
+ js::MainThreadData<js::intl::SharedIntlData> sharedIntlData;
+
+ void traceSharedIntlData(JSTracer* trc);
+#endif
+
+ // Table of bytecode and other data that may be shared across scripts
+ // within the runtime. This may be modified by threads using
+ // AutoLockScriptData.
+ private:
+ js::ScriptDataLockData<js::SharedImmutableScriptDataTable> scriptDataTable_;
+
+ public:
+ js::SharedImmutableScriptDataTable& scriptDataTable(
+ const js::AutoLockScriptData& lock) {
+ return scriptDataTable_.ref();
+ }
+
+ private:
+ static mozilla::Atomic<size_t> liveRuntimesCount;
+
+ public:
+ static bool hasLiveRuntimes() { return liveRuntimesCount > 0; }
+
+ explicit JSRuntime(JSRuntime* parentRuntime);
+ ~JSRuntime();
+
+ // destroyRuntime is used instead of a destructor, to ensure the downcast
+ // to JSContext remains valid. The final GC triggered here depends on this.
+ void destroyRuntime();
+
+ bool init(JSContext* cx, uint32_t maxbytes);
+
+ JSRuntime* thisFromCtor() { return this; }
+
+ private:
+ // Number of live SharedArrayBuffer objects, including those in Wasm shared
+ // memories. uint64_t to avoid any risk of overflow.
+ js::MainThreadData<uint64_t> liveSABs;
+
+ public:
+ void incSABCount() {
+ MOZ_RELEASE_ASSERT(liveSABs != UINT64_MAX);
+ liveSABs++;
+ }
+
+ void decSABCount() {
+ MOZ_RELEASE_ASSERT(liveSABs > 0);
+ liveSABs--;
+ }
+
+ bool hasLiveSABs() const { return liveSABs > 0; }
+
+ public:
+ js::MainThreadData<JS::BeforeWaitCallback> beforeWaitCallback;
+ js::MainThreadData<JS::AfterWaitCallback> afterWaitCallback;
+
+ public:
+ void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
+
+ /*
+ * This should be called after system malloc/calloc/realloc returns nullptr
+ * to try to recove some memory or to report an error. For realloc, the
+ * original pointer must be passed as reallocPtr.
+ *
+ * The function must be called outside the GC lock.
+ */
+ JS_FRIEND_API void* onOutOfMemory(js::AllocFunction allocator,
+ arena_id_t arena, size_t nbytes,
+ void* reallocPtr = nullptr,
+ JSContext* maybecx = nullptr);
+
+ /* onOutOfMemory but can call OnLargeAllocationFailure. */
+ JS_FRIEND_API void* onOutOfMemoryCanGC(js::AllocFunction allocator,
+ arena_id_t arena, size_t nbytes,
+ void* reallocPtr = nullptr);
+
+ static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
+
+ void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
+ JS::RuntimeSizes* rtSizes);
+
+ private:
+ // Settings for how helper threads can be used.
+ mozilla::Atomic<bool, mozilla::SequentiallyConsistent>
+ offthreadIonCompilationEnabled_;
+ mozilla::Atomic<bool, mozilla::SequentiallyConsistent>
+ parallelParsingEnabled_;
+
+#ifdef DEBUG
+ mozilla::Atomic<uint32_t> offThreadParsesRunning_;
+ mozilla::Atomic<bool> offThreadParsingBlocked_;
+#endif
+
+ js::MainThreadData<bool> autoWritableJitCodeActive_;
+
+ public:
+ // Note: these values may be toggled dynamically (in response to about:config
+ // prefs changing).
+ void setOffthreadIonCompilationEnabled(bool value) {
+ offthreadIonCompilationEnabled_ = value;
+ }
+ bool canUseOffthreadIonCompilation() const {
+ return offthreadIonCompilationEnabled_;
+ }
+ void setParallelParsingEnabled(bool value) {
+ parallelParsingEnabled_ = value;
+ }
+ bool canUseParallelParsing() const { return parallelParsingEnabled_; }
+
+#ifdef DEBUG
+
+ void incOffThreadParsesRunning() {
+ MOZ_ASSERT(!isOffThreadParsingBlocked());
+ offThreadParsesRunning_++;
+ }
+
+ void decOffThreadParsesRunning() {
+ MOZ_ASSERT(isOffThreadParseRunning());
+ offThreadParsesRunning_--;
+ }
+
+ bool isOffThreadParseRunning() const { return offThreadParsesRunning_; }
+
+ bool isOffThreadParsingBlocked() const { return offThreadParsingBlocked_; }
+ void setOffThreadParsingBlocked(bool blocked) {
+ MOZ_ASSERT(offThreadParsingBlocked_ != blocked);
+ MOZ_ASSERT(!isOffThreadParseRunning());
+ offThreadParsingBlocked_ = blocked;
+ }
+
+#endif
+
+ void toggleAutoWritableJitCodeActive(bool b) {
+ MOZ_ASSERT(autoWritableJitCodeActive_ != b,
+ "AutoWritableJitCode should not be nested.");
+ autoWritableJitCodeActive_ = b;
+ }
+
+ /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
+ js::MainThreadData<JS::OutOfMemoryCallback> oomCallback;
+ js::MainThreadData<void*> oomCallbackData;
+
+ /*
+ * Debugger.Memory functions like takeCensus use this embedding-provided
+ * function to assess the size of malloc'd blocks of memory.
+ */
+ js::MainThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
+
+ /* Last time at which an animation was played for this runtime. */
+ js::MainThreadData<mozilla::TimeStamp> lastAnimationTime;
+
+ private:
+ /* The stack format for the current runtime. Only valid on non-child
+ * runtimes. */
+ mozilla::Atomic<js::StackFormat, mozilla::ReleaseAcquire> stackFormat_;
+
+ public:
+ js::StackFormat stackFormat() const {
+ const JSRuntime* rt = this;
+ while (rt->parentRuntime) {
+ MOZ_ASSERT(rt->stackFormat_ == js::StackFormat::Default);
+ rt = rt->parentRuntime;
+ }
+ MOZ_ASSERT(rt->stackFormat_ != js::StackFormat::Default);
+ return rt->stackFormat_;
+ }
+ void setStackFormat(js::StackFormat format) {
+ MOZ_ASSERT(!parentRuntime);
+ MOZ_ASSERT(format != js::StackFormat::Default);
+ stackFormat_ = format;
+ }
+
+ private:
+ js::MainThreadData<js::RuntimeCaches> caches_;
+
+ public:
+ js::RuntimeCaches& caches() { return caches_.ref(); }
+
+ // List of all the live wasm::Instances in the runtime. Equal to the union
+ // of all instances registered in all JS::Realms. Accessed from watchdog
+ // threads for purposes of wasm::InterruptRunningCode().
+ js::ExclusiveData<js::wasm::InstanceVector> wasmInstances;
+
+ // The implementation-defined abstract operation HostResolveImportedModule.
+ js::MainThreadData<JS::ModuleResolveHook> moduleResolveHook;
+
+ // A hook that implements the abstract operations
+ // HostGetImportMetaProperties and HostFinalizeImportMeta.
+ js::MainThreadData<JS::ModuleMetadataHook> moduleMetadataHook;
+
+ // A hook that implements the abstract operation
+ // HostImportModuleDynamically. This is also used to enable/disable dynamic
+ // module import and can accessed by off-thread parsing.
+ mozilla::Atomic<JS::ModuleDynamicImportHook> moduleDynamicImportHook;
+
+ // Hooks called when script private references are created and destroyed.
+ js::MainThreadData<JS::ScriptPrivateReferenceHook> scriptPrivateAddRefHook;
+ js::MainThreadData<JS::ScriptPrivateReferenceHook> scriptPrivateReleaseHook;
+
+ void addRefScriptPrivate(const JS::Value& value) {
+ if (!value.isUndefined() && scriptPrivateAddRefHook) {
+ scriptPrivateAddRefHook(value);
+ }
+ }
+
+ void releaseScriptPrivate(const JS::Value& value) {
+ if (!value.isUndefined() && scriptPrivateReleaseHook) {
+ scriptPrivateReleaseHook(value);
+ }
+ }
+
+ public:
+#if defined(NIGHTLY_BUILD)
+ // Support for informing the embedding of any error thrown.
+ // This mechanism is designed to let the embedding
+ // log/report/fail in case certain errors are thrown
+ // (e.g. SyntaxError, ReferenceError or TypeError
+ // in critical code).
+ struct ErrorInterceptionSupport {
+ ErrorInterceptionSupport() : isExecuting(false), interceptor(nullptr) {}
+
+ // true if the error interceptor is currently executing,
+ // false otherwise. Used to avoid infinite loops.
+ bool isExecuting;
+
+ // if non-null, any call to `setPendingException`
+ // in this runtime will trigger the call to `interceptor`
+ JSErrorInterceptor* interceptor;
+ };
+ ErrorInterceptionSupport errorInterception;
+#endif // defined(NIGHTLY_BUILD)
+};
+
+// Context for sending telemetry to the embedder from any thread, main or
+// helper. Obtain a |JSTelemetrySender| by calling |getTelemetrySender()| on
+// the |JSRuntime|.
+struct JSTelemetrySender {
+ private:
+ friend struct JSRuntime;
+
+ JSAccumulateTelemetryDataCallback callback_;
+
+ explicit JSTelemetrySender(JSAccumulateTelemetryDataCallback callback)
+ : callback_(callback) {}
+
+ public:
+ JSTelemetrySender() : callback_(nullptr) {}
+ JSTelemetrySender(const JSTelemetrySender& other) = default;
+ explicit JSTelemetrySender(JSRuntime* runtime)
+ : JSTelemetrySender(runtime->getTelemetrySender()) {}
+
+ // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
+ // histogram. |key| provides an additional key to identify the histogram.
+ // |sample| is the data to add to the histogram.
+ void addTelemetry(int id, uint32_t sample, const char* key = nullptr) {
+ if (callback_) {
+ callback_(id, sample, key);
+ }
+ }
+};
+
+namespace js {
+
+static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Value* vec, size_t len) {
+ // Don't PodZero here because JS::Value is non-trivial.
+ for (size_t i = 0; i < len; i++) {
+ vec[i].setDouble(+0.0);
+ }
+}
+
+static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Value* beg, Value* end) {
+ MakeRangeGCSafe(beg, end - beg);
+}
+
+static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(jsid* beg, jsid* end) {
+ std::fill(beg, end, INT_TO_JSID(0));
+}
+
+static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(jsid* vec, size_t len) {
+ MakeRangeGCSafe(vec, vec + len);
+}
+
+static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Shape** beg, Shape** end) {
+ std::fill(beg, end, nullptr);
+}
+
+static MOZ_ALWAYS_INLINE void MakeRangeGCSafe(Shape** vec, size_t len) {
+ MakeRangeGCSafe(vec, vec + len);
+}
+
+static MOZ_ALWAYS_INLINE void SetValueRangeToUndefined(Value* beg, Value* end) {
+ for (Value* v = beg; v != end; ++v) {
+ v->setUndefined();
+ }
+}
+
+static MOZ_ALWAYS_INLINE void SetValueRangeToUndefined(Value* vec, size_t len) {
+ SetValueRangeToUndefined(vec, vec + len);
+}
+
+static MOZ_ALWAYS_INLINE void SetValueRangeToNull(Value* beg, Value* end) {
+ for (Value* v = beg; v != end; ++v) {
+ v->setNull();
+ }
+}
+
+static MOZ_ALWAYS_INLINE void SetValueRangeToNull(Value* vec, size_t len) {
+ SetValueRangeToNull(vec, vec + len);
+}
+
+extern const JSSecurityCallbacks NullSecurityCallbacks;
+
+// This callback is set by JS::SetProcessLargeAllocationFailureCallback
+// and may be null. See comment in jsapi.h.
+extern mozilla::Atomic<JS::LargeAllocationFailureCallback>
+ OnLargeAllocationFailure;
+
+// This callback is set by JS::SetBuildIdOp and may be null. See comment in
+// jsapi.h.
+extern mozilla::Atomic<JS::BuildIdOp> GetBuildId;
+
+extern JS::FilenameValidationCallback gFilenameValidationCallback;
+
+// This callback is set by js::SetHelperThreadTaskCallback and may be null.
+// See comment in jsapi.h.
+// Returns false if the thread pool fails to dispatch.
+extern bool (*HelperThreadTaskCallback)(js::UniquePtr<js::RunnableTask>);
+
+} /* namespace js */
+
+#endif /* vm_Runtime_h */