Changeset View
Changeset View
Standalone View
Standalone View
libraries/source/spidermonkey/include-win32-debug/js/TracingAPI.h
Show All 21 Lines | |||||
/** Returns a static string equivalent of |kind|. */ | /** Returns a static string equivalent of |kind|. */ | ||||
JS_FRIEND_API(const char*) | JS_FRIEND_API(const char*) | ||||
GCTraceKindToAscii(JS::TraceKind kind); | GCTraceKindToAscii(JS::TraceKind kind); | ||||
} // namespace JS | } // namespace JS | ||||
enum WeakMapTraceKind { | enum WeakMapTraceKind { | ||||
/** Do true ephemeron marking with an iterative weak marking phase. */ | /** | ||||
* Do not trace into weak map keys or values during traversal. Users must | |||||
* handle weak maps manually. | |||||
*/ | |||||
DoNotTraceWeakMaps, | DoNotTraceWeakMaps, | ||||
/** | /** | ||||
* Do true ephemeron marking with a weak key lookup marking phase. This is | * Do true ephemeron marking with a weak key lookup marking phase. This is | ||||
* expected to be constant for the lifetime of a JSTracer; it does not | * the default for GCMarker. | ||||
* change when switching from "plain" marking to weak marking. | |||||
*/ | */ | ||||
ExpandWeakMaps, | ExpandWeakMaps, | ||||
/** | /** | ||||
* Trace through to all values, irrespective of whether the keys are live | * Trace through to all values, irrespective of whether the keys are live | ||||
* or not. Used for non-marking tracers. | * or not. Used for non-marking tracers. | ||||
*/ | */ | ||||
TraceWeakMapValues, | TraceWeakMapValues, | ||||
Show All 9 Lines | |||||
{ | { | ||||
public: | public: | ||||
// Return the runtime set on the tracer. | // Return the runtime set on the tracer. | ||||
JSRuntime* runtime() const { return runtime_; } | JSRuntime* runtime() const { return runtime_; } | ||||
// Return the weak map tracing behavior currently set on this tracer. | // Return the weak map tracing behavior currently set on this tracer. | ||||
WeakMapTraceKind weakMapAction() const { return weakMapAction_; } | WeakMapTraceKind weakMapAction() const { return weakMapAction_; } | ||||
// An intermediate state on the road from C to C++ style dispatch. | |||||
enum class TracerKindTag { | enum class TracerKindTag { | ||||
// Marking path: a tracer used only for marking liveness of cells, not | |||||
// for moving them. The kind will transition to WeakMarking after | |||||
// everything reachable by regular edges has been marked. | |||||
Marking, | Marking, | ||||
WeakMarking, // In weak marking phase: looking up every marked obj/script. | |||||
// Same as Marking, except we have now moved on to the "weak marking | |||||
// phase", in which every marked obj/script is immediately looked up to | |||||
// see if it is a weak map key (and therefore might require marking its | |||||
// weak map value). | |||||
WeakMarking, | |||||
// A tracer that traverses the graph for the purposes of moving objects | |||||
// from the nursery to the tenured area. | |||||
Tenuring, | Tenuring, | ||||
// General-purpose traversal that invokes a callback on each cell. | |||||
// Traversing children is the responsibility of the callback. | |||||
Callback | Callback | ||||
}; | }; | ||||
bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; } | bool isMarkingTracer() const { return tag_ == TracerKindTag::Marking || tag_ == TracerKindTag::WeakMarking; } | ||||
bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; } | bool isWeakMarkingTracer() const { return tag_ == TracerKindTag::WeakMarking; } | ||||
bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } | bool isTenuringTracer() const { return tag_ == TracerKindTag::Tenuring; } | ||||
bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } | bool isCallbackTracer() const { return tag_ == TracerKindTag::Callback; } | ||||
inline JS::CallbackTracer* asCallbackTracer(); | inline JS::CallbackTracer* asCallbackTracer(); | ||||
#ifdef DEBUG | |||||
bool checkEdges() { return checkEdges_; } | |||||
#endif | |||||
protected: | protected: | ||||
JSTracer(JSRuntime* rt, TracerKindTag tag, | JSTracer(JSRuntime* rt, TracerKindTag tag, | ||||
WeakMapTraceKind weakTraceKind = TraceWeakMapValues) | WeakMapTraceKind weakTraceKind = TraceWeakMapValues) | ||||
: runtime_(rt), weakMapAction_(weakTraceKind), tag_(tag) | : runtime_(rt) | ||||
, weakMapAction_(weakTraceKind) | |||||
#ifdef DEBUG | |||||
, checkEdges_(true) | |||||
#endif | |||||
, tag_(tag) | |||||
{} | {} | ||||
#ifdef DEBUG | |||||
// Set whether to check edges are valid in debug builds. | |||||
void setCheckEdges(bool check) { | |||||
checkEdges_ = check; | |||||
} | |||||
#endif | |||||
private: | private: | ||||
JSRuntime* runtime_; | JSRuntime* runtime_; | ||||
WeakMapTraceKind weakMapAction_; | WeakMapTraceKind weakMapAction_; | ||||
#ifdef DEBUG | |||||
bool checkEdges_; | |||||
#endif | |||||
protected: | protected: | ||||
TracerKindTag tag_; | TracerKindTag tag_; | ||||
}; | }; | ||||
namespace JS { | namespace JS { | ||||
class AutoTracingName; | class AutoTracingName; | ||||
class AutoTracingIndex; | class AutoTracingIndex; | ||||
class AutoTracingCallback; | class AutoTracingCallback; | ||||
class JS_PUBLIC_API(CallbackTracer) : public JSTracer | class JS_PUBLIC_API(CallbackTracer) : public JSTracer | ||||
{ | { | ||||
public: | public: | ||||
CallbackTracer(JSRuntime* rt, WeakMapTraceKind weakTraceKind = TraceWeakMapValues) | CallbackTracer(JSRuntime* rt, WeakMapTraceKind weakTraceKind = TraceWeakMapValues) | ||||
: JSTracer(rt, JSTracer::TracerKindTag::Callback, weakTraceKind), | : JSTracer(rt, JSTracer::TracerKindTag::Callback, weakTraceKind), | ||||
contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr) | contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr) | ||||
{} | {} | ||||
CallbackTracer(JSContext* cx, WeakMapTraceKind weakTraceKind = TraceWeakMapValues); | |||||
// Override these methods to receive notification when an edge is visited | // Override these methods to receive notification when an edge is visited | ||||
// with the type contained in the callback. The default implementation | // with the type contained in the callback. The default implementation | ||||
// dispatches to the fully-generic onChild implementation, so for cases that | // dispatches to the fully-generic onChild implementation, so for cases that | ||||
// do not care about boxing overhead and do not need the actual edges, | // do not care about boxing overhead and do not need the actual edges, | ||||
// just override the generic onChild. | // just override the generic onChild. | ||||
virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); } | virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); } | ||||
virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); } | virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); } | ||||
Show All 9 Lines | virtual void onBaseShapeEdge(js::BaseShape** basep) { | ||||
onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape)); | onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape)); | ||||
} | } | ||||
virtual void onJitCodeEdge(js::jit::JitCode** codep) { | virtual void onJitCodeEdge(js::jit::JitCode** codep) { | ||||
onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode)); | onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode)); | ||||
} | } | ||||
virtual void onLazyScriptEdge(js::LazyScript** lazyp) { | virtual void onLazyScriptEdge(js::LazyScript** lazyp) { | ||||
onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript)); | onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript)); | ||||
} | } | ||||
virtual void onScopeEdge(js::Scope** scopep) { | |||||
onChild(JS::GCCellPtr(*scopep, JS::TraceKind::Scope)); | |||||
} | |||||
// Override this method to receive notification when a node in the GC | // Override this method to receive notification when a node in the GC | ||||
// heap graph is visited. | // heap graph is visited. | ||||
virtual void onChild(const JS::GCCellPtr& thing) = 0; | virtual void onChild(const JS::GCCellPtr& thing) = 0; | ||||
// Access to the tracing context: | // Access to the tracing context: | ||||
// When tracing with a JS::CallbackTracer, we invoke the callback with the | // When tracing with a JS::CallbackTracer, we invoke the callback with the | ||||
// edge location and the type of target. This is useful for operating on | // edge location and the type of target. This is useful for operating on | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | #endif | ||||
void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); } | void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); } | ||||
void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); } | void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); } | ||||
void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); } | void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); } | ||||
void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); } | void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); } | ||||
void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); } | void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); } | ||||
void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); } | void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); } | ||||
void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); } | void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); } | ||||
void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); } | void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); } | ||||
void dispatchToOnEdge(js::Scope** scopep) { onScopeEdge(scopep); } | |||||
private: | private: | ||||
friend class AutoTracingName; | friend class AutoTracingName; | ||||
const char* contextName_; | const char* contextName_; | ||||
friend class AutoTracingIndex; | friend class AutoTracingIndex; | ||||
size_t contextIndex_; | size_t contextIndex_; | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
JS::CallbackTracer* | JS::CallbackTracer* | ||||
JSTracer::asCallbackTracer() | JSTracer::asCallbackTracer() | ||||
{ | { | ||||
MOZ_ASSERT(isCallbackTracer()); | MOZ_ASSERT(isCallbackTracer()); | ||||
return static_cast<JS::CallbackTracer*>(this); | return static_cast<JS::CallbackTracer*>(this); | ||||
} | } | ||||
// The JS_Call*Tracer family of functions traces the given GC thing reference. | namespace JS { | ||||
// This performs the tracing action configured on the given JSTracer: | |||||
// typically calling the JSTracer::callback or marking the thing as live. | // The JS::TraceEdge family of functions traces the given GC thing reference. | ||||
// This performs the tracing action configured on the given JSTracer: typically | |||||
// calling the JSTracer::callback or marking the thing as live. | |||||
// | // | ||||
// The argument to JS_Call*Tracer is an in-out param: when the function | // The argument to JS::TraceEdge is an in-out param: when the function returns, | ||||
// returns, the garbage collector might have moved the GC thing. In this case, | // the garbage collector might have moved the GC thing. In this case, the | ||||
// the reference passed to JS_Call*Tracer will be updated to the object's new | // reference passed to JS::TraceEdge will be updated to the thing's new | ||||
// location. Callers of this method are responsible for updating any state | // location. Callers of this method are responsible for updating any state that | ||||
// that is dependent on the object's address. For example, if the object's | // is dependent on the object's address. For example, if the object's address | ||||
// address is used as a key in a hashtable, then the object must be removed | // is used as a key in a hashtable, then the object must be removed and | ||||
// and re-inserted with the correct hash. | // re-inserted with the correct hash. | ||||
// | // | ||||
extern JS_PUBLIC_API(void) | // Note that while |edgep| must never be null, it is fine for |*edgep| to be | ||||
JS_CallValueTracer(JSTracer* trc, JS::Heap<JS::Value>* valuep, const char* name); | // nullptr. | ||||
extern JS_PUBLIC_API(void) | |||||
JS_CallIdTracer(JSTracer* trc, JS::Heap<jsid>* idp, const char* name); | |||||
extern JS_PUBLIC_API(void) | |||||
JS_CallObjectTracer(JSTracer* trc, JS::Heap<JSObject*>* objp, const char* name); | |||||
extern JS_PUBLIC_API(void) | |||||
JS_CallStringTracer(JSTracer* trc, JS::Heap<JSString*>* strp, const char* name); | |||||
extern JS_PUBLIC_API(void) | |||||
JS_CallScriptTracer(JSTracer* trc, JS::Heap<JSScript*>* scriptp, const char* name); | |||||
extern JS_PUBLIC_API(void) | |||||
JS_CallFunctionTracer(JSTracer* trc, JS::Heap<JSFunction*>* funp, const char* name); | |||||
namespace JS { | |||||
template <typename T> | template <typename T> | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
TraceEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name); | TraceEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name); | ||||
} // namespace JS | |||||
// The following JS_CallUnbarriered*Tracer functions should only be called where | |||||
// you know for sure that a heap post barrier is not required. Use with extreme | |||||
// caution! | |||||
extern JS_PUBLIC_API(void) | |||||
JS_CallUnbarrieredValueTracer(JSTracer* trc, JS::Value* valuep, const char* name); | |||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
JS_CallUnbarrieredIdTracer(JSTracer* trc, jsid* idp, const char* name); | TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name); | ||||
// Edges that are always traced as part of root marking do not require | |||||
// incremental barriers. This function allows for marking non-barriered | |||||
// pointers, but asserts that this happens during root marking. | |||||
// | |||||
// Note that while |edgep| must never be null, it is fine for |*edgep| to be | |||||
// nullptr. | |||||
template <typename T> | |||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
JS_CallUnbarrieredObjectTracer(JSTracer* trc, JSObject** objp, const char* name); | UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name); | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
JS_CallUnbarrieredStringTracer(JSTracer* trc, JSString** strp, const char* name); | TraceChildren(JSTracer* trc, GCCellPtr thing); | ||||
extern JS_PUBLIC_API(void) | using ZoneSet = js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy>; | ||||
JS_CallUnbarrieredScriptTracer(JSTracer* trc, JSScript** scriptp, const char* name); | using CompartmentSet = js::HashSet<JSCompartment*, js::DefaultHasher<JSCompartment*>, | ||||
js::SystemAllocPolicy>; | |||||
/** | /** | ||||
* Trace an object that is known to always be tenured. No post barriers are | * Trace every value within |compartments| that is wrapped by a | ||||
* required in this case. | * cross-compartment wrapper from a compartment that is not an element of | ||||
* |compartments|. | |||||
*/ | */ | ||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, const char* name); | TraceIncomingCCWs(JSTracer* trc, const JS::CompartmentSet& compartments); | ||||
extern JS_PUBLIC_API(void) | |||||
JS_TraceRuntime(JSTracer* trc); | |||||
namespace JS { | |||||
extern JS_PUBLIC_API(void) | |||||
TraceChildren(JSTracer* trc, GCCellPtr thing); | |||||
typedef js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy> ZoneSet; | |||||
} // namespace JS | } // namespace JS | ||||
/** | |||||
* Trace every value within |zones| that is wrapped by a cross-compartment | |||||
* wrapper from a zone that is not an element of |zones|. | |||||
*/ | |||||
extern JS_PUBLIC_API(void) | |||||
JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones); | |||||
extern JS_PUBLIC_API(void) | extern JS_PUBLIC_API(void) | ||||
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, | JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, | ||||
void* thing, JS::TraceKind kind, bool includeDetails); | void* thing, JS::TraceKind kind, bool includeDetails); | ||||
namespace js { | namespace js { | ||||
namespace gc { | |||||
template <typename T> | |||||
extern JS_PUBLIC_API(bool) | |||||
EdgeNeedsSweep(JS::Heap<T>* edgep); | |||||
} // namespace gc | |||||
// Automates static dispatch for GC interaction with TraceableContainers. | // Trace an edge that is not a GC root and is not wrapped in a barriered | ||||
template <typename> | // wrapper for some reason. | ||||
struct DefaultGCPolicy; | // | ||||
// This method does not check if |*edgep| is non-null before tracing through | |||||
// This policy dispatches GC methods to a method on the type. | // it, so callers must check any nullable pointer before calling this method. | ||||
template <typename T> | template <typename T> | ||||
struct StructGCPolicy { | extern JS_PUBLIC_API(void) | ||||
static void trace(JSTracer* trc, T* t, const char* name) { | UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name); | ||||
// This is the default GC policy for storing GC things in containers. | |||||
// If your build is failing here, it means you either need an | |||||
// implementation of DefaultGCPolicy<T> for your type or, if this is | |||||
// the right policy for you, your struct or container is missing a | |||||
// trace method. | |||||
t->trace(trc); | |||||
} | |||||
static bool needsSweep(T* t) { | |||||
return t->needsSweep(); | |||||
} | |||||
}; | |||||
// This policy ignores any GC interaction, e.g. for non-GC types. | namespace gc { | ||||
template <typename T> | |||||
struct IgnoreGCPolicy { | |||||
static void trace(JSTracer* trc, T* t, const char* name) {} | |||||
static bool needsSweep(T* v) { return false; } | |||||
}; | |||||
// The default policy when no other more specific policy fits (e.g. for a | // Return true if the given edge is not live and is about to be swept. | ||||
// direct GC pointer), is to assume a struct type that implements the needed | |||||
// methods. | |||||
template <typename T> | template <typename T> | ||||
struct DefaultGCPolicy : public StructGCPolicy<T> {}; | extern JS_PUBLIC_API(bool) | ||||
EdgeNeedsSweep(JS::Heap<T>* edgep); | |||||
template <> | |||||
struct DefaultGCPolicy<jsid> | |||||
{ | |||||
static void trace(JSTracer* trc, jsid* id, const char* name) { | |||||
JS_CallUnbarrieredIdTracer(trc, id, name); | |||||
} | |||||
}; | |||||
template <> struct DefaultGCPolicy<uint32_t> : public IgnoreGCPolicy<uint32_t> {}; | |||||
template <> struct DefaultGCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {}; | |||||
// Not part of the public API, but declared here so we can use it in GCPolicy | |||||
// which is. | |||||
template <typename T> | template <typename T> | ||||
struct DefaultGCPolicy<JS::Heap<T>> | bool | ||||
{ | IsAboutToBeFinalizedUnbarriered(T* thingp); | ||||
static void trace(JSTracer* trc, JS::Heap<T>* thingp, const char* name) { | |||||
JS::TraceEdge(trc, thingp, name); | |||||
} | |||||
static bool needsSweep(JS::Heap<T>* thingp) { | |||||
return gc::EdgeNeedsSweep(thingp); | |||||
} | |||||
}; | |||||
} // namespace gc | |||||
} // namespace js | } // namespace js | ||||
#endif /* js_TracingAPI_h */ | #endif /* js_TracingAPI_h */ |
Wildfire Games · Phabricator