mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1181799 - Allow use of Rooted with arbitrary, fully static structs; r=sfink
This commit is contained in:
parent
dcdae36446
commit
d7fa32fc54
@ -104,7 +104,9 @@
|
|||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct GCMethods {};
|
struct GCMethods {
|
||||||
|
static T initial() { return T(); }
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class RootedBase {};
|
class RootedBase {};
|
||||||
@ -627,6 +629,54 @@ struct GCMethods<JSFunction*>
|
|||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
// To use a static class or struct 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; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace JS */
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class DispatchWrapper
|
||||||
|
{
|
||||||
|
static_assert(mozilla::IsBaseOf<JS::StaticTraceable, T>::value,
|
||||||
|
"DispatchWrapper is intended only for usage with a StaticTraceable");
|
||||||
|
|
||||||
|
using TraceFn = void (*)(T*, JSTracer*);
|
||||||
|
TraceFn tracer;
|
||||||
|
#if JS_BITS_PER_WORD == 32
|
||||||
|
uint32_t padding; // Ensure the storage fields have CellSize alignment.
|
||||||
|
#endif
|
||||||
|
T storage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Mimic a pointer type, so that we can drop into Rooted.
|
||||||
|
MOZ_IMPLICIT DispatchWrapper(const T& initial) : tracer(&T::trace), storage(initial) {}
|
||||||
|
T* operator &() { return &storage; }
|
||||||
|
const T* operator &() const { return &storage; }
|
||||||
|
operator T&() { return storage; }
|
||||||
|
operator const T&() const { return storage; }
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
auto wrapper = reinterpret_cast<DispatchWrapper*>(
|
||||||
|
uintptr_t(thingp) - offsetof(DispatchWrapper, storage));
|
||||||
|
wrapper->tracer(&wrapper->storage, trc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace js */
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local variable of type T whose value is always rooted. This is typically
|
* Local variable of type T whose value is always rooted. This is typically
|
||||||
* used for local variables, or for non-rooted values being passed to a
|
* used for local variables, or for non-rooted values being passed to a
|
||||||
@ -743,10 +793,18 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
|
|||||||
Rooted<void*>* prev;
|
Rooted<void*>* prev;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* |ptr| must be the last field in Rooted because the analysis treats all
|
* For pointer types, the TraceKind for tracing is based on the list it is
|
||||||
* Rooted as Rooted<void*> during the analysis. See bug 829372.
|
* in (selected via rootKind), so no additional storage is required here.
|
||||||
|
* All StaticTraceable, 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.
|
||||||
*/
|
*/
|
||||||
T ptr;
|
using MaybeWrapped = typename mozilla::Conditional<
|
||||||
|
mozilla::IsBaseOf<StaticTraceable, T>::value,
|
||||||
|
js::DispatchWrapper<T>,
|
||||||
|
T>::Type;
|
||||||
|
MaybeWrapped ptr;
|
||||||
|
|
||||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||||
|
|
||||||
|
@ -110,6 +110,9 @@ MarkExactStackRootsAcrossTypes(T context, JSTracer* trc)
|
|||||||
MarkExactStackRootList<Bindings, MarkBindingsRoot>(trc, context, "Bindings");
|
MarkExactStackRootList<Bindings, MarkBindingsRoot>(trc, context, "Bindings");
|
||||||
MarkExactStackRootList<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(
|
MarkExactStackRootList<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(
|
||||||
trc, context, "JSPropertyDescriptor");
|
trc, context, "JSPropertyDescriptor");
|
||||||
|
MarkExactStackRootList<JS::StaticTraceable,
|
||||||
|
js::DispatchWrapper<JS::StaticTraceable>::TraceWrapped>(
|
||||||
|
trc, context, "StaticTraceable");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -35,3 +35,57 @@ BEGIN_TEST(testGCSuppressions)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
END_TEST(testGCSuppressions)
|
END_TEST(testGCSuppressions)
|
||||||
|
|
||||||
|
struct MyContainer : public JS::StaticTraceable
|
||||||
|
{
|
||||||
|
RelocatablePtrObject obj;
|
||||||
|
RelocatablePtrString str;
|
||||||
|
|
||||||
|
MyContainer() : obj(nullptr), str(nullptr) {}
|
||||||
|
static void trace(MyContainer* self, JSTracer* trc) {
|
||||||
|
if (self->obj)
|
||||||
|
js::TraceEdge(trc, &self->obj, "test container");
|
||||||
|
if (self->str)
|
||||||
|
js::TraceEdge(trc, &self->str, "test container");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
template <>
|
||||||
|
struct RootedBase<MyContainer> {
|
||||||
|
RelocatablePtrObject& obj() { return static_cast<Rooted<MyContainer>*>(this)->get().obj; }
|
||||||
|
RelocatablePtrString& str() { return static_cast<Rooted<MyContainer>*>(this)->get().str; }
|
||||||
|
};
|
||||||
|
} // namespace js
|
||||||
|
|
||||||
|
BEGIN_TEST(testGCGenericRootedInternalStackStorage)
|
||||||
|
{
|
||||||
|
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(testGCGenericRootedInternalStackStorage)
|
||||||
|
|
||||||
|
BEGIN_TEST(testGCGenericRootedInternalStackStorageAugmented)
|
||||||
|
{
|
||||||
|
JS::Rooted<MyContainer> 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(testGCGenericRootedInternalStackStorageAugmented)
|
||||||
|
@ -299,6 +299,19 @@ namespace js {
|
|||||||
|
|
||||||
class ExclusiveContext;
|
class ExclusiveContext;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This list enumerates the different types of conceptual stacks we have in
|
||||||
|
* SpiderMonkey. In reality, they all share the C stack, but we allow different
|
||||||
|
* stack limits depending on the type of code running.
|
||||||
|
*/
|
||||||
|
enum StackKind
|
||||||
|
{
|
||||||
|
StackForSystemCode, // C++, such as the GC, running on behalf of the VM.
|
||||||
|
StackForTrustedScript, // Script running with trusted principals.
|
||||||
|
StackForUntrustedScript, // Script running with untrusted principals.
|
||||||
|
StackKindCount
|
||||||
|
};
|
||||||
|
|
||||||
enum ThingRootKind
|
enum ThingRootKind
|
||||||
{
|
{
|
||||||
THING_ROOT_OBJECT,
|
THING_ROOT_OBJECT,
|
||||||
@ -316,22 +329,10 @@ enum ThingRootKind
|
|||||||
THING_ROOT_BINDINGS,
|
THING_ROOT_BINDINGS,
|
||||||
THING_ROOT_PROPERTY_DESCRIPTOR,
|
THING_ROOT_PROPERTY_DESCRIPTOR,
|
||||||
THING_ROOT_PROP_DESC,
|
THING_ROOT_PROP_DESC,
|
||||||
|
THING_ROOT_STATIC_TRACEABLE,
|
||||||
THING_ROOT_LIMIT
|
THING_ROOT_LIMIT
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* This list enumerates the different types of conceptual stacks we have in
|
|
||||||
* SpiderMonkey. In reality, they all share the C stack, but we allow different
|
|
||||||
* stack limits depending on the type of code running.
|
|
||||||
*/
|
|
||||||
enum StackKind
|
|
||||||
{
|
|
||||||
StackForSystemCode, // C++, such as the GC, running on behalf of the VM.
|
|
||||||
StackForTrustedScript, // Script running with trusted principals.
|
|
||||||
StackForUntrustedScript, // Script running with untrusted principals.
|
|
||||||
StackKindCount
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct RootKind;
|
struct RootKind;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user