Bug 960342 - Add a RootedGeneric general class, r=terrence

This commit is contained in:
Steve Fink 2014-01-22 11:52:44 -08:00
parent d4180132b8
commit 9f72871624
3 changed files with 63 additions and 0 deletions

View File

@ -917,6 +917,61 @@ class SkipRoot
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/*
* RootedGeneric<T> allows a class to instantiate its own Rooted type by
* including the following two methods:
*
* static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
* void trace(JSTracer *trc);
*
* The trace() method must trace all of the class's fields.
*
* Implementation:
*
* RootedGeneric<T> works by placing a pointer to its 'rooter' field into the
* usual list of rooters when it is instantiated. When marking, it backs up
* from this pointer to find a vtable containing a type-appropriate trace()
* method.
*/
template <typename GCType>
class JS_PUBLIC_API(RootedGeneric)
{
public:
JS::Rooted<GCType> rooter;
SkipRoot skip;
RootedGeneric(js::ContextFriendFields *cx)
: rooter(cx), skip(cx, rooter.address())
{
}
RootedGeneric(js::ContextFriendFields *cx, const GCType &initial)
: rooter(cx, initial), skip(cx, rooter.address())
{
}
virtual inline void trace(JSTracer *trc);
operator const GCType&() const { return rooter.get(); }
GCType operator->() const { return rooter.get(); }
};
template <typename GCType>
inline void RootedGeneric<GCType>::trace(JSTracer *trc)
{
rooter->trace(trc);
}
// We will instantiate RootedGeneric<void*> in RootMarking.cpp, and MSVC will
// notice that void*s have no trace() method defined on them and complain (even
// though it's never called.) MSVC's complaint is not unreasonable, so
// specialize for void*.
template <>
inline void RootedGeneric<void*>::trace(JSTracer *trc)
{
MOZ_ASSUME_UNREACHABLE("RootedGeneric<void*>::trace()");
}
/* Interface substitute for Rooted<T> which does not root the variable's memory. */
template <typename T>
class FakeRooted : public RootedBase<T>

View File

@ -65,6 +65,13 @@ MarkExactStackRoot(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
case THING_ROOT_PROPERTY_ID: MarkIdRoot(trc, &((js::PropertyId *)addr)->asId(), "exact-propertyid"); break;
case THING_ROOT_BINDINGS: ((Bindings *)addr)->trace(trc); break;
case THING_ROOT_PROPERTY_DESCRIPTOR: ((JSPropertyDescriptor *)addr)->trace(trc); break;
case THING_ROOT_CUSTOM: {
// 'rooter' is a member within a class containing a vtable. Back up
// to the vtable and call trace() through it.
const size_t rooterOffset = offsetof(RootedGeneric<void*>, rooter);
reinterpret_cast< RootedGeneric<void*>* >(uintptr_t(rooter) - rooterOffset)->trace(trc);
break;
}
default: MOZ_ASSUME_UNREACHABLE("Invalid THING_ROOT kind"); break;
}
}

View File

@ -310,6 +310,7 @@ enum ThingRootKind
THING_ROOT_TYPE,
THING_ROOT_BINDINGS,
THING_ROOT_PROPERTY_DESCRIPTOR,
THING_ROOT_CUSTOM,
THING_ROOT_LIMIT
};