Bug 1205454 - Consolidate the tagged pointer marking methods; r=sfink

--HG--
extra : rebase_source : 18d7fe3f1f7d652e07c18a6e40b1b88f0e36cef0
This commit is contained in:
Terrence Cole 2015-09-17 10:57:55 -07:00
parent d4c2e2b686
commit 9f3728184b
14 changed files with 92 additions and 158 deletions

View File

@ -245,6 +245,24 @@ operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2)
return !(ptr1 == ptr2);
}
// Unwraps the given GCCellPtr and calls the given functor with a template
// argument of the actual type of the pointer.
template <typename F, typename... Args>
auto
DispatchTyped(F f, GCCellPtr thing, Args&&... args)
-> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
{
switch (thing.kind()) {
#define JS_EXPAND_DEF(name, type, _) \
case JS::TraceKind::name: \
return f(&thing.as<type>(), mozilla::Forward<Args>(args)...);
JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
#undef JS_EXPAND_DEF
default:
MOZ_CRASH("Invalid trace kind in DispatchTyped for GCCellPtr.");
}
}
} /* namespace JS */
namespace js {

View File

@ -178,7 +178,7 @@ template <> struct GCMethods<jsid>
// the pointer. If the jsid is not a GC type, calls F::defaultValue.
template <typename F, typename... Args>
auto
DispatchIdTyped(F f, jsid& id, Args&&... args)
DispatchTyped(F f, jsid& id, Args&&... args)
-> decltype(f(static_cast<JSString*>(nullptr), mozilla::Forward<Args>(args)...))
{
if (JSID_IS_STRING(id))

View File

@ -125,7 +125,7 @@ DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args)
template <typename F, typename... Args>
auto
DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args)
-> decltype(f(reinterpret_cast<JSObject*>(0), mozilla::Forward<Args>(args)...))
-> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
{
switch (traceKind) {
#define JS_EXPAND_DEF(name, type, _) \

View File

@ -1832,7 +1832,7 @@ class PersistentRootedBase<JS::Value> : public MutableValueOperations<JS::Persis
*/
template <typename F, typename... Args>
auto
DispatchValueTyped(F f, const JS::Value& val, Args&&... args)
DispatchTyped(F f, const JS::Value& val, Args&&... args)
-> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
{
if (val.isString())

View File

@ -261,7 +261,7 @@ struct InternalGCMethods<Value>
static bool isMarkableTaggedPointer(Value v) { return isMarkable(v); }
static void preBarrier(Value v) {
DispatchValueTyped(PreBarrierFunctor<Value>(), v);
DispatchTyped(PreBarrierFunctor<Value>(), v);
}
static void postBarrier(Value* vp, const Value& prev, const Value& next) {
@ -286,7 +286,7 @@ struct InternalGCMethods<Value>
}
static void readBarrier(const Value& v) {
DispatchValueTyped(ReadBarrierFunctor<Value>(), v);
DispatchTyped(ReadBarrierFunctor<Value>(), v);
}
};
@ -296,7 +296,7 @@ struct InternalGCMethods<jsid>
static bool isMarkable(jsid id) { return JSID_IS_STRING(id) || JSID_IS_SYMBOL(id); }
static bool isMarkableTaggedPointer(jsid id) { return isMarkable(id); }
static void preBarrier(jsid id) { DispatchIdTyped(PreBarrierFunctor<jsid>(), id); }
static void preBarrier(jsid id) { DispatchTyped(PreBarrierFunctor<jsid>(), id); }
static void postBarrier(jsid* idp, jsid prev, jsid next) {}
};

View File

@ -172,7 +172,7 @@ template <> bool ThingIsPermanentAtomOrWellKnownSymbol<JS::Symbol>(JS::Symbol* s
template<typename T>
void
js::CheckTracedThing(JSTracer* trc, T thing)
js::CheckTracedThing(JSTracer* trc, T* thing)
{
#ifdef DEBUG
MOZ_ASSERT(trc);
@ -242,30 +242,16 @@ struct CheckTracedFunctor : public VoidDefaultAdaptor<S> {
template <typename T> void operator()(T* t, JSTracer* trc) { CheckTracedThing(trc, t); }
};
template<typename T>
void
js::CheckTracedThing(JSTracer* trc, T thing)
{
DispatchTyped(CheckTracedFunctor<T>(), thing, trc);
}
namespace js {
template<>
void
CheckTracedThing<Value>(JSTracer* trc, Value val)
{
DispatchValueTyped(CheckTracedFunctor<Value>(), val, trc);
}
template <>
void
CheckTracedThing<jsid>(JSTracer* trc, jsid id)
{
DispatchIdTyped(CheckTracedFunctor<jsid>(), id, trc);
}
template <>
void
CheckTracedThing<TaggedProto>(JSTracer* trc, TaggedProto proto)
{
DispatchTaggedProtoTyped(CheckTracedFunctor<TaggedProto>(), proto, trc);
}
#define IMPL_CHECK_TRACED_THING(_, type, __) \
template void CheckTracedThing<type*>(JSTracer*, type*);
template void CheckTracedThing<type>(JSTracer*, type*);
JS_FOR_EACH_TRACEKIND(IMPL_CHECK_TRACED_THING);
#undef IMPL_CHECK_TRACED_THING
} // namespace js
@ -427,10 +413,7 @@ JS_FOR_EACH_TRACEKIND(IMPL_BASE_GC_TYPE);
// 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 <> struct PtrBaseGCType<TaggedProto> { typedef TaggedProto type; };
template <typename T> struct PtrBaseGCType { typedef T type; };
template <typename T> struct PtrBaseGCType<T*> { typedef typename BaseGCType<T>::type* type; };
template <typename T>
@ -442,6 +425,7 @@ ConvertToBase(T* thingp)
template <typename T> void DispatchToTracer(JSTracer* trc, T* thingp, const char* name);
template <typename T> T DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name);
template <typename T> void DoMarking(GCMarker* gcmarker, T* thing);
template <typename T> void DoMarking(GCMarker* gcmarker, T thing);
template <typename T>
@ -735,7 +719,7 @@ MustSkipMarking<JS::Symbol*>(JS::Symbol* sym)
template <typename T>
void
DoMarking(GCMarker* gcmarker, T thing)
DoMarking(GCMarker* gcmarker, T* thing)
{
// Do per-type marking precondition checks.
if (MustSkipMarking(thing))
@ -753,26 +737,11 @@ struct DoMarkingFunctor : public VoidDefaultAdaptor<S> {
template <typename T> void operator()(T* t, GCMarker* gcmarker) { DoMarking(gcmarker, t); }
};
template <>
template <typename T>
void
DoMarking<Value>(GCMarker* gcmarker, Value val)
DoMarking(GCMarker* gcmarker, T thing)
{
DispatchValueTyped(DoMarkingFunctor<Value>(), val, gcmarker);
}
template <>
void
DoMarking<jsid>(GCMarker* gcmarker, jsid id)
{
DispatchIdTyped(DoMarkingFunctor<jsid>(), id, gcmarker);
}
template <>
void
DoMarking<TaggedProto>(GCMarker* gcmarker, TaggedProto proto)
{
if (proto.isObject())
DoMarking<JSObject*>(gcmarker, proto.toObject());
DispatchTyped(DoMarkingFunctor<T>(), thing, gcmarker);
}
// The simplest traversal calls out to the fully generic traceChildren function
@ -843,7 +812,7 @@ GCMarker::traverse(AccessorShape* thing) {
template <typename S, typename T>
void
js::GCMarker::traverseEdge(S source, T target)
js::GCMarker::traverseEdge(S source, T* target)
{
// Atoms and Symbols do not have or mark their internal pointers, respectively.
MOZ_ASSERT(!ThingIsPermanentAtomOrWellKnownSymbol(source));
@ -869,18 +838,11 @@ template <typename V, typename S> struct TraverseEdgeFunctor : public VoidDefaul
}
};
template <typename S>
template <typename S, typename T>
void
js::GCMarker::traverseEdge(S source, jsid id)
js::GCMarker::traverseEdge(S source, T thing)
{
DispatchIdTyped(TraverseEdgeFunctor<jsid, S>(), id, this, source);
}
template <typename S>
void
js::GCMarker::traverseEdge(S source, Value v)
{
DispatchValueTyped(TraverseEdgeFunctor<Value, S>(), v, this, source);
DispatchTyped(TraverseEdgeFunctor<T, S>(), thing, this, source);
}
template <typename T>
@ -1897,6 +1859,12 @@ GCMarker::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
/*** Tenuring Tracer *****************************************************************************/
namespace js {
template <typename T>
void
TenuringTracer::traverse(T** tp)
{
}
template <>
void
TenuringTracer::traverse(JSObject** objp)
@ -1908,39 +1876,20 @@ TenuringTracer::traverse(JSObject** objp)
*objp = moveToTenured(*objp);
}
template <>
template <typename S>
struct TenuringTraversalFunctor : public IdentityDefaultAdaptor<S> {
template <typename T> S operator()(T* t, TenuringTracer* trc) {
trc->traverse(&t);
return js::gc::RewrapTaggedPointer<S, T*>::wrap(t);
}
};
template <typename T>
void
TenuringTracer::traverse(Value* valp)
TenuringTracer::traverse(T* thingp)
{
if (!valp->isObject())
return;
JSObject *obj = &valp->toObject();
traverse(&obj);
valp->setObject(*obj);
*thingp = DispatchTyped(TenuringTraversalFunctor<T>(), *thingp, this);
}
template <>
void
TenuringTracer::traverse(TaggedProto* protop)
{
if (!protop->isObject())
return;
JSObject *obj = protop->toObject();
traverse(&obj);
*protop = TaggedProto(obj);
}
template <> void js::TenuringTracer::traverse(js::BaseShape**) {}
template <> void js::TenuringTracer::traverse(js::jit::JitCode**) {}
template <> void js::TenuringTracer::traverse(JSScript**) {}
template <> void js::TenuringTracer::traverse(js::LazyScript**) {}
template <> void js::TenuringTracer::traverse(js::Shape**) {}
template <> void js::TenuringTracer::traverse(JSString**) {}
template <> void js::TenuringTracer::traverse(JS::Symbol**) {}
template <> void js::TenuringTracer::traverse(js::ObjectGroup**) {}
template <> void js::TenuringTracer::traverse(jsid*) {}
} // namespace js
template <typename T>
@ -2310,13 +2259,13 @@ IsMarkedInternalCommon(T* thingp)
template <typename T>
static bool
IsMarkedInternal(T* thingp)
IsMarkedInternal(T** thingp)
{
return IsMarkedInternalCommon(thingp);
}
template <typename T>
static bool
template <>
/* static */ bool
IsMarkedInternal(JSObject** thingp)
{
if (IsInsideNursery(*thingp)) {
@ -2335,39 +2284,21 @@ struct IsMarkedFunctor : public IdentityDefaultAdaptor<S> {
}
};
template <>
bool
IsMarkedInternal<Value>(Value* valuep)
template <typename T>
static bool
IsMarkedInternal(T* thingp)
{
bool rv = true;
*valuep = DispatchValueTyped(IsMarkedFunctor<Value>(), *valuep, &rv);
return rv;
}
template <>
bool
IsMarkedInternal<jsid>(jsid* idp)
{
bool rv = true;
*idp = DispatchIdTyped(IsMarkedFunctor<jsid>(), *idp, &rv);
return rv;
}
template <>
bool
IsMarkedInternal<TaggedProto>(TaggedProto* protop)
{
bool rv = true;
*protop = DispatchTaggedProtoTyped(IsMarkedFunctor<TaggedProto>(), *protop, &rv);
*thingp = DispatchTyped(IsMarkedFunctor<T>(), *thingp, &rv);
return rv;
}
template <typename T>
static bool
IsAboutToBeFinalizedInternal(T* thingp)
IsAboutToBeFinalizedInternal(T** thingp)
{
CheckIsMarkedThing(thingp);
T thing = *thingp;
T* thing = *thingp;
JSRuntime* rt = thing->runtimeFromAnyThread();
/* Permanent atoms are never finalized by non-owning runtimes. */
@ -2404,30 +2335,12 @@ struct IsAboutToBeFinalizedFunctor : public IdentityDefaultAdaptor<S> {
}
};
template <>
bool
IsAboutToBeFinalizedInternal<Value>(Value* valuep)
template <typename T>
static bool
IsAboutToBeFinalizedInternal(T* thingp)
{
bool rv = false;
*valuep = DispatchValueTyped(IsAboutToBeFinalizedFunctor<Value>(), *valuep, &rv);
return rv;
}
template <>
bool
IsAboutToBeFinalizedInternal<jsid>(jsid* idp)
{
bool rv = false;
*idp = DispatchIdTyped(IsAboutToBeFinalizedFunctor<jsid>(), *idp, &rv);
return rv;
}
template <>
bool
IsAboutToBeFinalizedInternal<TaggedProto>(TaggedProto* protop)
{
bool rv = false;
*protop = DispatchTaggedProtoTyped(IsAboutToBeFinalizedFunctor<TaggedProto>(), *protop, &rv);
*thingp = DispatchTyped(IsAboutToBeFinalizedFunctor<T>(), *thingp, &rv);
return rv;
}

View File

@ -183,10 +183,8 @@ class GCMarker : public JSTracer
template <typename T> void traverse(T thing);
// Calls traverse on target after making additional assertions.
template <typename S, typename T> void traverseEdge(S source, T* target);
template <typename S, typename T> void traverseEdge(S source, T target);
// C++ requires explicit declarations of partial template instantiations.
template <typename S> void traverseEdge(S source, jsid target);
template <typename S> void traverseEdge(S source, Value target);
/*
* Care must be taken changing the mark color from gray to black. The cycle
@ -471,6 +469,10 @@ DECLARE_REWRAP(js::TaggedProto, JSObject*, js::TaggedProto, );
bool
UnmarkGrayShapeRecursively(Shape* shape);
template<typename T>
void
CheckTracedThing(JSTracer* trc, T* thing);
template<typename T>
void
CheckTracedThing(JSTracer* trc, T thing);

View File

@ -66,6 +66,7 @@ class TenuringTracer : public JSTracer
const Nursery& nursery() const { return nursery_; }
// Returns true if the pointer was updated.
template <typename T> void traverse(T** thingp);
template <typename T> void traverse(T* thingp);
void insertIntoFixupList(gc::RelocationOverlay* entry);

View File

@ -413,7 +413,7 @@ BufferGrayRootsTracer::onChild(const JS::GCCellPtr& thing)
// objects and scripts. We rely on gray root buffering for this to work,
// but we only need to worry about uncollected dead compartments during
// incremental GCs (when we do gray root buffering).
DispatchTraceKindTyped(SetMaybeAliveFunctor(), tenured, thing.kind());
DispatchTyped(SetMaybeAliveFunctor(), thing);
if (!zone->gcGrayRoots.append(tenured))
bufferingGrayRootsFailed = true;

View File

@ -67,7 +67,7 @@ template <>
Value
DoCallback<Value>(JS::CallbackTracer* trc, Value* vp, const char* name)
{
*vp = DispatchValueTyped(DoCallbackFunctor<Value>(), *vp, trc, name);
*vp = DispatchTyped(DoCallbackFunctor<Value>(), *vp, trc, name);
return *vp;
}
@ -75,7 +75,7 @@ template <>
jsid
DoCallback<jsid>(JS::CallbackTracer* trc, jsid* idp, const char* name)
{
*idp = DispatchIdTyped(DoCallbackFunctor<jsid>(), *idp, trc, name);
*idp = DispatchTyped(DoCallbackFunctor<jsid>(), *idp, trc, name);
return *idp;
}
@ -83,7 +83,7 @@ template <>
TaggedProto
DoCallback<TaggedProto>(JS::CallbackTracer* trc, TaggedProto* protop, const char* name)
{
*protop = DispatchTaggedProtoTyped(DoCallbackFunctor<TaggedProto>(), *protop, trc, name);
*protop = DispatchTyped(DoCallbackFunctor<TaggedProto>(), *protop, trc, name);
return *protop;
}

View File

@ -3763,7 +3763,7 @@ CompartmentCheckTracer::onChild(const JS::GCCellPtr& thing)
{
TenuredCell* tenured = TenuredCell::fromPointer(thing.asCell());
JSCompartment* comp = DispatchTraceKindTyped(MaybeCompartmentFunctor(), tenured, thing.kind());
JSCompartment* comp = DispatchTyped(MaybeCompartmentFunctor(), thing);
if (comp && compartment) {
MOZ_ASSERT(comp == compartment || runtime()->isAtomsCompartment(comp) ||
(srcKind == JS::TraceKind::Object &&
@ -7332,7 +7332,7 @@ JS::IncrementalReferenceBarrier(GCCellPtr thing)
if (!thing)
return;
DispatchTraceKindTyped(IncrementalReferenceBarrierFunctor(), thing.asCell(), thing.kind());
DispatchTyped(IncrementalReferenceBarrierFunctor(), thing);
}
JS_PUBLIC_API(void)

View File

@ -1189,7 +1189,7 @@ struct IsForwardedFunctor : public BoolDefaultAdaptor<Value, false> {
inline bool
IsForwarded(const JS::Value& value)
{
return DispatchValueTyped(IsForwardedFunctor(), value);
return DispatchTyped(IsForwardedFunctor(), value);
}
template <typename T>
@ -1210,7 +1210,7 @@ struct ForwardedFunctor : public IdentityDefaultAdaptor<Value> {
inline Value
Forwarded(const JS::Value& value)
{
return DispatchValueTyped(ForwardedFunctor(), value);
return DispatchTyped(ForwardedFunctor(), value);
}
template <typename T>
@ -1246,7 +1246,7 @@ struct CheckValueAfterMovingGCFunctor : public VoidDefaultAdaptor<Value> {
inline void
CheckValueAfterMovingGC(const JS::Value& value)
{
DispatchValueTyped(CheckValueAfterMovingGCFunctor(), value);
DispatchTyped(CheckValueAfterMovingGCFunctor(), value);
}
#endif // JSGC_HASH_TABLE_CHECKS

View File

@ -104,7 +104,7 @@ class BarrieredBaseMixins<TaggedProto> : public TaggedProtoOperations<HeapPtr<Ta
// with the pointer. If the TaggedProto is lazy, calls F::defaultValue.
template <typename F, typename... Args>
auto
DispatchTaggedProtoTyped(F f, TaggedProto& proto, Args&&... args)
DispatchTyped(F f, TaggedProto& proto, Args&&... args)
-> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
{
if (proto.isObject())

View File

@ -37,7 +37,7 @@
using mozilla::Some;
using mozilla::RangedPtr;
using mozilla::UniquePtr;
using JS::DispatchTraceKindTyped;
using JS::DispatchTyped;
using JS::HandleValue;
using JS::Value;
using JS::ZoneSet;
@ -166,12 +166,12 @@ struct Node::ConstructFunctor : public js::BoolDefaultAdaptor<Value, false> {
Node::Node(const JS::GCCellPtr &thing)
{
DispatchTraceKindTyped(ConstructFunctor(), thing.asCell(), thing.kind(), this);
DispatchTyped(ConstructFunctor(), thing, this);
}
Node::Node(HandleValue value)
{
if (!DispatchValueTyped(ConstructFunctor(), value, this))
if (!DispatchTyped(ConstructFunctor(), value, this))
construct<void>(nullptr);
}