Mypal/js/src/vm/Runtime.h

1763 lines
53 KiB
C++

/* -*- 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/Scoped.h"
#include "mozilla/ThreadLocal.h"
#include "mozilla/Vector.h"
#include <algorithm>
#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_;
public:
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;
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;
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;
// The implementation-defined abstract operation HostResolveImportedModule.
JS::ModuleResolveHook moduleResolveHook;
};
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)
{
// 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);
}
/*
* 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 */