diff options
Diffstat (limited to 'js/src/vm/Runtime.h')
-rw-r--r-- | js/src/vm/Runtime.h | 1777 |
1 files changed, 1777 insertions, 0 deletions
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h new file mode 100644 index 000000000..4f7755b9d --- /dev/null +++ b/js/src/vm/Runtime.h @@ -0,0 +1,1777 @@ +/* -*- 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/. */ + +#ifndef vm_Runtime_h +#define vm_Runtime_h + +#include "mozilla/Atomics.h" +#include "mozilla/Attributes.h" +#include "mozilla/LinkedList.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/PodOperations.h" +#include "mozilla/Scoped.h" +#include "mozilla/ThreadLocal.h" +#include "mozilla/Vector.h" + +#include <setjmp.h> + +#include "jsatom.h" +#include "jsclist.h" +#include "jsscript.h" + +#ifdef XP_DARWIN +# include "wasm/WasmSignalHandlers.h" +#endif +#include "builtin/AtomicsObject.h" +#include "builtin/Intl.h" +#include "builtin/Promise.h" +#include "ds/FixedSizeHash.h" +#include "frontend/NameCollections.h" +#include "gc/GCRuntime.h" +#include "gc/Tracer.h" +#include "irregexp/RegExpStack.h" +#include "js/Debug.h" +#include "js/GCVector.h" +#include "js/HashTable.h" +#ifdef DEBUG +# include "js/Proxy.h" // For AutoEnterPolicy +#endif +#include "js/UniquePtr.h" +#include "js/Vector.h" +#include "threading/Thread.h" +#include "vm/CodeCoverage.h" +#include "vm/CommonPropertyNames.h" +#include "vm/DateTime.h" +#include "vm/MallocProvider.h" +#include "vm/Scope.h" +#include "vm/SharedImmutableStringsCache.h" +#include "vm/SPSProfiler.h" +#include "vm/Stack.h" +#include "vm/Stopwatch.h" +#include "vm/Symbol.h" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */ +#endif + +namespace js { + +class PerThreadData; +class ExclusiveContext; +class AutoKeepAtoms; +class EnterDebuggeeNoExecute; +#ifdef JS_TRACE_LOGGING +class TraceLoggerThread; +#endif + +typedef Vector<UniquePtr<PromiseTask>, 0, SystemAllocPolicy> PromiseTaskPtrVector; + +/* Thread Local Storage slot for storing the runtime for a thread. */ +extern MOZ_THREAD_LOCAL(PerThreadData*) TlsPerThreadData; + +} // namespace js + +struct DtoaState; + +#ifdef JS_SIMULATOR_ARM64 +namespace vixl { +class Simulator; +} +#endif + +namespace js { + +extern MOZ_COLD void +ReportOutOfMemory(ExclusiveContext* cx); + +extern MOZ_COLD void +ReportAllocationOverflow(ExclusiveContext* maybecx); + +extern MOZ_COLD void +ReportOverRecursed(ExclusiveContext* cx); + +class Activation; +class ActivationIterator; +class WasmActivation; + +namespace jit { +class JitRuntime; +class JitActivation; +struct PcScriptCache; +struct AutoFlushICache; +class CompileRuntime; + +#ifdef JS_SIMULATOR_ARM64 +typedef vixl::Simulator Simulator; +#elif defined(JS_SIMULATOR) +class Simulator; +#endif +} // namespace jit + +/* + * A FreeOp can do one thing: free memory. For convenience, it has delete_ + * convenience methods that also call destructors. + * + * FreeOp is passed to finalizers and other sweep-phase hooks so that we do not + * need to pass a JSContext to those hooks. + */ +class FreeOp : public JSFreeOp +{ + Vector<void*, 0, SystemAllocPolicy> freeLaterList; + jit::JitPoisonRangeVector jitPoisonRanges; + + public: + static FreeOp* get(JSFreeOp* fop) { + return static_cast<FreeOp*>(fop); + } + + explicit FreeOp(JSRuntime* maybeRuntime); + ~FreeOp(); + + bool onMainThread() const { + return runtime_ != nullptr; + } + + bool maybeOffMainThread() const { + // Sometimes background finalization happens on the main thread so + // runtime_ being null doesn't always mean we are off the main thread. + return !runtime_; + } + + bool isDefaultFreeOp() const; + + inline void free_(void* p); + inline void freeLater(void* p); + + inline bool appendJitPoisonRange(const jit::JitPoisonRange& range); + + template <class T> + inline void delete_(T* p) { + if (p) { + p->~T(); + free_(p); + } + } +}; + +} /* namespace js */ + +namespace JS { +struct RuntimeSizes; +} // namespace JS + +/* Various built-in or commonly-used names pinned on first context. */ +struct JSAtomState +{ +#define PROPERTYNAME_FIELD(idpart, id, text) js::ImmutablePropertyNamePtr id; + FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD) +#undef PROPERTYNAME_FIELD +#define PROPERTYNAME_FIELD(name, code, init, clasp) js::ImmutablePropertyNamePtr name; + JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD) +#undef PROPERTYNAME_FIELD +#define PROPERTYNAME_FIELD(name) js::ImmutablePropertyNamePtr name; + JS_FOR_EACH_WELL_KNOWN_SYMBOL(PROPERTYNAME_FIELD) +#undef PROPERTYNAME_FIELD +#define PROPERTYNAME_FIELD(name) js::ImmutablePropertyNamePtr Symbol_##name; + JS_FOR_EACH_WELL_KNOWN_SYMBOL(PROPERTYNAME_FIELD) +#undef PROPERTYNAME_FIELD + + js::ImmutablePropertyNamePtr* wellKnownSymbolNames() { +#define FIRST_PROPERTYNAME_FIELD(name) return &name; + JS_FOR_EACH_WELL_KNOWN_SYMBOL(FIRST_PROPERTYNAME_FIELD) +#undef FIRST_PROPERTYNAME_FIELD + } + + js::ImmutablePropertyNamePtr* wellKnownSymbolDescriptions() { +#define FIRST_PROPERTYNAME_FIELD(name) return &Symbol_ ##name; + JS_FOR_EACH_WELL_KNOWN_SYMBOL(FIRST_PROPERTYNAME_FIELD) +#undef FIRST_PROPERTYNAME_FIELD + } +}; + +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() {} + WellKnownSymbols(const WellKnownSymbols&) = delete; + WellKnownSymbols& operator=(const WellKnownSymbols&) = delete; +}; + +#define NAME_OFFSET(name) offsetof(JSAtomState, name) + +inline HandlePropertyName +AtomStateOffsetToName(const JSAtomState& atomState, size_t offset) +{ + return *reinterpret_cast<js::ImmutablePropertyNamePtr*>((char*)&atomState + offset); +} + +// 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 { + ExclusiveAccessLock, + HelperThreadStateLock, + GCLock +}; + +inline bool +CanUseExtraThreads() +{ + extern bool gCanUseExtraThreads; + return gCanUseExtraThreads; +} + +void DisableExtraThreads(); + +/* + * Encapsulates portions of the runtime/context that are tied to a + * single active thread. Instances of this structure can occur for + * the main thread as |JSRuntime::mainThread|, for select operations + * performed off thread, such as parsing. + */ +class PerThreadData +{ + /* + * Backpointer to the full shared JSRuntime* with which this + * thread is associated. This is private because accessing the + * fields of this runtime can provoke race conditions, so the + * intention is that access will be mediated through safe + * functions like |runtimeFromMainThread| and |associatedWith()| below. + */ + JSRuntime* runtime_; + + public: +#ifdef JS_TRACE_LOGGING + TraceLoggerMainThread* traceLogger; +#endif + + /* Pointer to the current AutoFlushICache. */ + js::jit::AutoFlushICache* autoFlushICache_; + + public: + /* State used by jsdtoa.cpp. */ + DtoaState* dtoaState; + + /* + * When this flag is non-zero, any attempt to GC will be skipped. It is used + * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in + * debugging facilities that cannot tolerate a GC and would rather OOM + * immediately, such as utilities exposed to GDB. Setting this flag is + * extremely dangerous and should only be used when in an OOM situation or + * in non-exposed debugging facilities. + */ + int32_t suppressGC; + +#ifdef DEBUG + // Whether this thread is actively Ion compiling. + bool ionCompiling; + + // Whether this thread is actively Ion compiling in a context where a minor + // GC could happen simultaneously. If this is true, this thread cannot use + // any pointers into the nursery. + bool ionCompilingSafeForMinorGC; + + // Whether this thread is currently performing GC. This thread could be the + // main thread or a helper thread while the main thread is running the + // collector. + bool performingGC; + + // Whether this thread is currently sweeping GC things. This thread could + // be the main thread or a helper thread while the main thread is running + // the mutator. This is used to assert that destruction of GCPtr only + // happens when we are sweeping. + bool gcSweeping; +#endif + + // Pools used for recycling name maps and vectors when parsing and + // emitting bytecode. Purged on GC when there are no active script + // compilations. + frontend::NameCollectionPool frontendCollectionPool; + + explicit PerThreadData(JSRuntime* runtime); + ~PerThreadData(); + + bool init(); + + bool associatedWith(const JSRuntime* rt) { return runtime_ == rt; } + inline JSRuntime* runtimeFromMainThread(); + inline JSRuntime* runtimeIfOnOwnerThread(); + + JSContext* contextFromMainThread(); + + inline bool exclusiveThreadsPresent(); + + // For threads which may be associated with different runtimes, depending + // on the work they are doing. + class MOZ_STACK_CLASS AutoEnterRuntime + { + PerThreadData* pt; + + public: + AutoEnterRuntime(PerThreadData* pt, JSRuntime* rt) + : pt(pt) + { + MOZ_ASSERT(!pt->runtime_); + pt->runtime_ = rt; + } + + ~AutoEnterRuntime() { + pt->runtime_ = nullptr; + } + }; + + js::jit::AutoFlushICache* autoFlushICache() const; + void setAutoFlushICache(js::jit::AutoFlushICache* afc); + +#ifdef JS_SIMULATOR + js::jit::Simulator* simulator() const; +#endif +}; + +using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>; + +class AutoLockForExclusiveAccess; +} // namespace js + +struct JSRuntime : public JS::shadow::Runtime, + public js::MallocProvider<JSRuntime> +{ + /* + * Per-thread data for the main thread that is associated with + * this JSRuntime, as opposed to any worker threads used in + * parallel sections. See definition of |PerThreadData| struct + * above for more details. + * + * NB: This field is statically asserted to be at offset + * sizeof(js::shadow::Runtime). See + * PerThreadDataFriendFields::getMainThread. + */ + js::PerThreadData mainThread; + + /* + * If Baseline or Ion code is on the stack, and has called into C++, this + * will be aligned to an exit frame. + */ + uint8_t* jitTop; + + /* + * Points to the most recent JitActivation pushed on the thread. + * See JitActivation constructor in vm/Stack.cpp + */ + js::jit::JitActivation* jitActivation; + + /* See comment for JSRuntime::interrupt_. */ + protected: + mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_; + + // Like jitStackLimit_, but not reset to trigger interrupts. + uintptr_t jitStackLimitNoInterrupt_; + + public: + uintptr_t jitStackLimit() const { return jitStackLimit_; } + + // For read-only JIT use: + void* addressOfJitStackLimit() { return &jitStackLimit_; } + static size_t offsetOfJitStackLimit() { return offsetof(JSRuntime, jitStackLimit_); } + + void* addressOfJitStackLimitNoInterrupt() { return &jitStackLimitNoInterrupt_; } + + // Information about the heap allocated backtrack stack used by RegExp JIT code. + js::irregexp::RegExpStack regexpStack; + +#ifdef DEBUG + private: + // The number of possible bailing places encounters before forcefully bailing + // in that place. Zero means inactive. + uint32_t ionBailAfter_; + + public: + void* addressOfIonBailAfter() { return &ionBailAfter_; } + + // Set after how many bailing places we should forcefully bail. + // Zero disables this feature. + void setIonBailAfter(uint32_t after) { + ionBailAfter_ = after; + } +#endif + + private: + friend class js::Activation; + friend class js::ActivationIterator; + friend class js::jit::JitActivation; + friend class js::WasmActivation; + friend class js::jit::CompileRuntime; + + protected: + /* + * Points to the most recent activation running on the thread. + * See Activation comment in vm/Stack.h. + */ + js::Activation* activation_; + + /* + * Points to the most recent profiling activation running on the + * thread. + */ + js::Activation * volatile profilingActivation_; + + /* + * The profiler sampler generation after the latest sample. + * + * The lapCount indicates the number of largest number of 'laps' + * (wrapping from high to low) that occurred when writing entries + * into the sample buffer. All JitcodeGlobalMap entries referenced + * from a given sample are assigned the generation of the sample buffer + * at the START of the run. If multiple laps occur, then some entries + * (towards the end) will be written out with the "wrong" generation. + * The lapCount indicates the required fudge factor to use to compare + * entry generations with the sample buffer generation. + */ + mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> profilerSampleBufferGen_; + mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> profilerSampleBufferLapCount_; + + /* See WasmActivation comment. */ + js::WasmActivation * volatile wasmActivationStack_; + + public: + /* If non-null, report JavaScript entry points to this monitor. */ + JS::dbg::AutoEntryMonitor* entryMonitor; + + /* + * Stack of debuggers that currently disallow debuggee execution. + * + * When we check for NX we are inside the debuggee compartment, and thus a + * stack of Debuggers that have prevented execution need to be tracked to + * enter the correct Debugger compartment to report the error. + */ + js::EnterDebuggeeNoExecute* noExecuteDebuggerTop; + + js::Activation* const* addressOfActivation() const { + return &activation_; + } + static unsigned offsetOfActivation() { + return offsetof(JSRuntime, activation_); + } + + js::Activation* profilingActivation() const { + return profilingActivation_; + } + void* addressOfProfilingActivation() { + return (void*) &profilingActivation_; + } + static unsigned offsetOfProfilingActivation() { + return offsetof(JSRuntime, profilingActivation_); + } + + uint32_t profilerSampleBufferGen() { + return profilerSampleBufferGen_; + } + void resetProfilerSampleBufferGen() { + profilerSampleBufferGen_ = 0; + } + void setProfilerSampleBufferGen(uint32_t gen) { + // May be called from sampler thread or signal handler; use + // compareExchange to make sure we have monotonic increase. + for (;;) { + uint32_t curGen = profilerSampleBufferGen_; + if (curGen >= gen) + break; + + if (profilerSampleBufferGen_.compareExchange(curGen, gen)) + break; + } + } + + uint32_t profilerSampleBufferLapCount() { + MOZ_ASSERT(profilerSampleBufferLapCount_ > 0); + return profilerSampleBufferLapCount_; + } + void resetProfilerSampleBufferLapCount() { + profilerSampleBufferLapCount_ = 1; + } + void updateProfilerSampleBufferLapCount(uint32_t lapCount) { + MOZ_ASSERT(profilerSampleBufferLapCount_ > 0); + + // May be called from sampler thread or signal handler; use + // compareExchange to make sure we have monotonic increase. + for (;;) { + uint32_t curLapCount = profilerSampleBufferLapCount_; + if (curLapCount >= lapCount) + break; + + if (profilerSampleBufferLapCount_.compareExchange(curLapCount, lapCount)) + break; + } + } + + js::WasmActivation* wasmActivationStack() const { + return wasmActivationStack_; + } + static js::WasmActivation* innermostWasmActivation() { + js::PerThreadData* ptd = js::TlsPerThreadData.get(); + return ptd ? ptd->runtimeFromMainThread()->wasmActivationStack_ : nullptr; + } + + js::Activation* activation() const { + return activation_; + } + + /* + * If non-null, another runtime guaranteed to outlive this one and whose + * permanent data may be used by this one where possible. + */ + JSRuntime* parentRuntime; + + private: +#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 + + mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_; + + /* Call this to accumulate telemetry data. */ + JSAccumulateTelemetryDataCallback telemetryCallback; + 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); + + void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback); + + enum InterruptMode { + RequestInterruptUrgent, + RequestInterruptCanWait + }; + + // Any thread can call requestInterrupt() to request that the main JS thread + // stop running and call the interrupt callback (allowing the interrupt + // callback to halt execution). To stop the main JS thread, requestInterrupt + // sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to + // UINTPTR_MAX). The JS engine must continually poll one of these fields + // and call handleInterrupt if either field has the interrupt value. (The + // point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already + // needs to guard on jitStackLimit_ in every function prologue to avoid + // stack overflow, so we avoid a second branch on interrupt_ by setting + // jitStackLimit_ to a value that is guaranteed to fail the guard.) + // + // Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed + // Atomic so, while the writes are guaranteed to eventually be visible to + // the main thread, it can happen in any order. handleInterrupt calls the + // interrupt callback if either is set, so it really doesn't matter as long + // as the JS engine is continually polling at least one field. In corner + // cases, this relaxed ordering could lead to an interrupt handler being + // called twice in succession after a single requestInterrupt call, but + // that's fine. + void requestInterrupt(InterruptMode mode); + bool handleInterrupt(JSContext* cx); + + MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const { + return interrupt_; + } + + // For read-only JIT use: + void* addressOfInterruptUint32() { + static_assert(sizeof(interrupt_) == sizeof(uint32_t), "Assumed by JIT callers"); + return &interrupt_; + } + + // Set when handling a segfault in the wasm signal handler. + bool handlingSegFault; + + private: + // Set when we're handling an interrupt of JIT/wasm code in + // InterruptRunningJitCode. + mozilla::Atomic<bool> handlingJitInterrupt_; + + public: + bool startHandlingJitInterrupt() { + // Return true if we changed handlingJitInterrupt_ from + // false to true. + return handlingJitInterrupt_.compareExchange(false, true); + } + void finishHandlingJitInterrupt() { + MOZ_ASSERT(handlingJitInterrupt_); + handlingJitInterrupt_ = false; + } + bool handlingJitInterrupt() const { + return handlingJitInterrupt_; + } + + using InterruptCallbackVector = js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>; + InterruptCallbackVector interruptCallbacks; + bool interruptCallbackDisabled; + + JSGetIncumbentGlobalCallback getIncumbentGlobalCallback; + JSEnqueuePromiseJobCallback enqueuePromiseJobCallback; + void* enqueuePromiseJobCallbackData; + + JSPromiseRejectionTrackerCallback promiseRejectionTrackerCallback; + void* promiseRejectionTrackerCallbackData; + + JS::StartAsyncTaskCallback startAsyncTaskCallback; + JS::FinishAsyncTaskCallback finishAsyncTaskCallback; + js::ExclusiveData<js::PromiseTaskPtrVector> promiseTasksToDestroy; + + private: + /* + * Lock taken when using per-runtime or per-zone data that could otherwise + * be accessed simultaneously by both the main thread and another thread + * with an ExclusiveContext. + * + * Locking this only occurs if there is actually a thread other than the + * main thread with an ExclusiveContext which could access such data. + */ + js::Mutex exclusiveAccessLock; +#ifdef DEBUG + bool mainThreadHasExclusiveAccess; +#endif + + /* Number of non-main threads with an ExclusiveContext. */ + size_t numExclusiveThreads; + + friend class js::AutoLockForExclusiveAccess; + + public: + void setUsedByExclusiveThread(JS::Zone* zone); + void clearUsedByExclusiveThread(JS::Zone* zone); + + bool exclusiveThreadsPresent() const { + return numExclusiveThreads > 0; + } + + // How many compartments there are across all zones. This number includes + // ExclusiveContext compartments, so it isn't necessarily equal to the + // number of compartments visited by CompartmentsIter. + size_t numCompartments; + + /* Locale-specific callbacks for string conversion. */ + const JSLocaleCallbacks* localeCallbacks; + + /* Default locale for Internationalization API */ + char* defaultLocale; + + /* Default JSVersion. */ + JSVersion defaultVersion_; + + /* Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics object */ + js::FutexRuntime fx; + + private: + /* See comment for JS_AbortIfWrongThread in jsapi.h. */ + js::Thread::Id ownerThread_; + size_t ownerThreadNative_; + friend bool js::CurrentThreadCanAccessRuntime(const JSRuntime* rt); + public: + + size_t ownerThreadNative() const { + return ownerThreadNative_; + } + + /* Temporary arena pool used while compiling and decompiling. */ + static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024; + js::LifoAlloc tempLifoAlloc; + + private: + js::jit::JitRuntime* jitRuntime_; + + /* + * Self-hosting state cloned on demand into other compartments. Shared with the parent + * runtime if there is one. + */ + js::NativeObject* selfHostingGlobal_; + + static js::GlobalObject* + createSelfHostingGlobal(JSContext* cx); + + bool getUnclonedSelfHostedValue(JSContext* cx, js::HandlePropertyName name, + js::MutableHandleValue vp); + JSFunction* getUnclonedSelfHostedFunction(JSContext* cx, js::HandlePropertyName name); + + /* Space for interpreter frames. */ + js::InterpreterStack interpreterStack_; + + js::jit::JitRuntime* createJitRuntime(JSContext* cx); + + public: + js::jit::JitRuntime* getJitRuntime(JSContext* cx) { + return jitRuntime_ ? jitRuntime_ : createJitRuntime(cx); + } + js::jit::JitRuntime* jitRuntime() const { + return jitRuntime_; + } + bool hasJitRuntime() const { + return !!jitRuntime_; + } + js::InterpreterStack& interpreterStack() { + return interpreterStack_; + } + + inline JSContext* unsafeContextFromAnyThread(); + inline JSContext* contextFromMainThread(); + + JSObject* getIncumbentGlobal(JSContext* cx); + bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise, + js::HandleObject incumbentGlobal); + void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise); + void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise); + + private: + // Used to generate random keys for hash tables. + mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomKeyGenerator_; + mozilla::non_crypto::XorShift128PlusRNG& randomKeyGenerator(); + + public: + mozilla::HashCodeScrambler randomHashCodeScrambler(); + mozilla::non_crypto::XorShift128PlusRNG forkRandomKeyGenerator(); + + //------------------------------------------------------------------------- + // Self-hosting support + //------------------------------------------------------------------------- + + bool hasInitializedSelfHosting() const { + return selfHostingGlobal_; + } + + bool initSelfHosting(JSContext* cx); + void finishSelfHosting(); + void markSelfHostingGlobal(JSTracer* trc); + bool isSelfHostingGlobal(JSObject* global) { + return global == selfHostingGlobal_; + } + bool isSelfHostingCompartment(JSCompartment* comp) const; + bool isSelfHostingZone(const JS::Zone* zone) const; + bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName, + js::HandleAtom name, unsigned nargs, + js::HandleObject proto, + 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); + + //------------------------------------------------------------------------- + // 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(); + + /* Shared Intl data for this runtime. */ + js::SharedIntlData sharedIntlData; + + void traceSharedIntlData(JSTracer* trc); + + JSVersion defaultVersion() const { return defaultVersion_; } + void setDefaultVersion(JSVersion v) { defaultVersion_ = v; } + + /* Base address of the native stack for the current thread. */ + const uintptr_t nativeStackBase; + + /* The native stack size limit that runtime should not exceed. */ + size_t nativeStackQuota[js::StackKindCount]; + + /* Compartment destroy callback. */ + JSDestroyCompartmentCallback destroyCompartmentCallback; + + /* Compartment memory reporting callback. */ + JSSizeOfIncludingThisCompartmentCallback sizeOfIncludingThisCompartmentCallback; + + /* Zone destroy callback. */ + JSZoneCallback destroyZoneCallback; + + /* Zone sweep callback. */ + JSZoneCallback sweepZoneCallback; + + /* Call this to get the name of a compartment. */ + JSCompartmentNameCallback compartmentNameCallback; + + js::ActivityCallback activityCallback; + void* activityCallbackArg; + void triggerActivityCallback(bool active); + + /* The request depth for this thread. */ + unsigned requestDepth; + +#ifdef DEBUG + unsigned checkRequestDepth; +#endif + + /* Garbage collector state, used by jsgc.c. */ + js::gc::GCRuntime gc; + + /* Garbage collector state has been successfully initialized. */ + bool gcInitialized; + + bool hasZealMode(js::gc::ZealMode mode) { return gc.hasZealMode(mode); } + + void lockGC() { + gc.lockGC(); + } + + void unlockGC() { + gc.unlockGC(); + } + +#ifdef JS_SIMULATOR + js::jit::Simulator* simulator_; +#endif + + public: +#ifdef JS_SIMULATOR + js::jit::Simulator* simulator() const; + uintptr_t* addressOfSimulatorStackLimit(); +#endif + + /* Strong references on scripts held for PCCount profiling API. */ + JS::PersistentRooted<js::ScriptAndCountsVector>* scriptAndCountsVector; + + /* Code coverage output. */ + js::coverage::LCovRuntime lcovOutput; + + /* Well-known numbers. */ + const js::Value NaNValue; + const js::Value negativeInfinityValue; + const js::Value positiveInfinityValue; + + js::PropertyName* emptyString; + + mozilla::UniquePtr<js::SourceHook> sourceHook; + + /* SPS profiling metadata */ + js::SPSProfiler spsProfiler; + + /* If true, new scripts must be created with PC counter information. */ + bool profilingScripts; + + /* Whether sampling should be enabled or not. */ + private: + mozilla::Atomic<bool, mozilla::SequentiallyConsistent> suppressProfilerSampling; + + public: + bool isProfilerSamplingEnabled() const { + return !suppressProfilerSampling; + } + void disableProfilerSampling() { + suppressProfilerSampling = true; + } + void enableProfilerSampling() { + suppressProfilerSampling = false; + } + + /* Had an out-of-memory error which did not populate an exception. */ + bool hadOutOfMemory; + +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + /* We are currently running a simulated OOM test. */ + bool runningOOMTest; +#endif + + /* + * Allow relazifying functions in compartments that are active. This is + * only used by the relazifyFunctions() testing function. + */ + bool allowRelazificationForTesting; + + /* Linked list of all Debugger objects in the runtime. */ + mozilla::LinkedList<js::Debugger> debuggerList; + + /* + * Head of circular list of all enabled Debuggers that have + * onNewGlobalObject handler methods established. + */ + JSCList onNewGlobalObjectWatchers; + +#if defined(XP_DARWIN) + js::wasm::MachExceptionHandler wasmMachExceptionHandler; +#endif + + private: + js::FreeOp* defaultFreeOp_; + + public: + js::FreeOp* defaultFreeOp() { + MOZ_ASSERT(defaultFreeOp_); + return defaultFreeOp_; + } + + uint32_t debuggerMutations; + + const JSSecurityCallbacks* securityCallbacks; + const js::DOMCallbacks* DOMcallbacks; + JSDestroyPrincipalsOp destroyPrincipals; + JSReadPrincipalsOp readPrincipals; + + /* Optional warning reporter. */ + JS::WarningReporter warningReporter; + + JS::BuildIdOp buildIdOp; + + /* AsmJSCache callbacks are runtime-wide. */ + JS::AsmJSCacheOps asmJSCacheOps; + + /* + * The propertyRemovals counter is incremented for every JSObject::clear, + * and for each JSObject::remove method call that frees a slot in the given + * object. See js_NativeGet and js_NativeSet in jsobj.cpp. + */ + uint32_t propertyRemovals; + +#if !EXPOSE_INTL_API + /* Number localization, used by jsnum.cpp. */ + const char* thousandsSeparator; + const char* decimalSeparator; + 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_; + } + + // Count of AutoKeepAtoms instances on the main thread's stack. When any + // instances exist, atoms in the runtime will not be collected. Threads + // with an ExclusiveContext do not increment this value, but the presence + // of any such threads also inhibits collection of atoms. We don't scan the + // stacks of exclusive threads, so we need to avoid collecting their + // objects in another way. The only GC thing pointers they have are to + // their exclusive compartment (which is not collected) or to the atoms + // compartment. Therefore, we avoid collecting the atoms compartment when + // exclusive threads are running. + private: + unsigned keepAtoms_; + friend class js::AutoKeepAtoms; + public: + bool keepAtoms() { + return keepAtoms_ != 0 || exclusiveThreadsPresent(); + } + + private: + const JSPrincipals* trustedPrincipals_; + public: + void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; } + const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; } + + private: + bool beingDestroyed_; + public: + bool isBeingDestroyed() const { + return beingDestroyed_; + } + + private: + // Set of all atoms other than those in permanentAtoms and staticStrings. + // Reading or writing this set requires the calling thread to have an + // ExclusiveContext and hold a lock. Use AutoLockForExclusiveAccess. + js::AtomSet* atoms_; + + // Compartment and associated zone containing all atoms in the runtime, as + // well as runtime wide IonCode stubs. Modifying the contents of this + // compartment requires the calling thread to have an ExclusiveContext and + // hold a lock. Use AutoLockForExclusiveAccess. + JSCompartment* atomsCompartment_; + + // Set of all live symbols produced by Symbol.for(). All such symbols are + // allocated in the atomsCompartment. Reading or writing the symbol + // registry requires the calling thread to have an ExclusiveContext and + // hold a lock. Use AutoLockForExclusiveAccess. + js::SymbolRegistry symbolRegistry_; + + public: + bool initializeAtoms(JSContext* cx); + void finishAtoms(); + bool atomsAreFinished() const { return !atoms_; } + + void sweepAtoms(); + + js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) { + return *atoms_; + } + JSCompartment* atomsCompartment(js::AutoLockForExclusiveAccess& lock) { + return atomsCompartment_; + } + + bool isAtomsCompartment(JSCompartment* comp) { + return comp == atomsCompartment_; + } + + // The atoms compartment is the only one in its zone. + inline bool isAtomsZone(const JS::Zone* zone) const; + + bool activeGCInAtomsZone(); + + js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) { + return symbolRegistry_; + } + + // 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::StaticStrings* staticStrings; + + // Cached pointers to various permanent property names. + JSAtomState* commonNames; + + // All permanent atoms in the runtime, other than those in staticStrings. + // Unlike |atoms_|, access to this does not require + // AutoLockForExclusiveAccess because it is frozen and thus read-only. + js::FrozenAtomSet* permanentAtoms; + + bool transformToPermanentAtoms(JSContext* cx); + + // Cached well-known symbols (ES6 rev 24 6.1.5.1). Like permanent atoms, + // these are shared with the parentRuntime, if any. + js::WellKnownSymbols* wellKnownSymbols; + + const JSWrapObjectCallbacks* wrapObjectCallbacks; + js::PreserveWrapperCallback preserveWrapperCallback; + + // Table of bytecode and other data that may be shared across scripts + // within the runtime. This may be modified by threads with an + // ExclusiveContext and requires a lock. + private: + js::ScriptDataTable scriptDataTable_; + public: + js::ScriptDataTable& scriptDataTable(js::AutoLockForExclusiveAccess& lock) { + return scriptDataTable_; + } + + bool jitSupportsFloatingPoint; + bool jitSupportsUnalignedAccesses; + bool jitSupportsSimd; + + // Cache for jit::GetPcScript(). + js::jit::PcScriptCache* ionPcScriptCache; + + js::ScriptEnvironmentPreparer* scriptEnvironmentPreparer; + + js::CTypesActivityCallback ctypesActivityCallback; + + private: + static mozilla::Atomic<size_t> liveRuntimesCount; + + public: + static bool hasLiveRuntimes() { + return liveRuntimesCount > 0; + } + + protected: + explicit JSRuntime(JSRuntime* parentRuntime); + + // 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(uint32_t maxbytes, uint32_t maxNurseryBytes); + + JSRuntime* thisFromCtor() { return this; } + + public: + /* + * Call this after allocating memory held by GC things, to update memory + * pressure counters or report the OOM error if necessary. If oomError and + * cx is not null the function also reports OOM error. + * + * The function must be called outside the GC lock and in case of OOM error + * the caller must ensure that no deadlock possible during OOM reporting. + */ + void updateMallocCounter(size_t nbytes); + void updateMallocCounter(JS::Zone* zone, size_t nbytes); + + 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, size_t nbytes, + void* reallocPtr = nullptr, JSContext* maybecx = nullptr); + + /* onOutOfMemory but can call the largeAllocationFailureCallback. */ + JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes, + void* reallocPtr = nullptr); + + void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* runtime); + + private: + const js::Class* windowProxyClass_; + + // Settings for how helper threads can be used. + bool offthreadIonCompilationEnabled_; + bool parallelParsingEnabled_; + + 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_; + } + + void toggleAutoWritableJitCodeActive(bool b) { + MOZ_ASSERT(autoWritableJitCodeActive_ != b, "AutoWritableJitCode should not be nested."); + MOZ_ASSERT(CurrentThreadCanAccessRuntime(this)); + autoWritableJitCodeActive_ = b; + } + + const js::Class* maybeWindowProxyClass() const { + return windowProxyClass_; + } + void setWindowProxyClass(const js::Class* clasp) { + windowProxyClass_ = clasp; + } + +#ifdef DEBUG + public: + js::AutoEnterPolicy* enteredPolicy; +#endif + + /* See comment for JS::SetLargeAllocationFailureCallback in jsapi.h. */ + JS::LargeAllocationFailureCallback largeAllocationFailureCallback; + void* largeAllocationFailureCallbackData; + + /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */ + JS::OutOfMemoryCallback oomCallback; + void* oomCallbackData; + + /* + * These variations of malloc/calloc/realloc will call the + * large-allocation-failure callback on OOM and retry the allocation. + */ + + static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024; + + template <typename T> + T* pod_callocCanGC(size_t numElems) { + T* p = pod_calloc<T>(numElems); + if (MOZ_LIKELY(!!p)) + return p; + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) { + reportAllocationOverflow(); + return nullptr; + } + return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes)); + } + + template <typename T> + T* pod_reallocCanGC(T* p, size_t oldSize, size_t newSize) { + T* p2 = pod_realloc<T>(p, oldSize, newSize); + if (MOZ_LIKELY(!!p2)) + return p2; + size_t bytes; + if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) { + reportAllocationOverflow(); + return nullptr; + } + return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes, p)); + } + + /* + * Debugger.Memory functions like takeCensus use this embedding-provided + * function to assess the size of malloc'd blocks of memory. + */ + mozilla::MallocSizeOf debuggerMallocSizeOf; + + /* Last time at which an animation was played for this runtime. */ + int64_t lastAnimationTime; + + public: + js::PerformanceMonitoring performanceMonitoring; + + private: + /* List of Ion compilation waiting to get linked. */ + typedef mozilla::LinkedList<js::jit::IonBuilder> IonBuilderList; + + IonBuilderList ionLazyLinkList_; + size_t ionLazyLinkListSize_; + + public: + IonBuilderList& ionLazyLinkList(); + + size_t ionLazyLinkListSize() { + return ionLazyLinkListSize_; + } + + void ionLazyLinkListRemove(js::jit::IonBuilder* builder); + void ionLazyLinkListAdd(js::jit::IonBuilder* builder); + + 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; + } + + // For inherited heap state accessors. + friend class js::gc::AutoTraceSession; + friend class JS::AutoEnterCycleCollection; +}; + +namespace js { + +static inline JSContext* +GetJSContextFromMainThread() +{ + return js::TlsPerThreadData.get()->contextFromMainThread(); +} + +/* + * Flags accompany script version data so that a) dynamically created scripts + * can inherit their caller's compile-time properties and b) scripts can be + * appropriately compared in the eval cache across global option changes. An + * example of the latter is enabling the top-level-anonymous-function-is-error + * option: subsequent evals of the same, previously-valid script text may have + * become invalid. + */ +namespace VersionFlags { +static const unsigned MASK = 0x0FFF; /* see JSVersion in jspubtd.h */ +} /* namespace VersionFlags */ + +static inline JSVersion +VersionNumber(JSVersion version) +{ + return JSVersion(uint32_t(version) & VersionFlags::MASK); +} + +static inline JSVersion +VersionExtractFlags(JSVersion version) +{ + return JSVersion(uint32_t(version) & ~VersionFlags::MASK); +} + +static inline void +VersionCopyFlags(JSVersion* version, JSVersion from) +{ + *version = JSVersion(VersionNumber(*version) | VersionExtractFlags(from)); +} + +static inline bool +VersionHasFlags(JSVersion version) +{ + return !!VersionExtractFlags(version); +} + +static inline bool +VersionIsKnown(JSVersion version) +{ + return VersionNumber(version) != JSVERSION_UNKNOWN; +} + +inline void +FreeOp::free_(void* p) +{ + js_free(p); +} + +inline void +FreeOp::freeLater(void* p) +{ + // FreeOps other than the defaultFreeOp() are constructed on the stack, + // and won't hold onto the pointers to free indefinitely. + MOZ_ASSERT(!isDefaultFreeOp()); + + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!freeLaterList.append(p)) + oomUnsafe.crash("FreeOp::freeLater"); +} + +inline bool +FreeOp::appendJitPoisonRange(const jit::JitPoisonRange& range) +{ + // FreeOps other than the defaultFreeOp() are constructed on the stack, + // and won't hold onto the pointers to free indefinitely. + MOZ_ASSERT(!isDefaultFreeOp()); + + return jitPoisonRanges.append(range); +} + +/* + * RAII class that takes the GC lock while it is live. + * + * Note that the lock may be temporarily released by use of AutoUnlockGC when + * passed a non-const reference to this class. + */ +class MOZ_RAII AutoLockGC +{ + public: + explicit AutoLockGC(JSRuntime* rt + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : runtime_(rt) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + lock(); + } + + ~AutoLockGC() { + unlock(); + } + + void lock() { + MOZ_ASSERT(lockGuard_.isNothing()); + lockGuard_.emplace(runtime_->gc.lock); + } + + void unlock() { + MOZ_ASSERT(lockGuard_.isSome()); + lockGuard_.reset(); + } + + js::LockGuard<js::Mutex>& guard() { + return lockGuard_.ref(); + } + + private: + JSRuntime* runtime_; + mozilla::Maybe<js::LockGuard<js::Mutex>> lockGuard_; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + AutoLockGC(const AutoLockGC&) = delete; + AutoLockGC& operator=(const AutoLockGC&) = delete; +}; + +class MOZ_RAII AutoUnlockGC +{ + public: + explicit AutoUnlockGC(AutoLockGC& lock + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : lock(lock) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + lock.unlock(); + } + + ~AutoUnlockGC() { + lock.lock(); + } + + private: + AutoLockGC& lock; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + AutoUnlockGC(const AutoUnlockGC&) = delete; + AutoUnlockGC& operator=(const AutoUnlockGC&) = delete; +}; + +class MOZ_RAII AutoKeepAtoms +{ + PerThreadData* pt; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + + public: + explicit AutoKeepAtoms(PerThreadData* pt + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : pt(pt) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (JSRuntime* rt = pt->runtimeIfOnOwnerThread()) { + rt->keepAtoms_++; + } else { + // This should be a thread with an exclusive context, which will + // always inhibit collection of atoms. + MOZ_ASSERT(pt->exclusiveThreadsPresent()); + } + } + ~AutoKeepAtoms() { + if (JSRuntime* rt = pt->runtimeIfOnOwnerThread()) { + MOZ_ASSERT(rt->keepAtoms_); + rt->keepAtoms_--; + if (rt->gc.fullGCForAtomsRequested() && !rt->keepAtoms()) + rt->gc.triggerFullGCForAtoms(); + } + } +}; + +inline JSRuntime* +PerThreadData::runtimeFromMainThread() +{ + MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_)); + return runtime_; +} + +inline JSRuntime* +PerThreadData::runtimeIfOnOwnerThread() +{ + return (runtime_ && CurrentThreadCanAccessRuntime(runtime_)) ? runtime_ : nullptr; +} + +inline bool +PerThreadData::exclusiveThreadsPresent() +{ + return runtime_->exclusiveThreadsPresent(); +} + +/************************************************************************/ + +static MOZ_ALWAYS_INLINE void +MakeRangeGCSafe(Value* vec, size_t len) +{ + mozilla::PodZero(vec, len); +} + +static MOZ_ALWAYS_INLINE void +MakeRangeGCSafe(Value* beg, Value* end) +{ + mozilla::PodZero(beg, end - beg); +} + +static MOZ_ALWAYS_INLINE void +MakeRangeGCSafe(jsid* beg, jsid* end) +{ + for (jsid* id = beg; id != end; ++id) + *id = 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) +{ + mozilla::PodZero(beg, end - beg); +} + +static MOZ_ALWAYS_INLINE void +MakeRangeGCSafe(Shape** vec, size_t len) +{ + mozilla::PodZero(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); +} + +/* + * Allocation policy that uses JSRuntime::pod_malloc and friends, so that + * memory pressure is properly accounted for. This is suitable for + * long-lived objects owned by the JSRuntime. + * + * Since it doesn't hold a JSContext (those may not live long enough), it + * can't report out-of-memory conditions itself; the caller must check for + * OOM and take the appropriate action. + * + * FIXME bug 647103 - replace these *AllocPolicy names. + */ +class RuntimeAllocPolicy +{ + JSRuntime* const runtime; + + public: + MOZ_IMPLICIT RuntimeAllocPolicy(JSRuntime* rt) : runtime(rt) {} + + template <typename T> + T* maybe_pod_malloc(size_t numElems) { + return runtime->maybe_pod_malloc<T>(numElems); + } + + template <typename T> + T* maybe_pod_calloc(size_t numElems) { + return runtime->maybe_pod_calloc<T>(numElems); + } + + template <typename T> + T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) { + return runtime->maybe_pod_realloc<T>(p, oldSize, newSize); + } + + template <typename T> + T* pod_malloc(size_t numElems) { + return runtime->pod_malloc<T>(numElems); + } + + template <typename T> + T* pod_calloc(size_t numElems) { + return runtime->pod_calloc<T>(numElems); + } + + template <typename T> + T* pod_realloc(T* p, size_t oldSize, size_t newSize) { + return runtime->pod_realloc<T>(p, oldSize, newSize); + } + + void free_(void* p) { js_free(p); } + void reportAllocOverflow() const {} + + bool checkSimulatedOOM() const { + return !js::oom::ShouldFailWithOOM(); + } +}; + +extern const JSSecurityCallbacks NullSecurityCallbacks; + +// Debugging RAII class which marks the current thread as performing an Ion +// compilation, for use by CurrentThreadCan{Read,Write}CompilationData +class MOZ_RAII AutoEnterIonCompilation +{ + public: + explicit AutoEnterIonCompilation(bool safeForMinorGC + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + +#ifdef DEBUG + PerThreadData* pt = js::TlsPerThreadData.get(); + MOZ_ASSERT(!pt->ionCompiling); + MOZ_ASSERT(!pt->ionCompilingSafeForMinorGC); + pt->ionCompiling = true; + pt->ionCompilingSafeForMinorGC = safeForMinorGC; +#endif + } + + ~AutoEnterIonCompilation() { +#ifdef DEBUG + PerThreadData* pt = js::TlsPerThreadData.get(); + MOZ_ASSERT(pt->ionCompiling); + pt->ionCompiling = false; + pt->ionCompilingSafeForMinorGC = false; +#endif + } + + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +namespace gc { + +// In debug builds, set/unset the performing GC flag for the current thread. +struct MOZ_RAII AutoSetThreadIsPerformingGC +{ +#ifdef DEBUG + AutoSetThreadIsPerformingGC() + : threadData_(js::TlsPerThreadData.get()) + { + MOZ_ASSERT(!threadData_->performingGC); + threadData_->performingGC = true; + } + + ~AutoSetThreadIsPerformingGC() { + MOZ_ASSERT(threadData_->performingGC); + threadData_->performingGC = false; + } + + private: + PerThreadData* threadData_; +#else + AutoSetThreadIsPerformingGC() {} +#endif +}; + +// In debug builds, set/unset the GC sweeping flag for the current thread. +struct MOZ_RAII AutoSetThreadIsSweeping +{ +#ifdef DEBUG + AutoSetThreadIsSweeping() + : threadData_(js::TlsPerThreadData.get()) + { + MOZ_ASSERT(!threadData_->gcSweeping); + threadData_->gcSweeping = true; + } + + ~AutoSetThreadIsSweeping() { + MOZ_ASSERT(threadData_->gcSweeping); + threadData_->gcSweeping = false; + } + + private: + PerThreadData* threadData_; +#else + AutoSetThreadIsSweeping() {} +#endif +}; + +} // namespace gc + +/* + * Provides a delete policy that can be used for objects which have their + * lifetime managed by the GC and can only safely be destroyed while the nursery + * is empty. + * + * This is necessary when initializing such an object may fail after the initial + * allocation. The partially-initialized object must be destroyed, but it may + * not be safe to do so at the current time. This policy puts the object on a + * queue to be destroyed at a safe time. + */ +template <typename T> +struct GCManagedDeletePolicy +{ + void operator()(const T* ptr) { + if (ptr) { + JSRuntime* rt = TlsPerThreadData.get()->runtimeIfOnOwnerThread(); + if (rt && rt->gc.nursery.isEnabled()) { + // The object may contain nursery pointers and must only be + // destroyed after a minor GC. + rt->gc.callAfterMinorGC(deletePtr, const_cast<T*>(ptr)); + } else { + // The object cannot contain nursery pointers so can be + // destroyed immediately. + gc::AutoSetThreadIsSweeping threadIsSweeping; + js_delete(const_cast<T*>(ptr)); + } + } + } + + private: + static void deletePtr(void* data) { + js_delete(reinterpret_cast<T*>(data)); + } +}; + +} /* namespace js */ + +namespace JS { + +template <typename T> +struct DeletePolicy<js::GCPtr<T>> : public js::GCManagedDeletePolicy<js::GCPtr<T>> +{}; + +// Scope data that contain GCPtrs must use the correct DeletePolicy. +// +// This is defined here because vm/Scope.h cannot #include "vm/Runtime.h" + +template <> +struct DeletePolicy<js::FunctionScope::Data> + : public js::GCManagedDeletePolicy<js::FunctionScope::Data> +{ }; + +template <> +struct DeletePolicy<js::ModuleScope::Data> + : public js::GCManagedDeletePolicy<js::ModuleScope::Data> +{ }; + +} /* namespace JS */ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif /* vm_Runtime_h */ |