зеркало из https://github.com/mozilla/pjs.git
Bug 751995 - Handle orphaned wrappers. r=peterv
This commit is contained in:
Родитель
79624f0b28
Коммит
68e265c9bc
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function frameDoc() { return document.getElementById("f").contentDocument; }
|
||||
|
||||
function arm() {
|
||||
// Create an element in the iframe.
|
||||
var div = frameDoc().createElement("div");
|
||||
|
||||
// Force a wrapper to be created for .style.
|
||||
var style = div.style;
|
||||
style.color = "green";
|
||||
|
||||
// Adopt the element out of the iframe, leaving the |style| behind.
|
||||
document.adoptNode(div);
|
||||
}
|
||||
|
||||
function boom()
|
||||
{
|
||||
// Create an orphan.
|
||||
arm();
|
||||
|
||||
// Force an iteration over all the wrappers in frameDoc's scope, causing
|
||||
// us to notice the orphan.
|
||||
frameDoc().write("2");
|
||||
|
||||
// All done.
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();"><iframe id="f" src="data:text/html,1"></iframe></body>
|
||||
</html>
|
|
@ -37,5 +37,6 @@ load 648206-1.html
|
|||
load 705875.html
|
||||
load 720305-1.html
|
||||
load 723465.html
|
||||
load 751995.html
|
||||
asserts(0-1) load 752038.html # We may hit bug 645229 here.
|
||||
load 754311.html
|
||||
|
|
|
@ -1729,6 +1729,80 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
XPCWrappedNative*
|
||||
XPCWrappedNative::GetParentWrapper()
|
||||
{
|
||||
XPCWrappedNative *wrapper = nsnull;
|
||||
JSObject *parent = js::GetObjectParent(mFlatJSObject);
|
||||
if (parent && IS_WN_WRAPPER(parent)) {
|
||||
wrapper = static_cast<XPCWrappedNative*>(js::GetObjectPrivate(parent));
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Orphans are sad little things - If only we could treat them better. :-(
|
||||
//
|
||||
// When a wrapper gets reparented to another scope (for example, when calling
|
||||
// adoptNode), it's entirely possible that it previously served as the parent for
|
||||
// other wrappers (via PreCreate hooks). When it moves, the old mFlatJSObject is
|
||||
// replaced by a cross-compartment wrapper. Its descendants really _should_ move
|
||||
// too, but we have no way of locating them short of a compartment-wide sweep
|
||||
// (which we believe to be prohibitively expensive).
|
||||
//
|
||||
// So we just leave them behind. In practice, the only time this turns out to
|
||||
// be a problem is during subsequent wrapper reparenting. When this happens, we
|
||||
// call into the below fixup code at the last minute and straighten things out
|
||||
// before proceeding.
|
||||
//
|
||||
// See bug 751995 for more information.
|
||||
|
||||
bool
|
||||
XPCWrappedNative::IsOrphan()
|
||||
{
|
||||
JSObject *parent = js::GetObjectParent(mFlatJSObject);
|
||||
|
||||
// If there's no parent, we've presumably got a global, which can't be an
|
||||
// orphan by definition.
|
||||
if (!parent)
|
||||
return false;
|
||||
|
||||
// If our parent is a cross-compartment wrapper, it has left us behind.
|
||||
return js::IsCrossCompartmentWrapper(parent);
|
||||
}
|
||||
|
||||
// Recursively fix up orphans on the parent chain of a wrapper. Note that this
|
||||
// can cause a wrapper to move even if IsOrphan() is false, since its parent
|
||||
// might be an orphan, and fixing the parent causes this wrapper to become an
|
||||
// orphan.
|
||||
nsresult
|
||||
XPCWrappedNative::RescueOrphans(XPCCallContext& ccx)
|
||||
{
|
||||
// Even if we're not an orphan at the moment, one of our ancestors might
|
||||
// be. If so, we need to recursively rescue up the parent chain.
|
||||
nsresult rv;
|
||||
XPCWrappedNative *parentWrapper = GetParentWrapper();
|
||||
if (parentWrapper && parentWrapper->IsOrphan()) {
|
||||
rv = parentWrapper->RescueOrphans(ccx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Now that we know our parent is in the right place, determine if we've
|
||||
// been orphaned. If not, we have nothing to do.
|
||||
if (!IsOrphan())
|
||||
return NS_OK;
|
||||
|
||||
// We've been orphaned. Find where our parent went, and follow it.
|
||||
JSObject *parentGhost = js::GetObjectParent(mFlatJSObject);
|
||||
JSObject *realParent = js::UnwrapObject(parentGhost);
|
||||
nsRefPtr<XPCWrappedNative> ignored;
|
||||
return ReparentWrapperIfFound(ccx,
|
||||
XPCWrappedNativeScope::
|
||||
FindInJSObjectScope(ccx, parentGhost),
|
||||
XPCWrappedNativeScope::
|
||||
FindInJSObjectScope(ccx, realParent),
|
||||
realParent, mIdentity, getter_AddRefs(ignored));
|
||||
}
|
||||
|
||||
#define IS_TEAROFF_CLASS(clazz) \
|
||||
((clazz) == &XPC_WN_Tearoff_JSClass)
|
||||
|
||||
|
|
|
@ -1547,6 +1547,19 @@ MoveWrapper(XPCCallContext& ccx, XPCWrappedNative *wrapper,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// For performance reasons, we wait to fix up orphaned wrappers (wrappers
|
||||
// whose parents have moved to another scope) until right before they
|
||||
// threaten to confuse us.
|
||||
//
|
||||
// If this wrapper is an orphan, reunite it with its parent. If, following
|
||||
// that, the wrapper is no longer in the old scope, then we don't need to
|
||||
// reparent it.
|
||||
MOZ_ASSERT(wrapper->GetScope() == oldScope);
|
||||
nsresult rv = wrapper->RescueOrphans(ccx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (wrapper->GetScope() != oldScope)
|
||||
return NS_OK;
|
||||
|
||||
nsISupports *identity = wrapper->GetIdentityObject();
|
||||
nsCOMPtr<nsIClassInfo> info(do_QueryInterface(identity));
|
||||
|
||||
|
@ -1571,9 +1584,9 @@ MoveWrapper(XPCCallContext& ccx, XPCWrappedNative *wrapper,
|
|||
return NS_OK;
|
||||
|
||||
JSObject *newParent = oldScope->GetGlobalJSObject();
|
||||
nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
|
||||
newParent,
|
||||
&newParent);
|
||||
rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
|
||||
newParent,
|
||||
&newParent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
|
|
@ -2704,6 +2704,15 @@ public:
|
|||
nsISupports* aCOMObj,
|
||||
XPCWrappedNative** aWrapper);
|
||||
|
||||
// Returns the wrapper corresponding to the parent of our mFlatJSObject.
|
||||
//
|
||||
// If the parent does not have a WN, or if there is no parent, null is
|
||||
// returned.
|
||||
XPCWrappedNative *GetParentWrapper();
|
||||
|
||||
bool IsOrphan();
|
||||
nsresult RescueOrphans(XPCCallContext& ccx);
|
||||
|
||||
void FlatJSObjectFinalized();
|
||||
|
||||
void SystemIsBeingShutDown();
|
||||
|
|
Загрузка…
Ссылка в новой задаче