mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1020690 - Type exact stack rooting machinery. r=sfink
--HG-- extra : rebase_source : 366ff0579912b8a03f29abb882cabcc982a44d47
This commit is contained in:
parent
4a089c98e4
commit
773bc32603
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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. */
|
||||
|
@ -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 */
|
||||
|
@ -266,6 +266,7 @@ class Bindings
|
||||
return !callObjShape_->isEmptyShape();
|
||||
}
|
||||
|
||||
static js::ThingRootKind rootKind() { return js::THING_ROOT_BINDINGS; }
|
||||
void trace(JSTracer *trc);
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user