mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1188364 - Supress GC while transplanting to prevent compacting GC observing intermediate state r=terrence
This commit is contained in:
parent
616689b68c
commit
fd636314d9
@ -793,6 +793,7 @@ class GCRuntime
|
||||
|
||||
bool isIncrementalGc() const { return isIncremental; }
|
||||
bool isFullGc() const { return isFull; }
|
||||
bool isCompactingGc() const { return isCompacting; }
|
||||
|
||||
bool shouldCleanUpEverything() { return cleanUpEverything; }
|
||||
|
||||
|
@ -916,53 +916,54 @@ JS_TransplantObject(JSContext* cx, HandleObject origobj, HandleObject target)
|
||||
RootedValue origv(cx, ObjectValue(*origobj));
|
||||
RootedObject newIdentity(cx);
|
||||
|
||||
{
|
||||
AutoDisableProxyCheck adpc(cx->runtime());
|
||||
// Don't allow a compacting GC to observe any intermediate state.
|
||||
AutoDisableCompactingGC nocgc(cx->runtime());
|
||||
|
||||
JSCompartment* destination = target->compartment();
|
||||
AutoDisableProxyCheck adpc(cx->runtime());
|
||||
|
||||
if (origobj->compartment() == destination) {
|
||||
// If the original object is in the same compartment as the
|
||||
// destination, then we know that we won't find a wrapper in the
|
||||
// destination's cross compartment map and that the same
|
||||
// object will continue to work.
|
||||
if (!JSObject::swap(cx, origobj, target))
|
||||
MOZ_CRASH();
|
||||
newIdentity = origobj;
|
||||
} else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
|
||||
// There might already be a wrapper for the original object in
|
||||
// the new compartment. If there is, we use its identity and swap
|
||||
// in the contents of |target|.
|
||||
newIdentity = &p->value().get().toObject();
|
||||
JSCompartment* destination = target->compartment();
|
||||
|
||||
// When we remove origv from the wrapper map, its wrapper, newIdentity,
|
||||
// must immediately cease to be a cross-compartment wrapper. Nuke it.
|
||||
destination->removeWrapper(p);
|
||||
NukeCrossCompartmentWrapper(cx, newIdentity);
|
||||
|
||||
if (!JSObject::swap(cx, newIdentity, target))
|
||||
MOZ_CRASH();
|
||||
} else {
|
||||
// Otherwise, we use |target| for the new identity object.
|
||||
newIdentity = target;
|
||||
}
|
||||
|
||||
// Now, iterate through other scopes looking for references to the
|
||||
// old object, and update the relevant cross-compartment wrappers.
|
||||
if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
|
||||
if (origobj->compartment() == destination) {
|
||||
// If the original object is in the same compartment as the
|
||||
// destination, then we know that we won't find a wrapper in the
|
||||
// destination's cross compartment map and that the same
|
||||
// object will continue to work.
|
||||
if (!JSObject::swap(cx, origobj, target))
|
||||
MOZ_CRASH();
|
||||
newIdentity = origobj;
|
||||
} else if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
|
||||
// There might already be a wrapper for the original object in
|
||||
// the new compartment. If there is, we use its identity and swap
|
||||
// in the contents of |target|.
|
||||
newIdentity = &p->value().get().toObject();
|
||||
|
||||
// Lastly, update the original object to point to the new one.
|
||||
if (origobj->compartment() != destination) {
|
||||
RootedObject newIdentityWrapper(cx, newIdentity);
|
||||
AutoCompartment ac(cx, origobj);
|
||||
if (!JS_WrapObject(cx, &newIdentityWrapper))
|
||||
MOZ_CRASH();
|
||||
MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
|
||||
if (!JSObject::swap(cx, origobj, newIdentityWrapper))
|
||||
MOZ_CRASH();
|
||||
origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv);
|
||||
}
|
||||
// When we remove origv from the wrapper map, its wrapper, newIdentity,
|
||||
// must immediately cease to be a cross-compartment wrapper. Nuke it.
|
||||
destination->removeWrapper(p);
|
||||
NukeCrossCompartmentWrapper(cx, newIdentity);
|
||||
|
||||
if (!JSObject::swap(cx, newIdentity, target))
|
||||
MOZ_CRASH();
|
||||
} else {
|
||||
// Otherwise, we use |target| for the new identity object.
|
||||
newIdentity = target;
|
||||
}
|
||||
|
||||
// Now, iterate through other scopes looking for references to the
|
||||
// old object, and update the relevant cross-compartment wrappers.
|
||||
if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
|
||||
MOZ_CRASH();
|
||||
|
||||
// Lastly, update the original object to point to the new one.
|
||||
if (origobj->compartment() != destination) {
|
||||
RootedObject newIdentityWrapper(cx, newIdentity);
|
||||
AutoCompartment ac(cx, origobj);
|
||||
if (!JS_WrapObject(cx, &newIdentityWrapper))
|
||||
MOZ_CRASH();
|
||||
MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity);
|
||||
if (!JSObject::swap(cx, origobj, newIdentityWrapper))
|
||||
MOZ_CRASH();
|
||||
origobj->compartment()->putWrapper(cx, CrossCompartmentKey(newIdentity), origv);
|
||||
}
|
||||
|
||||
// The new identity object might be one of several things. Return it to avoid
|
||||
|
@ -2005,6 +2005,8 @@ AutoDisableCompactingGC::AutoDisableCompactingGC(JSRuntime* rt)
|
||||
: gc(rt->gc)
|
||||
{
|
||||
gc.disableCompactingGC();
|
||||
if (gc.isIncrementalGCInProgress() && gc.isCompactingGc())
|
||||
AutoFinishGC finishGC(rt);
|
||||
}
|
||||
|
||||
AutoDisableCompactingGC::~AutoDisableCompactingGC()
|
||||
|
@ -300,7 +300,7 @@ IsCrossCompartmentWrapper(JSObject* obj);
|
||||
void
|
||||
NukeCrossCompartmentWrapper(JSContext* cx, JSObject* wrapper);
|
||||
|
||||
bool
|
||||
void
|
||||
RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
|
@ -494,7 +494,9 @@ js::NukeCrossCompartmentWrappers(JSContext* cx,
|
||||
// Given a cross-compartment wrapper |wobj|, update it to point to
|
||||
// |newTarget|. This recomputes the wrapper with JS_WrapValue, and thus can be
|
||||
// useful even if wrapper already points to newTarget.
|
||||
bool
|
||||
// This operation crashes on failure rather than leaving the heap in an
|
||||
// inconsistent state.
|
||||
void
|
||||
js::RemapWrapper(JSContext* cx, JSObject* wobjArg, JSObject* newTargetArg)
|
||||
{
|
||||
RootedObject wobj(cx, wobjArg);
|
||||
@ -551,8 +553,8 @@ js::RemapWrapper(JSContext* cx, JSObject* wobjArg, JSObject* newTargetArg)
|
||||
// Update the entry in the compartment's wrapper map to point to the old
|
||||
// wrapper, which has now been updated (via reuse or swap).
|
||||
MOZ_ASSERT(wobj->is<WrapperObject>());
|
||||
wcompartment->putWrapper(cx, CrossCompartmentKey(newTarget), ObjectValue(*wobj));
|
||||
return true;
|
||||
if (!wcompartment->putWrapper(cx, CrossCompartmentKey(newTarget), ObjectValue(*wobj)))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
// Remap all cross-compartment wrappers pointing to |oldTarget| to point to
|
||||
@ -575,10 +577,8 @@ js::RemapAllWrappersForObject(JSContext* cx, JSObject* oldTargetArg,
|
||||
}
|
||||
}
|
||||
|
||||
for (const Value& v : toTransplant) {
|
||||
if (!RemapWrapper(cx, &v.toObject(), newTarget))
|
||||
MOZ_CRASH();
|
||||
}
|
||||
for (const Value& v : toTransplant)
|
||||
RemapWrapper(cx, &v.toObject(), newTarget);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -615,8 +615,7 @@ js::RecomputeWrappers(JSContext* cx, const CompartmentFilter& sourceFilter,
|
||||
for (const Value& v : toRecompute) {
|
||||
JSObject* wrapper = &v.toObject();
|
||||
JSObject* wrapped = Wrapper::wrappedObject(wrapper);
|
||||
if (!RemapWrapper(cx, wrapper, wrapped))
|
||||
MOZ_CRASH();
|
||||
RemapWrapper(cx, wrapper, wrapped);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user