mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1147180 - Introduce a new, strongly-typed tracing path; r=jonco, r=sfink
This commit is contained in:
parent
23e404d42b
commit
b1eef6cb11
@ -119,7 +119,7 @@ class JS_PUBLIC_API(JSTracer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setTracingName(const char* name) {
|
void setTracingName(const char* name) {
|
||||||
setTracingDetails(nullptr, (void*)name, size_t(-1));
|
setTracingDetails(nullptr, (void*)name, InvalidIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the currently set tracing details.
|
// Remove the currently set tracing details.
|
||||||
@ -128,6 +128,8 @@ class JS_PUBLIC_API(JSTracer)
|
|||||||
debugPrintArg_ = nullptr;
|
debugPrintArg_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const static size_t InvalidIndex = size_t(-1);
|
||||||
|
|
||||||
// Return true if tracing details are currently set.
|
// Return true if tracing details are currently set.
|
||||||
bool hasTracingDetails() const;
|
bool hasTracingDetails() const;
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "gc/Marking.h"
|
#include "gc/Marking.h"
|
||||||
|
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
|
#include "mozilla/IntegerRange.h"
|
||||||
|
#include "mozilla/TypeTraits.h"
|
||||||
|
|
||||||
#include "jsprf.h"
|
#include "jsprf.h"
|
||||||
|
|
||||||
@ -31,6 +33,9 @@ using namespace js;
|
|||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
using mozilla::DebugOnly;
|
using mozilla::DebugOnly;
|
||||||
|
using mozilla::IsBaseOf;
|
||||||
|
using mozilla::IsSame;
|
||||||
|
using mozilla::MakeRange;
|
||||||
|
|
||||||
void * const js::NullPtr::constNullValue = nullptr;
|
void * const js::NullPtr::constNullValue = nullptr;
|
||||||
|
|
||||||
@ -147,24 +152,33 @@ AsGCMarker(JSTracer* trc)
|
|||||||
return static_cast<GCMarker*>(trc);
|
return static_cast<GCMarker*>(trc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> bool ThingIsPermanentAtom(T* thing) { return false; }
|
template <typename T> bool ThingIsPermanentAtomOrWellKnownSymbol(T* thing) { return false; }
|
||||||
template <> bool ThingIsPermanentAtom<JSString>(JSString* str) { return str->isPermanentAtom(); }
|
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JSString>(JSString* str) {
|
||||||
template <> bool ThingIsPermanentAtom<JSFlatString>(JSFlatString* str) { return str->isPermanentAtom(); }
|
return str->isPermanentAtom();
|
||||||
template <> bool ThingIsPermanentAtom<JSLinearString>(JSLinearString* str) { return str->isPermanentAtom(); }
|
}
|
||||||
template <> bool ThingIsPermanentAtom<JSAtom>(JSAtom* atom) { return atom->isPermanent(); }
|
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JSFlatString>(JSFlatString* str) {
|
||||||
template <> bool ThingIsPermanentAtom<PropertyName>(PropertyName* name) { return name->isPermanent(); }
|
return str->isPermanentAtom();
|
||||||
template <> bool ThingIsPermanentAtom<JS::Symbol>(JS::Symbol* sym) { return sym->isWellKnownSymbol(); }
|
}
|
||||||
|
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JSLinearString>(JSLinearString* str) {
|
||||||
|
return str->isPermanentAtom();
|
||||||
|
}
|
||||||
|
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JSAtom>(JSAtom* atom) {
|
||||||
|
return atom->isPermanent();
|
||||||
|
}
|
||||||
|
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<PropertyName>(PropertyName* name) {
|
||||||
|
return name->isPermanent();
|
||||||
|
}
|
||||||
|
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JS::Symbol>(JS::Symbol* sym) {
|
||||||
|
return sym->isWellKnownSymbol();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static inline void
|
static inline void
|
||||||
CheckMarkedThing(JSTracer* trc, T** thingp)
|
CheckMarkedThing(JSTracer* trc, T thing)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
MOZ_ASSERT(trc);
|
MOZ_ASSERT(trc);
|
||||||
MOZ_ASSERT(thingp);
|
MOZ_ASSERT(thing);
|
||||||
|
|
||||||
T* thing = *thingp;
|
|
||||||
MOZ_ASSERT(*thingp);
|
|
||||||
|
|
||||||
thing = MaybeForwarded(thing);
|
thing = MaybeForwarded(thing);
|
||||||
|
|
||||||
@ -173,13 +187,13 @@ CheckMarkedThing(JSTracer* trc, T** thingp)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc) && !Nursery::IsMinorCollectionTracer(trc),
|
MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc) && !Nursery::IsMinorCollectionTracer(trc),
|
||||||
!IsForwarded(*thingp));
|
!IsForwarded(thing));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Permanent atoms are not associated with this runtime, but will be ignored
|
* Permanent atoms are not associated with this runtime, but will be ignored
|
||||||
* during marking.
|
* during marking.
|
||||||
*/
|
*/
|
||||||
if (ThingIsPermanentAtom(thing))
|
if (ThingIsPermanentAtomOrWellKnownSymbol(thing))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Zone* zone = thing->zoneFromAnyThread();
|
Zone* zone = thing->zoneFromAnyThread();
|
||||||
@ -189,10 +203,10 @@ CheckMarkedThing(JSTracer* trc, T** thingp)
|
|||||||
MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc), CurrentThreadCanAccessRuntime(rt));
|
MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc), CurrentThreadCanAccessRuntime(rt));
|
||||||
|
|
||||||
MOZ_ASSERT(zone->runtimeFromAnyThread() == trc->runtime());
|
MOZ_ASSERT(zone->runtimeFromAnyThread() == trc->runtime());
|
||||||
MOZ_ASSERT(trc->hasTracingDetails());
|
|
||||||
|
|
||||||
MOZ_ASSERT(thing->isAligned());
|
MOZ_ASSERT(thing->isAligned());
|
||||||
MOZ_ASSERT(MapTypeToTraceKind<T>::kind == GetGCThingTraceKind(thing));
|
MOZ_ASSERT(MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind ==
|
||||||
|
GetGCThingTraceKind(thing));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do not check IsMarkingTracer directly -- it should only be used in paths
|
* Do not check IsMarkingTracer directly -- it should only be used in paths
|
||||||
@ -226,6 +240,37 @@ CheckMarkedThing(JSTracer* trc, T** thingp)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
CheckMarkedThing<Value>(JSTracer* trc, Value val)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (val.isString())
|
||||||
|
CheckMarkedThing(trc, val.toString());
|
||||||
|
else if (val.isObject())
|
||||||
|
CheckMarkedThing(trc, &val.toObject());
|
||||||
|
else if (val.isSymbol())
|
||||||
|
CheckMarkedThing(trc, val.toSymbol());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void
|
||||||
|
CheckMarkedThing<jsid>(JSTracer* trc, jsid id)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (JSID_IS_STRING(id))
|
||||||
|
CheckMarkedThing(trc, JSID_TO_STRING(id));
|
||||||
|
else if (JSID_IS_SYMBOL(id))
|
||||||
|
CheckMarkedThing(trc, JSID_TO_SYMBOL(id));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#define JS_ROOT_MARKING_ASSERT(trc) \
|
||||||
|
MOZ_ASSERT_IF(trc->isMarkingTracer(), \
|
||||||
|
trc->runtime()->gc.state() == NO_INCREMENTAL || \
|
||||||
|
trc->runtime()->gc.state() == MARK_ROOTS);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only set the maybeAlive flag for objects and scripts. It's assumed that,
|
* We only set the maybeAlive flag for objects and scripts. It's assumed that,
|
||||||
* if a compartment is alive, then it will have at least some live object or
|
* if a compartment is alive, then it will have at least some live object or
|
||||||
@ -260,12 +305,328 @@ SetMaybeAliveFlag(JSScript* thing)
|
|||||||
thing->compartment()->maybeAlive = true;
|
thing->compartment()->maybeAlive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define FOR_EACH_GC_LAYOUT(D) \
|
||||||
|
D(Object, JSObject) \
|
||||||
|
D(String, JSString) \
|
||||||
|
D(Symbol, JS::Symbol) \
|
||||||
|
D(Script, JSScript) \
|
||||||
|
D(Shape, js::Shape) \
|
||||||
|
D(BaseShape, js::BaseShape) \
|
||||||
|
D(JitCode, js::jit::JitCode) \
|
||||||
|
D(LazyScript, js::LazyScript) \
|
||||||
|
D(ObjectGroup, js::ObjectGroup)
|
||||||
|
|
||||||
|
// A C++ version of JSGCTraceKind
|
||||||
|
enum class TraceKind {
|
||||||
|
#define NAMES(name, _) name,
|
||||||
|
FOR_EACH_GC_LAYOUT(NAMES)
|
||||||
|
#undef NAMES
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FOR_EACH_GC_POINTER_TYPE(D) \
|
||||||
|
D(BaseShape*) \
|
||||||
|
D(UnownedBaseShape*) \
|
||||||
|
D(jit::JitCode*) \
|
||||||
|
D(NativeObject*) \
|
||||||
|
D(ArrayObject*) \
|
||||||
|
D(ArgumentsObject*) \
|
||||||
|
D(ArrayBufferObject*) \
|
||||||
|
D(ArrayBufferObjectMaybeShared*) \
|
||||||
|
D(ArrayBufferViewObject*) \
|
||||||
|
D(DebugScopeObject*) \
|
||||||
|
D(GlobalObject*) \
|
||||||
|
D(JSObject*) \
|
||||||
|
D(JSFunction*) \
|
||||||
|
D(NestedScopeObject*) \
|
||||||
|
D(PlainObject*) \
|
||||||
|
D(SavedFrame*) \
|
||||||
|
D(ScopeObject*) \
|
||||||
|
D(SharedArrayBufferObject*) \
|
||||||
|
D(SharedTypedArrayObject*) \
|
||||||
|
D(JSScript*) \
|
||||||
|
D(LazyScript*) \
|
||||||
|
D(Shape*) \
|
||||||
|
D(JSAtom*) \
|
||||||
|
D(JSString*) \
|
||||||
|
D(JSFlatString*) \
|
||||||
|
D(JSLinearString*) \
|
||||||
|
D(PropertyName*) \
|
||||||
|
D(JS::Symbol*) \
|
||||||
|
D(js::ObjectGroup*) \
|
||||||
|
D(Value) \
|
||||||
|
D(jsid)
|
||||||
|
|
||||||
|
// The second parameter to BaseGCType is derived automatically based on T. The
|
||||||
|
// relation here is that for any T, the TraceKind will automatically,
|
||||||
|
// statically select the correct Cell layout for marking. Below, we instantiate
|
||||||
|
// each override with a declaration of the most derived layout type.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// BaseGCType<T>::type
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
// BaseGCType<JSFunction>::type => JSObject
|
||||||
|
// BaseGCType<UnownedBaseShape>::type => BaseShape
|
||||||
|
// etc.
|
||||||
|
template <typename T,
|
||||||
|
TraceKind = IsBaseOf<JSObject, T>::value ? TraceKind::Object
|
||||||
|
: IsBaseOf<JSString, T>::value ? TraceKind::String
|
||||||
|
: IsBaseOf<JS::Symbol, T>::value ? TraceKind::Symbol
|
||||||
|
: IsBaseOf<JSScript, T>::value ? TraceKind::Script
|
||||||
|
: IsBaseOf<Shape, T>::value ? TraceKind::Shape
|
||||||
|
: IsBaseOf<BaseShape, T>::value ? TraceKind::BaseShape
|
||||||
|
: IsBaseOf<jit::JitCode, T>::value ? TraceKind::JitCode
|
||||||
|
: IsBaseOf<LazyScript, T>::value ? TraceKind::LazyScript
|
||||||
|
: TraceKind::ObjectGroup>
|
||||||
|
struct BaseGCType;
|
||||||
|
#define IMPL_BASE_GC_TYPE(name, type_) \
|
||||||
|
template <typename T> struct BaseGCType<T, TraceKind:: name> { typedef type_ type; };
|
||||||
|
FOR_EACH_GC_LAYOUT(IMPL_BASE_GC_TYPE);
|
||||||
|
#undef IMPL_BASE_GC_TYPE
|
||||||
|
|
||||||
|
// Our barrier templates are parameterized on the pointer types so that we can
|
||||||
|
// share the definitions with Value and jsid. Thus, we need to strip the
|
||||||
|
// pointer before sending the type to BaseGCType and re-add it on the other
|
||||||
|
// side. As such:
|
||||||
|
template <typename T> struct PtrBaseGCType {};
|
||||||
|
template <> struct PtrBaseGCType<Value> { typedef Value type; };
|
||||||
|
template <> struct PtrBaseGCType<jsid> { typedef jsid type; };
|
||||||
|
template <typename T> struct PtrBaseGCType<T*> { typedef typename BaseGCType<T>::type* type; };
|
||||||
|
|
||||||
|
template <typename T> void DispatchToTracer(JSTracer* trc, T* thingp, const char* name, size_t i);
|
||||||
|
template <typename T> void DoTracing(JS::CallbackTracer* trc, T* thingp, const char* name, size_t i);
|
||||||
|
template <typename T> void DoMarking(GCMarker* gcmarker, T thing);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
js::TraceEdge(JSTracer* trc, BarrieredBase<T>* thingp, const char* name)
|
||||||
|
{
|
||||||
|
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp->unsafeGet());
|
||||||
|
DispatchToTracer(trc, layout, name, JSTracer::InvalidIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
||||||
|
{
|
||||||
|
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
|
||||||
|
DispatchToTracer(trc, layout, name, JSTracer::InvalidIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
|
||||||
|
{
|
||||||
|
JS_ROOT_MARKING_ASSERT(trc);
|
||||||
|
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
|
||||||
|
DispatchToTracer(trc, layout, name, JSTracer::InvalidIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
js::TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* thingp, const char* name)
|
||||||
|
{
|
||||||
|
for (auto i : MakeRange(len)) {
|
||||||
|
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(&thingp[i]);
|
||||||
|
DispatchToTracer(trc, layout, name, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
js::TraceRootRange(JSTracer* trc, size_t len, T* thingp, const char* name)
|
||||||
|
{
|
||||||
|
JS_ROOT_MARKING_ASSERT(trc);
|
||||||
|
for (auto i : MakeRange(len)) {
|
||||||
|
auto layout = reinterpret_cast<typename PtrBaseGCType<T>::type*>(&thingp[i]);
|
||||||
|
DispatchToTracer(trc, layout, name, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate a copy of the Tracing templates for each derived type.
|
||||||
|
#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(type) \
|
||||||
|
template void js::TraceEdge<type>(JSTracer*, BarrieredBase<type>*, const char*); \
|
||||||
|
template void js::TraceManuallyBarrieredEdge<type>(JSTracer*, type*, const char*); \
|
||||||
|
template void js::TraceRoot<type>(JSTracer*, type*, const char*); \
|
||||||
|
template void js::TraceRange<type>(JSTracer*, size_t, BarrieredBase<type>*, const char*); \
|
||||||
|
template void js::TraceRootRange<type>(JSTracer*, size_t, type*, const char*);
|
||||||
|
FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
|
||||||
|
#undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
|
||||||
|
|
||||||
|
// This method is responsible for dynamic dispatch to the real tracer
|
||||||
|
// implementation. Consider replacing this choke point with virtual dispatch:
|
||||||
|
// a sufficiently smart C++ compiler may be able to devirtualize some paths.
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
DispatchToTracer(JSTracer* trc, T* thingp, const char* name, size_t i)
|
||||||
|
{
|
||||||
|
#define IS_SAME_TYPE_OR(name, type) mozilla::IsSame<type*, T>::value ||
|
||||||
|
static_assert(
|
||||||
|
FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR)
|
||||||
|
mozilla::IsSame<T, JS::Value>::value ||
|
||||||
|
mozilla::IsSame<T, jsid>::value,
|
||||||
|
"Only the base cell layout types are allowed into marking/tracing internals");
|
||||||
|
#undef IS_SAME_TYPE_OR
|
||||||
|
CheckMarkedThing(trc, *thingp);
|
||||||
|
|
||||||
|
if (trc->isMarkingTracer())
|
||||||
|
return DoMarking(static_cast<GCMarker*>(trc), *thingp);
|
||||||
|
return DoTracing(static_cast<JS::CallbackTracer*>(trc), thingp, name, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline bool
|
||||||
|
MustSkipMarking(T thing)
|
||||||
|
{
|
||||||
|
// Don't mark things outside a zone if we are in a per-zone GC.
|
||||||
|
return !thing->zone()->isGCMarking();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool
|
||||||
|
MustSkipMarking<JSObject*>(JSObject* obj)
|
||||||
|
{
|
||||||
|
// We may mark a Nursery thing outside the context of the
|
||||||
|
// MinorCollectionTracer because of a pre-barrier. The pre-barrier is not
|
||||||
|
// needed in this case because we perform a minor collection before each
|
||||||
|
// incremental slice.
|
||||||
|
if (IsInsideNursery(obj))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Don't mark things outside a zone if we are in a per-zone GC. It is
|
||||||
|
// faster to check our own arena header, which we can do since we know that
|
||||||
|
// the object is tenured.
|
||||||
|
return !TenuredCell::fromPointer(obj)->zone()->isGCMarking();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool
|
||||||
|
MustSkipMarking<JSString*>(JSString* str)
|
||||||
|
{
|
||||||
|
// Don't mark permanent atoms, as they may be associated with another
|
||||||
|
// runtime. Note that PushMarkStack() also checks this, but we need to not
|
||||||
|
// run the isGCMarking test from off-main-thread, so have to check it here
|
||||||
|
// too.
|
||||||
|
return str->isPermanentAtom() ||
|
||||||
|
!str->zone()->isGCMarking();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool
|
||||||
|
MustSkipMarking<JS::Symbol*>(JS::Symbol* sym)
|
||||||
|
{
|
||||||
|
// As for JSString, don't touch a globally owned well-known symbol from
|
||||||
|
// off-main-thread.
|
||||||
|
return sym->isWellKnownSymbol() ||
|
||||||
|
!sym->zone()->isGCMarking();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
DoMarking(GCMarker* gcmarker, T thing)
|
||||||
|
{
|
||||||
|
// Do per-type marking precondition checks.
|
||||||
|
if (MustSkipMarking(thing))
|
||||||
|
return;
|
||||||
|
|
||||||
|
PushMarkStack(gcmarker, thing);
|
||||||
|
|
||||||
|
// Mark the compartment as live.
|
||||||
|
SetMaybeAliveFlag(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void
|
||||||
|
DoMarking<Value>(GCMarker* gcmarker, Value val)
|
||||||
|
{
|
||||||
|
if (val.isString())
|
||||||
|
DoMarking(gcmarker, val.toString());
|
||||||
|
else if (val.isObject())
|
||||||
|
DoMarking(gcmarker, &val.toObject());
|
||||||
|
else if (val.isSymbol())
|
||||||
|
DoMarking(gcmarker, val.toSymbol());
|
||||||
|
else
|
||||||
|
gcmarker->clearTracingDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void
|
||||||
|
DoMarking<jsid>(GCMarker* gcmarker, jsid id)
|
||||||
|
{
|
||||||
|
if (JSID_IS_STRING(id))
|
||||||
|
DoMarking(gcmarker, JSID_TO_STRING(id));
|
||||||
|
else if (JSID_IS_SYMBOL(id))
|
||||||
|
DoMarking(gcmarker, JSID_TO_SYMBOL(id));
|
||||||
|
else
|
||||||
|
gcmarker->clearTracingDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
DoTracing(JS::CallbackTracer* trc, T* thingp, const char* name, size_t i)
|
||||||
|
{
|
||||||
|
JSGCTraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind;
|
||||||
|
trc->setTracingIndex(name, i);
|
||||||
|
trc->invoke((void**)thingp, kind);
|
||||||
|
trc->unsetTracingLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void
|
||||||
|
DoTracing<Value>(JS::CallbackTracer* trc, Value* vp, const char* name, size_t i)
|
||||||
|
{
|
||||||
|
if (vp->isObject()) {
|
||||||
|
JSObject* prior = &vp->toObject();
|
||||||
|
JSObject* obj = prior;
|
||||||
|
DoTracing(trc, &obj, name, i);
|
||||||
|
if (obj != prior)
|
||||||
|
vp->setObjectOrNull(obj);
|
||||||
|
} else if (vp->isString()) {
|
||||||
|
JSString* prior = vp->toString();
|
||||||
|
JSString* str = prior;
|
||||||
|
DoTracing(trc, &str, name, i);
|
||||||
|
if (str != prior)
|
||||||
|
vp->setString(str);
|
||||||
|
} else if (vp->isSymbol()) {
|
||||||
|
JS::Symbol* prior = vp->toSymbol();
|
||||||
|
JS::Symbol* sym = prior;
|
||||||
|
DoTracing(trc, &sym, name, i);
|
||||||
|
if (sym != prior)
|
||||||
|
vp->setSymbol(sym);
|
||||||
|
} else {
|
||||||
|
/* Unset realLocation manually if we do not call MarkInternal. */
|
||||||
|
trc->unsetTracingLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void
|
||||||
|
DoTracing<jsid>(JS::CallbackTracer* trc, jsid* idp, const char* name, size_t i)
|
||||||
|
{
|
||||||
|
if (JSID_IS_STRING(*idp)) {
|
||||||
|
JSString* prior = JSID_TO_STRING(*idp);
|
||||||
|
JSString* str = prior;
|
||||||
|
DoTracing(trc, &str, name, i);
|
||||||
|
if (str != prior)
|
||||||
|
*idp = NON_INTEGER_ATOM_TO_JSID(reinterpret_cast<JSAtom*>(str));
|
||||||
|
} else if (JSID_IS_SYMBOL(*idp)) {
|
||||||
|
JS::Symbol* prior = JSID_TO_SYMBOL(*idp);
|
||||||
|
JS::Symbol* sym = prior;
|
||||||
|
DoTracing(trc, &sym, name, i);
|
||||||
|
if (sym != prior)
|
||||||
|
*idp = SYMBOL_TO_JSID(sym);
|
||||||
|
} else {
|
||||||
|
/* Unset realLocation manually if we do not call MarkInternal. */
|
||||||
|
trc->unsetTracingLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void
|
static void
|
||||||
MarkInternal(JSTracer* trc, T** thingp)
|
MarkInternal(JSTracer* trc, T** thingp)
|
||||||
{
|
{
|
||||||
CheckMarkedThing(trc, thingp);
|
|
||||||
T* thing = *thingp;
|
T* thing = *thingp;
|
||||||
|
CheckMarkedThing(trc, thing);
|
||||||
|
|
||||||
if (trc->isMarkingTracer()) {
|
if (trc->isMarkingTracer()) {
|
||||||
/*
|
/*
|
||||||
@ -282,7 +643,7 @@ MarkInternal(JSTracer* trc, T** thingp)
|
|||||||
* runtime. Note that PushMarkStack() also checks this, but the tests
|
* runtime. Note that PushMarkStack() also checks this, but the tests
|
||||||
* and maybeAlive write below should only be done on the main thread.
|
* and maybeAlive write below should only be done on the main thread.
|
||||||
*/
|
*/
|
||||||
if (ThingIsPermanentAtom(thing))
|
if (ThingIsPermanentAtomOrWellKnownSymbol(thing))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -302,11 +663,6 @@ MarkInternal(JSTracer* trc, T** thingp)
|
|||||||
trc->clearTracingDetails();
|
trc->clearTracingDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define JS_ROOT_MARKING_ASSERT(trc) \
|
|
||||||
MOZ_ASSERT_IF(trc->isMarkingTracer(), \
|
|
||||||
trc->runtime()->gc.state() == NO_INCREMENTAL || \
|
|
||||||
trc->runtime()->gc.state() == MARK_ROOTS);
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
namespace gc {
|
namespace gc {
|
||||||
|
|
||||||
@ -333,7 +689,7 @@ MarkPermanentAtom(JSTracer* trc, JSAtom* atom, const char* name)
|
|||||||
|
|
||||||
MOZ_ASSERT(atom->isPermanent());
|
MOZ_ASSERT(atom->isPermanent());
|
||||||
|
|
||||||
CheckMarkedThing(trc, &atom);
|
CheckMarkedThing(trc, atom);
|
||||||
|
|
||||||
if (trc->isMarkingTracer()) {
|
if (trc->isMarkingTracer()) {
|
||||||
// Atoms do not refer to other GC things so don't need to go on the mark stack.
|
// Atoms do not refer to other GC things so don't need to go on the mark stack.
|
||||||
@ -358,7 +714,7 @@ MarkWellKnownSymbol(JSTracer* trc, JS::Symbol* sym)
|
|||||||
trc->setTracingName("wellKnownSymbols");
|
trc->setTracingName("wellKnownSymbols");
|
||||||
|
|
||||||
MOZ_ASSERT(sym->isWellKnownSymbol());
|
MOZ_ASSERT(sym->isWellKnownSymbol());
|
||||||
CheckMarkedThing(trc, &sym);
|
CheckMarkedThing(trc, sym);
|
||||||
if (trc->isMarkingTracer()) {
|
if (trc->isMarkingTracer()) {
|
||||||
// Permanent atoms are marked before well-known symbols.
|
// Permanent atoms are marked before well-known symbols.
|
||||||
MOZ_ASSERT(sym->description()->isMarked());
|
MOZ_ASSERT(sym->description()->isMarked());
|
||||||
@ -417,7 +773,7 @@ template <typename T>
|
|||||||
static bool
|
static bool
|
||||||
IsMarked(T** thingp)
|
IsMarked(T** thingp)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT_IF(!ThingIsPermanentAtom(*thingp),
|
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp),
|
||||||
CurrentThreadCanAccessRuntime((*thingp)->runtimeFromMainThread()));
|
CurrentThreadCanAccessRuntime((*thingp)->runtimeFromMainThread()));
|
||||||
return IsMarkedFromAnyThread(thingp);
|
return IsMarkedFromAnyThread(thingp);
|
||||||
}
|
}
|
||||||
@ -447,7 +803,7 @@ template <typename T>
|
|||||||
static bool
|
static bool
|
||||||
IsAboutToBeFinalized(T** thingp)
|
IsAboutToBeFinalized(T** thingp)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT_IF(!ThingIsPermanentAtom(*thingp),
|
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp),
|
||||||
CurrentThreadCanAccessRuntime((*thingp)->runtimeFromMainThread()));
|
CurrentThreadCanAccessRuntime((*thingp)->runtimeFromMainThread()));
|
||||||
return IsAboutToBeFinalizedFromAnyThread(thingp);
|
return IsAboutToBeFinalizedFromAnyThread(thingp);
|
||||||
}
|
}
|
||||||
@ -463,7 +819,7 @@ IsAboutToBeFinalizedFromAnyThread(T** thingp)
|
|||||||
JSRuntime* rt = thing->runtimeFromAnyThread();
|
JSRuntime* rt = thing->runtimeFromAnyThread();
|
||||||
|
|
||||||
/* Permanent atoms are never finalized by non-owning runtimes. */
|
/* Permanent atoms are never finalized by non-owning runtimes. */
|
||||||
if (ThingIsPermanentAtom(thing) && !TlsPerThreadData.get()->associatedWith(rt))
|
if (ThingIsPermanentAtomOrWellKnownSymbol(thing) && !TlsPerThreadData.get()->associatedWith(rt))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Nursery& nursery = rt->gc.nursery;
|
Nursery& nursery = rt->gc.nursery;
|
||||||
|
@ -37,6 +37,28 @@ struct IonScript;
|
|||||||
struct VMFunction;
|
struct VMFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** Tracing ***/
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
TraceEdge(JSTracer* trc, BarrieredBase<T>* thingp, const char* name);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
TraceRoot(JSTracer* trc, T* thingp, const char* name);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* thingp, const char* name);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
TraceRootRange(JSTracer* trc, size_t len, T* thingp, const char* name);
|
||||||
|
|
||||||
namespace gc {
|
namespace gc {
|
||||||
|
|
||||||
/*** Object Marking ***/
|
/*** Object Marking ***/
|
||||||
|
Loading…
Reference in New Issue
Block a user