Bug 1020690 - Type exact stack rooting machinery. r=sfink

--HG--
extra : rebase_source : 366ff0579912b8a03f29abb882cabcc982a44d47
This commit is contained in:
Jon Coppeard 2014-06-05 10:38:00 -04:00
parent 4a089c98e4
commit 773bc32603
9 changed files with 152 additions and 105 deletions

View File

@ -634,10 +634,16 @@ class InternalHandle<T*>
};
/*
* By default, pointers should use the inheritance hierarchy to find their
* By default, things should use the inheritance hierarchy to find their
* ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that
* Rooted<T> may be used without the class definition being available.
*/
template <typename T>
struct RootKind
{
static ThingRootKind rootKind() { return T::rootKind(); }
};
template <typename T>
struct RootKind<T *>
{
@ -792,7 +798,7 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
#endif
#ifdef JSGC_TRACK_EXACT_ROOTS
Rooted<T> *previous() { return prev; }
Rooted<T> *previous() { return reinterpret_cast<Rooted<T>*>(prev); }
#endif
/*
@ -827,7 +833,12 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
private:
#ifdef JSGC_TRACK_EXACT_ROOTS
Rooted<void*> **stack, *prev;
/*
* These need to be templated on void* to avoid aliasing issues between, for
* example, Rooted<JSObject> and Rooted<JSFunction>, which use the same
* stack head pointer for different classes.
*/
Rooted<void *> **stack, *prev;
#endif
/*
@ -863,61 +874,6 @@ class RootedBase<JSObject*>
JS::Handle<U*> as() const;
};
/*
* 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;
explicit RootedGeneric(js::ContextFriendFields *cx)
: rooter(cx)
{
}
RootedGeneric(js::ContextFriendFields *cx, const GCType &initial)
: rooter(cx, initial)
{
}
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

@ -36,6 +36,7 @@ class JS_PUBLIC_API(AutoGCRooter);
template <typename T> class AutoVectorRooter;
template<typename K, typename V> class AutoHashMapRooter;
template<typename T> class AutoHashSetRooter;
template<typename T> class RootedGeneric;
class MOZ_STACK_CLASS SourceBufferHolder;
@ -83,6 +84,7 @@ using JS::AutoGCRooter;
using JS::AutoHashMapRooter;
using JS::AutoHashSetRooter;
using JS::AutoVectorRooter;
using JS::RootedGeneric;
using JS::CallArgs;
using JS::CallNonGenericMethod;

View File

@ -40,59 +40,82 @@ typedef RootedValueMap::Entry RootEntry;
typedef RootedValueMap::Enum RootEnum;
#ifdef JSGC_USE_EXACT_ROOTING
static inline void
MarkExactStackRoot(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
// Note: the following two functions cannot be static as long as we are using
// GCC 4.4, since it requires template function parameters to have external
// linkage.
void
MarkBindingsRoot(JSTracer *trc, Bindings *bindings, const char *name)
{
void **addr = (void **)rooter->address();
if (IsNullTaggedPointer(*addr))
return;
bindings->trace(trc);
}
if (kind == THING_ROOT_OBJECT && *addr == TaggedProto::LazyProto)
return;
void
MarkPropertyDescriptorRoot(JSTracer *trc, JSPropertyDescriptor *pd, const char *name)
{
pd->trace(trc);
}
switch (kind) {
case THING_ROOT_OBJECT: MarkObjectRoot(trc, (JSObject **)addr, "exact-object"); break;
case THING_ROOT_STRING: MarkStringRoot(trc, (JSString **)addr, "exact-string"); break;
case THING_ROOT_SCRIPT: MarkScriptRoot(trc, (JSScript **)addr, "exact-script"); break;
case THING_ROOT_LAZY_SCRIPT: MarkLazyScriptRoot(trc, (LazyScript **)addr, "exact-lazy-script"); break;
case THING_ROOT_SHAPE: MarkShapeRoot(trc, (Shape **)addr, "exact-shape"); break;
case THING_ROOT_BASE_SHAPE: MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact-baseshape"); break;
case THING_ROOT_TYPE: MarkTypeRoot(trc, (types::Type *)addr, "exact-type"); break;
case THING_ROOT_TYPE_OBJECT: MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact-typeobject"); break;
case THING_ROOT_JIT_CODE: MarkJitCodeRoot(trc, (jit::JitCode **)addr, "exact-jitcode"); break;
case THING_ROOT_VALUE: MarkValueRoot(trc, (Value *)addr, "exact-value"); break;
case THING_ROOT_ID: MarkIdRoot(trc, (jsid *)addr, "exact-id"); 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;
template <class T>
static inline bool
IgnoreExactRoot(T *thingp)
{
return false;
}
template <class T>
inline bool
IgnoreExactRoot(T **thingp)
{
return IsNullTaggedPointer(*thingp);
}
template <>
inline bool
IgnoreExactRoot(JSObject **thingp)
{
return IsNullTaggedPointer(*thingp) || *thingp == TaggedProto::LazyProto;
}
template <class T, void MarkFunc(JSTracer *trc, T *ref, const char *name), class Source>
static inline void
MarkExactStackRootList(JSTracer *trc, Source *s, const char *name)
{
Rooted<T> *rooter = s->template gcRooters<T>();
while (rooter) {
T *addr = rooter->address();
if (!IgnoreExactRoot(addr))
MarkFunc(trc, addr, name);
rooter = rooter->previous();
}
}
template <class T, void (MarkFunc)(JSTracer *trc, T *ref, const char *name)>
static inline void
MarkExactStackRootList(JSTracer *trc, Rooted<void*> *rooter, ThingRootKind kind)
MarkExactStackRootsForType(JSTracer *trc, const char *name = nullptr)
{
while (rooter) {
MarkExactStackRoot(trc, rooter, kind);
rooter = rooter->previous();
}
for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
MarkExactStackRootList<T, MarkFunc>(trc, cx.get(), name);
MarkExactStackRootList<T, MarkFunc>(trc, &trc->runtime()->mainThread, name);
}
static void
MarkExactStackRoots(JSTracer *trc)
{
for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
MarkExactStackRootList(trc, cx->thingGCRooters[i], ThingRootKind(i));
MarkExactStackRootList(trc, trc->runtime()->mainThread.thingGCRooters[i], ThingRootKind(i));
}
MarkExactStackRootsForType<JSObject *, MarkObjectRoot>(trc, "exact-object");
MarkExactStackRootsForType<Shape *, MarkShapeRoot>(trc, "exact-shape");
MarkExactStackRootsForType<BaseShape *, MarkBaseShapeRoot>(trc, "exact-baseshape");
MarkExactStackRootsForType<types::TypeObject *, MarkTypeObjectRoot>(trc, "exact-typeobject");
MarkExactStackRootsForType<JSString *, MarkStringRoot>(trc, "exact-string");
MarkExactStackRootsForType<jit::JitCode *, MarkJitCodeRoot>(trc, "exact-jitcode");
MarkExactStackRootsForType<JSScript *, MarkScriptRoot>(trc, "exact-script");
MarkExactStackRootsForType<LazyScript *, MarkLazyScriptRoot>(trc, "exact-lazy-script");
MarkExactStackRootsForType<jsid, MarkIdRoot>(trc, "exact-id");
MarkExactStackRootsForType<Value, MarkValueRoot>(trc, "exact-value");
MarkExactStackRootsForType<types::Type, MarkTypeRoot>(trc, "exact-type");
MarkExactStackRootsForType<Bindings, MarkBindingsRoot>(trc);
MarkExactStackRootsForType<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(trc);
}
#endif /* JSGC_USE_EXACT_ROOTING */

View File

@ -591,6 +591,43 @@ class JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/*
* RootedGeneric<T> allows a class to instantiate its own Rooted type by
* including the method:
*
* void trace(JSTracer *trc);
*
* The trace() method must trace all of the class's fields.
*/
template <class T>
class RootedGeneric : private CustomAutoRooter
{
public:
template <typename CX>
explicit RootedGeneric(CX *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: CustomAutoRooter(cx)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
template <typename CX>
explicit RootedGeneric(CX *cx, const T& initial MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: CustomAutoRooter(cx), value(initial)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
operator const T&() const { return value; }
T operator->() const { return value; }
private:
virtual void trace(JSTracer *trc) { value->trace(trc); }
T value;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* A handle to an array of rooted values. */
class HandleValueArray
{
@ -2878,6 +2915,8 @@ struct JSPropertyDescriptor {
{}
void trace(JSTracer *trc);
static js::ThingRootKind rootKind() { return js::THING_ROOT_PROPERTY_DESCRIPTOR; }
};
namespace JS {

View File

@ -232,10 +232,7 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode)
MOZ_CRASH();
#endif
#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
for (int i = 0; i < THING_ROOT_LIMIT; ++i)
JS_ASSERT(cx->thingGCRooters[i] == nullptr);
#endif
cx->checkNoGCRooters();
if (mode != DCM_NEW_FAILED) {
if (JSContextCallback cxCallback = rt->cxCallback) {
@ -266,6 +263,14 @@ js::DestroyContext(JSContext *cx, DestroyContextMode mode)
js_delete_poison(cx);
}
void
ContextFriendFields::checkNoGCRooters() {
#if defined(JSGC_USE_EXACT_ROOTING) && defined(DEBUG)
for (int i = 0; i < THING_ROOT_LIMIT; ++i)
JS_ASSERT(thingGCRooters[i] == nullptr);
#endif
}
bool
AutoResolving::alreadyStartedSlow() const
{

View File

@ -309,6 +309,8 @@ class Type
static inline Type ObjectType(JSObject *obj);
static inline Type ObjectType(TypeObject *obj);
static inline Type ObjectType(TypeObjectKey *obj);
static js::ThingRootKind rootKind() { return js::THING_ROOT_TYPE; }
};
/* Get the type of a jsval, or zero for an unknown special value. */

View File

@ -279,7 +279,6 @@ enum ThingRootKind
THING_ROOT_TYPE,
THING_ROOT_BINDINGS,
THING_ROOT_PROPERTY_DESCRIPTOR,
THING_ROOT_CUSTOM,
THING_ROOT_LIMIT
};
@ -347,19 +346,31 @@ struct ContextFriendFields
}
#ifdef JSGC_TRACK_EXACT_ROOTS
private:
/*
* Stack allocated GC roots for stack GC heap pointers, which may be
* overwritten if moved during a GC.
*/
JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
public:
template <class T>
inline JS::Rooted<T> *gcRooters() {
js::ThingRootKind kind = RootKind<T>::rootKind();
return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
}
#endif
void checkNoGCRooters();
/* Stack of thread-stack-allocated GC roots. */
JS::AutoGCRooter *autoGCRooters;
friend JSRuntime *GetRuntime(const JSContext *cx);
friend JSCompartment *GetContextCompartment(const JSContext *cx);
friend JS::Zone *GetContextZone(const JSContext *cx);
template <typename T> friend class JS::Rooted;
};
/*
@ -414,11 +425,19 @@ struct PerThreadDataFriendFields
PerThreadDataFriendFields();
#ifdef JSGC_TRACK_EXACT_ROOTS
private:
/*
* Stack allocated GC roots for stack GC heap pointers, which may be
* overwritten if moved during a GC.
*/
JS::Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
public:
template <class T>
inline JS::Rooted<T> *gcRooters() {
js::ThingRootKind kind = RootKind<T>::rootKind();
return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
}
#endif
/* Limit pointer for checking native stack consumption. */
@ -443,6 +462,8 @@ struct PerThreadDataFriendFields
return reinterpret_cast<const PerThreadDataFriendFields *>(
reinterpret_cast<const char*>(rt) + RuntimeMainThreadOffset);
}
template <typename T> friend class JS::Rooted;
};
} /* namespace js */

View File

@ -266,6 +266,7 @@ class Bindings
return !callObjShape_->isEmptyShape();
}
static js::ThingRootKind rootKind() { return js::THING_ROOT_BINDINGS; }
void trace(JSTracer *trc);
};

View File

@ -853,7 +853,6 @@ struct StackBaseShape
static inline bool match(UnownedBaseShape *key, const StackBaseShape *lookup);
// For RootedGeneric<StackBaseShape*>
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
void trace(JSTracer *trc);
};
@ -1505,7 +1504,6 @@ struct StackShape
}
// For RootedGeneric<StackShape*>
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
void trace(JSTracer *trc);
};