Bug 1189809 - Remove the ill-fated DynamicTraceable; r=jonco

This commit is contained in:
Terrence Cole 2015-07-31 08:27:12 -07:00
parent 7986b6b982
commit e6ed4bf78a
10 changed files with 30 additions and 139 deletions

View File

@ -567,26 +567,15 @@ struct GCMethods<JSFunction*>
namespace JS {
// If a class containing GC pointers has (or can gain) a vtable, then it can be
// trivially used with Rooted/Handle/MutableHandle by deriving from
// DynamicTraceable and overriding |void trace(JSTracer*)|.
class DynamicTraceable
// Non pointer types -- structs or classes that contain GC pointers, either as
// a member or in a more complex container layout -- can also be stored in a
// [Persistent]Rooted if it derives from JS::Traceable. A JS::Traceable stored
// in a [Persistent]Rooted must implement the method:
// |static void trace(T*, JSTracer*)|
class Traceable
{
public:
static js::ThingRootKind rootKind() { return js::THING_ROOT_DYNAMIC_TRACEABLE; }
virtual ~DynamicTraceable() {}
virtual void trace(JSTracer* trc) = 0;
};
// To use a static class or struct (e.g. not containing a vtable) as part of a
// Rooted/Handle/MutableHandle, ensure that it derives from StaticTraceable
// (i.e. so that automatic upcast via calls works) and ensure that a method
// |static void trace(T*, JSTracer*)| exists on the class.
class StaticTraceable
{
public:
static js::ThingRootKind rootKind() { return js::THING_ROOT_STATIC_TRACEABLE; }
static js::ThingRootKind rootKind() { return js::THING_ROOT_TRACEABLE; }
};
} /* namespace JS */
@ -596,8 +585,8 @@ namespace js {
template <typename T>
class DispatchWrapper
{
static_assert(mozilla::IsBaseOf<JS::StaticTraceable, T>::value,
"DispatchWrapper is intended only for usage with a StaticTraceable");
static_assert(mozilla::IsBaseOf<JS::Traceable, T>::value,
"DispatchWrapper is intended only for usage with a Traceable");
using TraceFn = void (*)(T*, JSTracer*);
TraceFn tracer;
@ -620,7 +609,7 @@ class DispatchWrapper
// Trace the contained storage (of unknown type) using the trace function
// we set aside when we did know the type.
static void TraceWrapped(JSTracer* trc, JS::StaticTraceable* thingp, const char* name) {
static void TraceWrapped(JSTracer* trc, JS::Traceable* thingp, const char* name) {
auto wrapper = reinterpret_cast<DispatchWrapper*>(
uintptr_t(thingp) - offsetof(DispatchWrapper, storage));
wrapper->tracer(&wrapper->storage, trc);
@ -666,8 +655,7 @@ namespace JS {
template <typename T>
class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
{
static_assert(!mozilla::IsConvertible<T, StaticTraceable*>::value &&
!mozilla::IsConvertible<T, DynamicTraceable*>::value,
static_assert(!mozilla::IsConvertible<T, Traceable*>::value,
"Rooted takes pointer or Traceable types but not Traceable* type");
/* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */
@ -730,13 +718,13 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
/*
* For pointer types, the TraceKind for tracing is based on the list it is
* in (selected via rootKind), so no additional storage is required here.
* All StaticTraceable, however, share the same list, so the function to
* All Traceable, however, share the same list, so the function to
* call for tracing is stored adjacent to the struct. Since C++ cannot
* templatize on storage class, this is implemented via the wrapper class
* DispatchWrapper.
*/
using MaybeWrapped = typename mozilla::Conditional<
mozilla::IsBaseOf<StaticTraceable, T>::value,
mozilla::IsBaseOf<Traceable, T>::value,
js::DispatchWrapper<T>,
T>::Type;
MaybeWrapped ptr;

View File

@ -34,14 +34,15 @@ template <typename Key,
typename KeyTraceFunc = DefaultTracer<Key>,
typename ValueTraceFunc = DefaultTracer<Value>>
class TraceableHashMap : public HashMap<Key, Value, HashPolicy, AllocPolicy>,
public JS::DynamicTraceable
public JS::Traceable
{
using Base = HashMap<Key, Value, HashPolicy, AllocPolicy>;
public:
explicit TraceableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {}
void trace(JSTracer* trc) override {
static void trace(TraceableHashMap* map, JSTracer* trc) { map->trace(trc); }
void trace(JSTracer* trc) {
if (!this->initialized())
return;
for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {

View File

@ -37,7 +37,7 @@ class TraceableVector
MinInlineCapacity,
AllocPolicy,
TraceableVector<T, MinInlineCapacity, AllocPolicy, TraceFunc>>,
public JS::DynamicTraceable
public JS::Traceable
{
using Base = mozilla::VectorBase<T, MinInlineCapacity, AllocPolicy, TraceableVector>;
@ -48,7 +48,8 @@ class TraceableVector
return Base::operator=(mozilla::Forward<TraceableVector>(vec));
}
void trace(JSTracer* trc) override {
static void trace(TraceableVector* vec, JSTracer* trc) { vec->trace(trc); }
void trace(JSTracer* trc) {
for (size_t i = 0; i < this->length(); ++i)
TraceFunc::trace(trc, &Base::operator[](i), "vector element");
}

View File

@ -40,20 +40,6 @@ typedef RootedValueMap::Range RootRange;
typedef RootedValueMap::Entry RootEntry;
typedef RootedValueMap::Enum RootEnum;
// We cannot instantiate (even indirectly) the abstract JS::DynamicTraceable.
// Instead we cast to a ConcreteTraceable, then upcast before calling trace so
// that we get the implementation defined dynamically in the vtable.
struct ConcreteTraceable : public JS::DynamicTraceable
{
void trace(JSTracer* trc) override {}
};
static void
MarkDynamicTraceable(JSTracer* trc, ConcreteTraceable* t, const char* name)
{
static_cast<JS::DynamicTraceable*>(t)->trace(trc);
}
template <typename T>
using TraceFunction = void (*)(JSTracer* trc, T* ref, const char* name);
@ -76,8 +62,7 @@ MarkExactStackRootsAcrossTypes(T context, JSTracer* trc)
MarkExactStackRootList<JSObject*>(trc, context, "exact-object");
MarkExactStackRootList<Shape*>(trc, context, "exact-shape");
MarkExactStackRootList<BaseShape*>(trc, context, "exact-baseshape");
MarkExactStackRootList<ObjectGroup*>(
trc, context, "exact-objectgroup");
MarkExactStackRootList<ObjectGroup*>(trc, context, "exact-objectgroup");
MarkExactStackRootList<JSString*>(trc, context, "exact-string");
MarkExactStackRootList<JS::Symbol*>(trc, context, "exact-symbol");
MarkExactStackRootList<jit::JitCode*>(trc, context, "exact-jitcode");
@ -85,11 +70,8 @@ MarkExactStackRootsAcrossTypes(T context, JSTracer* trc)
MarkExactStackRootList<LazyScript*>(trc, context, "exact-lazy-script");
MarkExactStackRootList<jsid>(trc, context, "exact-id");
MarkExactStackRootList<Value>(trc, context, "exact-value");
MarkExactStackRootList<JS::StaticTraceable,
js::DispatchWrapper<JS::StaticTraceable>::TraceWrapped>(
trc, context, "StaticTraceable");
MarkExactStackRootList<ConcreteTraceable, MarkDynamicTraceable>(
trc, context, "DynamicTraceable");
MarkExactStackRootList<JS::Traceable, js::DispatchWrapper<JS::Traceable>::TraceWrapped>(
trc, context, "Traceable");
}
static void

View File

@ -40,7 +40,7 @@ BEGIN_TEST(testGCSuppressions)
}
END_TEST(testGCSuppressions)
struct MyContainer : public JS::StaticTraceable
struct MyContainer : public JS::Traceable
{
RelocatablePtrObject obj;
RelocatablePtrString str;
@ -62,22 +62,6 @@ struct RootedBase<MyContainer> {
};
} // namespace js
BEGIN_TEST(testGCRootedStaticStructInternalStackStorage)
{
JS::Rooted<MyContainer> container(cx);
container.get().obj = JS_NewObject(cx, nullptr);
container.get().str = JS_NewStringCopyZ(cx, "Hello");
JS_GC(cx->runtime());
JS_GC(cx->runtime());
JS::RootedObject obj(cx, container.get().obj);
JS::RootedValue val(cx, StringValue(container.get().str));
CHECK(JS_SetProperty(cx, obj, "foo", val));
return true;
}
END_TEST(testGCRootedStaticStructInternalStackStorage)
BEGIN_TEST(testGCRootedStaticStructInternalStackStorageAugmented)
{
JS::Rooted<MyContainer> container(cx);
@ -94,69 +78,6 @@ BEGIN_TEST(testGCRootedStaticStructInternalStackStorageAugmented)
}
END_TEST(testGCRootedStaticStructInternalStackStorageAugmented)
struct DynamicBase : public JS::DynamicTraceable
{
RelocatablePtrObject obj;
DynamicBase() : obj(nullptr) {}
void trace(JSTracer* trc) override {
if (obj)
js::TraceEdge(trc, &obj, "test container");
}
};
struct DynamicContainer : public DynamicBase
{
RelocatablePtrString str;
DynamicContainer() : str(nullptr) {}
void trace(JSTracer* trc) override {
this->DynamicBase::trace(trc);
if (str)
js::TraceEdge(trc, &str, "test container");
}
};
namespace js {
template <>
struct RootedBase<DynamicContainer> {
RelocatablePtrObject& obj() { return static_cast<Rooted<DynamicContainer>*>(this)->get().obj; }
RelocatablePtrString& str() { return static_cast<Rooted<DynamicContainer>*>(this)->get().str; }
};
} // namespace js
BEGIN_TEST(testGCRootedDynamicStructInternalStackStorage)
{
JS::Rooted<DynamicContainer> container(cx);
container.get().obj = JS_NewObject(cx, nullptr);
container.get().str = JS_NewStringCopyZ(cx, "Hello");
JS_GC(cx->runtime());
JS_GC(cx->runtime());
JS::RootedObject obj(cx, container.get().obj);
JS::RootedValue val(cx, StringValue(container.get().str));
CHECK(JS_SetProperty(cx, obj, "foo", val));
return true;
}
END_TEST(testGCRootedDynamicStructInternalStackStorage)
BEGIN_TEST(testGCRootedDynamicStructInternalStackStorageAugmented)
{
JS::Rooted<DynamicContainer> container(cx);
container.obj() = JS_NewObject(cx, nullptr);
container.str() = JS_NewStringCopyZ(cx, "Hello");
JS_GC(cx->runtime());
JS_GC(cx->runtime());
JS::RootedObject obj(cx, container.obj());
JS::RootedValue val(cx, StringValue(container.str()));
CHECK(JS_SetProperty(cx, obj, "foo", val));
return true;
}
END_TEST(testGCRootedDynamicStructInternalStackStorageAugmented)
using MyHashMap = js::TraceableHashMap<js::Shape*, JSObject*>;
BEGIN_TEST(testGCRootedHashMap)
@ -236,9 +157,10 @@ BEGIN_TEST(testGCHandleHashMap)
}
END_TEST(testGCHandleHashMap)
using ShapeVec = TraceableVector<Shape*>;
BEGIN_TEST(testGCRootedVector)
{
using ShapeVec = TraceableVector<Shape*>;
JS::Rooted<ShapeVec> shapes(cx, ShapeVec(cx));
for (size_t i = 0; i < 10; ++i) {
@ -311,8 +233,6 @@ receiveMutableHandleToShapeVector(JS::MutableHandle<TraceableVector<Shape*>> han
}
END_TEST(testGCRootedVector)
using ShapeVec = TraceableVector<Shape*>;
static bool
FillVector(JSContext* cx, MutableHandle<ShapeVec> shapes)
{

View File

@ -2507,7 +2507,7 @@ JS_New(JSContext* cx, JS::HandleObject ctor, const JS::HandleValueArray& args);
/*** Property descriptors ************************************************************************/
struct JSPropertyDescriptor : public JS::StaticTraceable {
struct JSPropertyDescriptor : public JS::Traceable {
JSObject* obj;
unsigned attrs;
JSGetterOp getter;

View File

@ -285,8 +285,7 @@ enum ThingRootKind
THING_ROOT_LAZY_SCRIPT,
THING_ROOT_ID,
THING_ROOT_VALUE,
THING_ROOT_STATIC_TRACEABLE,
THING_ROOT_DYNAMIC_TRACEABLE,
THING_ROOT_TRACEABLE,
THING_ROOT_LIMIT
};

View File

@ -206,7 +206,7 @@ JS_STATIC_ASSERT(sizeof(Binding) == sizeof(uintptr_t));
* both function and top-level scripts (the latter is needed to track names in
* strict mode eval code, to give such code its own lexical environment).
*/
class Bindings : public JS::StaticTraceable
class Bindings : public JS::Traceable
{
friend class BindingIter;
friend class AliasedFormalIter;

View File

@ -1173,7 +1173,7 @@ struct DefaultHasher<AbstractFramePtr> {
// entries that must be scanned through, and to avoid the headaches of
// maintaining a cache for each compartment and invalidating stale cache entries
// in the presence of cross-compartment calls.
class LiveSavedFrameCache : public JS::StaticTraceable
class LiveSavedFrameCache : public JS::Traceable
{
public:
using FramePtr = mozilla::Variant<AbstractFramePtr, jit::CommonFrameLayout*>;

View File

@ -272,7 +272,7 @@ class TypeSet
// Information about a single concrete type. We pack this into one word,
// where small values are particular primitive or other singleton types and
// larger values are either specific JS objects or object groups.
class Type : public JS::StaticTraceable
class Type : public JS::Traceable
{
friend class TypeSet;