mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 05:10:49 +00:00
Bug 1135985 - Introduce a new, strongly-typed tracing path; r=jonco, r=sfink
--HG-- extra : rebase_source : c664b207ab859504c66b32cfd4126a67cbf0cafd
This commit is contained in:
parent
6613491227
commit
1ad0c97fed
@ -119,7 +119,7 @@ class JS_PUBLIC_API(JSTracer)
|
||||
}
|
||||
|
||||
void setTracingName(const char *name) {
|
||||
setTracingDetails(nullptr, (void *)name, size_t(-1));
|
||||
setTracingDetails(nullptr, (void *)name, InvalidIndex);
|
||||
}
|
||||
|
||||
// Remove the currently set tracing details.
|
||||
@ -128,6 +128,8 @@ class JS_PUBLIC_API(JSTracer)
|
||||
debugPrintArg_ = nullptr;
|
||||
}
|
||||
|
||||
const static size_t InvalidIndex = size_t(-1);
|
||||
|
||||
// Return true if tracing details are currently set.
|
||||
bool hasTracingDetails() const;
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/IntegerRange.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "jsprf.h"
|
||||
|
||||
@ -31,6 +33,9 @@ using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::IsBaseOf;
|
||||
using mozilla::IsSame;
|
||||
using mozilla::MakeRange;
|
||||
|
||||
void * const js::NullPtr::constNullValue = nullptr;
|
||||
|
||||
@ -147,24 +152,33 @@ AsGCMarker(JSTracer *trc)
|
||||
return static_cast<GCMarker *>(trc);
|
||||
}
|
||||
|
||||
template <typename T> bool ThingIsPermanentAtom(T *thing) { return false; }
|
||||
template <> bool ThingIsPermanentAtom<JSString>(JSString *str) { return str->isPermanentAtom(); }
|
||||
template <> bool ThingIsPermanentAtom<JSFlatString>(JSFlatString *str) { return str->isPermanentAtom(); }
|
||||
template <> bool ThingIsPermanentAtom<JSLinearString>(JSLinearString *str) { return str->isPermanentAtom(); }
|
||||
template <> bool ThingIsPermanentAtom<JSAtom>(JSAtom *atom) { return atom->isPermanent(); }
|
||||
template <> bool ThingIsPermanentAtom<PropertyName>(PropertyName *name) { return name->isPermanent(); }
|
||||
template <> bool ThingIsPermanentAtom<JS::Symbol>(JS::Symbol *sym) { return sym->isWellKnownSymbol(); }
|
||||
template <typename T> bool ThingIsPermanentAtomOrWellKnownSymbol(T *thing) { return false; }
|
||||
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JSString>(JSString *str) {
|
||||
return str->isPermanentAtom();
|
||||
}
|
||||
template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JSFlatString>(JSFlatString *str) {
|
||||
return str->isPermanentAtom();
|
||||
}
|
||||
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>
|
||||
static inline void
|
||||
CheckMarkedThing(JSTracer *trc, T **thingp)
|
||||
CheckMarkedThing(JSTracer *trc, T thing)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(trc);
|
||||
MOZ_ASSERT(thingp);
|
||||
|
||||
T *thing = *thingp;
|
||||
MOZ_ASSERT(*thingp);
|
||||
MOZ_ASSERT(thing);
|
||||
|
||||
thing = MaybeForwarded(thing);
|
||||
|
||||
@ -173,13 +187,13 @@ CheckMarkedThing(JSTracer *trc, T **thingp)
|
||||
return;
|
||||
|
||||
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
|
||||
* during marking.
|
||||
*/
|
||||
if (ThingIsPermanentAtom(thing))
|
||||
if (ThingIsPermanentAtomOrWellKnownSymbol(thing))
|
||||
return;
|
||||
|
||||
Zone *zone = thing->zoneFromAnyThread();
|
||||
@ -189,10 +203,10 @@ CheckMarkedThing(JSTracer *trc, T **thingp)
|
||||
MOZ_ASSERT_IF(!MovingTracer::IsMovingTracer(trc), CurrentThreadCanAccessRuntime(rt));
|
||||
|
||||
MOZ_ASSERT(zone->runtimeFromAnyThread() == trc->runtime());
|
||||
MOZ_ASSERT(trc->hasTracingDetails());
|
||||
|
||||
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
|
||||
@ -226,6 +240,37 @@ CheckMarkedThing(JSTracer *trc, T **thingp)
|
||||
#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,
|
||||
* 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;
|
||||
}
|
||||
|
||||
#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>
|
||||
static void
|
||||
MarkInternal(JSTracer *trc, T **thingp)
|
||||
{
|
||||
CheckMarkedThing(trc, thingp);
|
||||
T *thing = *thingp;
|
||||
CheckMarkedThing(trc, thing);
|
||||
|
||||
if (trc->isMarkingTracer()) {
|
||||
/*
|
||||
@ -282,7 +643,7 @@ MarkInternal(JSTracer *trc, T **thingp)
|
||||
* runtime. Note that PushMarkStack() also checks this, but the tests
|
||||
* and maybeAlive write below should only be done on the main thread.
|
||||
*/
|
||||
if (ThingIsPermanentAtom(thing))
|
||||
if (ThingIsPermanentAtomOrWellKnownSymbol(thing))
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -302,11 +663,6 @@ MarkInternal(JSTracer *trc, T **thingp)
|
||||
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 gc {
|
||||
|
||||
@ -333,7 +689,7 @@ MarkPermanentAtom(JSTracer *trc, JSAtom *atom, const char *name)
|
||||
|
||||
MOZ_ASSERT(atom->isPermanent());
|
||||
|
||||
CheckMarkedThing(trc, &atom);
|
||||
CheckMarkedThing(trc, atom);
|
||||
|
||||
if (trc->isMarkingTracer()) {
|
||||
// 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");
|
||||
|
||||
MOZ_ASSERT(sym->isWellKnownSymbol());
|
||||
CheckMarkedThing(trc, &sym);
|
||||
CheckMarkedThing(trc, sym);
|
||||
if (trc->isMarkingTracer()) {
|
||||
// Permanent atoms are marked before well-known symbols.
|
||||
MOZ_ASSERT(sym->description()->isMarked());
|
||||
@ -417,7 +773,7 @@ template <typename T>
|
||||
static bool
|
||||
IsMarked(T **thingp)
|
||||
{
|
||||
MOZ_ASSERT_IF(!ThingIsPermanentAtom(*thingp),
|
||||
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp),
|
||||
CurrentThreadCanAccessRuntime((*thingp)->runtimeFromMainThread()));
|
||||
return IsMarkedFromAnyThread(thingp);
|
||||
}
|
||||
@ -447,7 +803,7 @@ template <typename T>
|
||||
static bool
|
||||
IsAboutToBeFinalized(T **thingp)
|
||||
{
|
||||
MOZ_ASSERT_IF(!ThingIsPermanentAtom(*thingp),
|
||||
MOZ_ASSERT_IF(!ThingIsPermanentAtomOrWellKnownSymbol(*thingp),
|
||||
CurrentThreadCanAccessRuntime((*thingp)->runtimeFromMainThread()));
|
||||
return IsAboutToBeFinalizedFromAnyThread(thingp);
|
||||
}
|
||||
@ -463,7 +819,7 @@ IsAboutToBeFinalizedFromAnyThread(T **thingp)
|
||||
JSRuntime *rt = thing->runtimeFromAnyThread();
|
||||
|
||||
/* 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;
|
||||
|
||||
Nursery &nursery = rt->gc.nursery;
|
||||
|
@ -37,6 +37,28 @@ struct IonScript;
|
||||
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 {
|
||||
|
||||
/*** Object Marking ***/
|
||||
|
Loading…
x
Reference in New Issue
Block a user