mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1107639 - Allow two phase construction of PersistentRooted r=terrence
This commit is contained in:
parent
7e4dfb99c1
commit
3451f6624a
@ -1070,7 +1070,9 @@ MutableHandle<T>::MutableHandle(PersistentRooted<T> *root)
|
||||
* These roots can be used in heap-allocated data structures, so they are not
|
||||
* associated with any particular JSContext or stack. They are registered with
|
||||
* the JSRuntime itself, without locking, so they require a full JSContext to be
|
||||
* constructed, not one of its more restricted superclasses.
|
||||
* initialized, not one of its more restricted superclasses. Initialization may
|
||||
* take place on construction, or in two phases if the no-argument constructor
|
||||
* is called followed by init().
|
||||
*
|
||||
* Note that you must not use an PersistentRooted in an object owned by a JS
|
||||
* object:
|
||||
@ -1096,40 +1098,43 @@ MutableHandle<T>::MutableHandle(PersistentRooted<T> *root)
|
||||
* marked when the object itself is marked.
|
||||
*/
|
||||
template<typename T>
|
||||
class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T> > {
|
||||
class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T>> {
|
||||
typedef mozilla::LinkedListElement<PersistentRooted<T>> Base;
|
||||
|
||||
friend class mozilla::LinkedList<PersistentRooted>;
|
||||
friend class mozilla::LinkedListElement<PersistentRooted>;
|
||||
|
||||
friend struct js::gc::PersistentRootedMarker<T>;
|
||||
|
||||
friend void js::gc::FinishPersistentRootedChains(JSRuntime *rt);
|
||||
|
||||
void registerWithRuntime(JSRuntime *rt) {
|
||||
MOZ_ASSERT(!initialized());
|
||||
JS::shadow::Runtime *srt = JS::shadow::Runtime::asShadowRuntime(rt);
|
||||
srt->getPersistentRootedList<T>().insertBack(this);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit PersistentRooted(JSContext *cx) : ptr(js::GCMethods<T>::initial())
|
||||
{
|
||||
registerWithRuntime(js::GetRuntime(cx));
|
||||
PersistentRooted() : ptr(js::GCMethods<T>::initial()) {}
|
||||
|
||||
explicit PersistentRooted(JSContext *cx) {
|
||||
init(cx);
|
||||
}
|
||||
|
||||
PersistentRooted(JSContext *cx, T initial) : ptr(initial)
|
||||
{
|
||||
registerWithRuntime(js::GetRuntime(cx));
|
||||
PersistentRooted(JSContext *cx, T initial) {
|
||||
init(cx, initial);
|
||||
}
|
||||
|
||||
explicit PersistentRooted(JSRuntime *rt) : ptr(js::GCMethods<T>::initial())
|
||||
{
|
||||
registerWithRuntime(rt);
|
||||
explicit PersistentRooted(JSRuntime *rt) {
|
||||
init(rt);
|
||||
}
|
||||
|
||||
PersistentRooted(JSRuntime *rt, T initial) : ptr(initial)
|
||||
{
|
||||
registerWithRuntime(rt);
|
||||
PersistentRooted(JSRuntime *rt, T initial) {
|
||||
init(rt, initial);
|
||||
}
|
||||
|
||||
PersistentRooted(const PersistentRooted &rhs)
|
||||
: mozilla::LinkedListElement<PersistentRooted<T> >(),
|
||||
: mozilla::LinkedListElement<PersistentRooted<T>>(),
|
||||
ptr(rhs.ptr)
|
||||
{
|
||||
/*
|
||||
@ -1143,6 +1148,37 @@ class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T>
|
||||
const_cast<PersistentRooted &>(rhs).setNext(this);
|
||||
}
|
||||
|
||||
bool initialized() {
|
||||
return Base::isInList();
|
||||
}
|
||||
|
||||
void init(JSContext *cx) {
|
||||
init(cx, js::GCMethods<T>::initial());
|
||||
}
|
||||
|
||||
void init(JSContext *cx, T initial)
|
||||
{
|
||||
ptr = initial;
|
||||
registerWithRuntime(js::GetRuntime(cx));
|
||||
}
|
||||
|
||||
void init(JSRuntime *rt) {
|
||||
init(rt, js::GCMethods<T>::initial());
|
||||
}
|
||||
|
||||
void init(JSRuntime *rt, T initial)
|
||||
{
|
||||
ptr = initial;
|
||||
registerWithRuntime(rt);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (initialized()) {
|
||||
set(js::GCMethods<T>::initial());
|
||||
Base::remove();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Important: Return a reference here so passing a Rooted<T> to
|
||||
* something that takes a |const T&| is not a GC hazard.
|
||||
@ -1155,17 +1191,17 @@ class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T>
|
||||
const T &get() const { return ptr; }
|
||||
|
||||
T &operator=(T value) {
|
||||
MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
|
||||
ptr = value;
|
||||
set(value);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T &operator=(const PersistentRooted &value) {
|
||||
ptr = value;
|
||||
T &operator=(const PersistentRooted &other) {
|
||||
set(other.ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void set(T value) {
|
||||
MOZ_ASSERT(initialized());
|
||||
MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
|
||||
ptr = value;
|
||||
}
|
||||
|
@ -38,8 +38,15 @@ const JSClass BarkWhenTracedClass::class_ = {
|
||||
|
||||
struct Kennel {
|
||||
PersistentRootedObject obj;
|
||||
Kennel() { }
|
||||
explicit Kennel(JSContext *cx) : obj(cx) { }
|
||||
Kennel(JSContext *cx, const HandleObject &woof) : obj(cx, woof) { }
|
||||
void init(JSContext *cx, const HandleObject &woof) {
|
||||
obj.init(cx, woof);
|
||||
}
|
||||
void clear() {
|
||||
obj = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
// A function for allocating a Kennel and a barker. Only allocating
|
||||
@ -178,3 +185,35 @@ BEGIN_TEST(test_PersistentRootedAssign)
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_PersistentRootedAssign)
|
||||
|
||||
static PersistentRootedObject gGlobalRoot;
|
||||
|
||||
// PersistentRooted instances can initialized in a separate step to allow for global PersistentRooteds.
|
||||
BEGIN_TEST(test_GlobalPersistentRooted)
|
||||
{
|
||||
BarkWhenTracedClass::reset();
|
||||
|
||||
CHECK(!gGlobalRoot.initialized());
|
||||
|
||||
{
|
||||
RootedObject barker(cx, JS_NewObject(cx, &BarkWhenTracedClass::class_, JS::NullPtr(), JS::NullPtr()));
|
||||
CHECK(barker);
|
||||
|
||||
gGlobalRoot.init(cx, barker);
|
||||
}
|
||||
|
||||
CHECK(gGlobalRoot.initialized());
|
||||
|
||||
// GC should be able to find our barker.
|
||||
CHECK(GCFinalizesNBarkers(cx, 0));
|
||||
|
||||
gGlobalRoot.reset();
|
||||
CHECK(!gGlobalRoot.initialized());
|
||||
|
||||
// Now GC should not be able to find the barker.
|
||||
JS_GC(JS_GetRuntime(cx));
|
||||
CHECK(BarkWhenTracedClass::finalizeCount == 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_GlobalPersistentRooted)
|
||||
|
@ -1325,16 +1325,24 @@ GCRuntime::finish()
|
||||
FinishTrace();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void
|
||||
FinishPersistentRootedChain(mozilla::LinkedList<PersistentRooted<T>>& list)
|
||||
{
|
||||
while (!list.isEmpty())
|
||||
list.getFirst()->reset();
|
||||
}
|
||||
|
||||
void
|
||||
js::gc::FinishPersistentRootedChains(JSRuntime *rt)
|
||||
{
|
||||
/* The lists of persistent roots are stored on the shadow runtime. */
|
||||
rt->functionPersistentRooteds.clear();
|
||||
rt->idPersistentRooteds.clear();
|
||||
rt->objectPersistentRooteds.clear();
|
||||
rt->scriptPersistentRooteds.clear();
|
||||
rt->stringPersistentRooteds.clear();
|
||||
rt->valuePersistentRooteds.clear();
|
||||
FinishPersistentRootedChain(rt->functionPersistentRooteds);
|
||||
FinishPersistentRootedChain(rt->idPersistentRooteds);
|
||||
FinishPersistentRootedChain(rt->objectPersistentRooteds);
|
||||
FinishPersistentRootedChain(rt->scriptPersistentRooteds);
|
||||
FinishPersistentRootedChain(rt->stringPersistentRooteds);
|
||||
FinishPersistentRootedChain(rt->valuePersistentRooteds);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user