Bug 797304 - Replace MoveWrapper nonsense with orphan fixup. r=peterv

This commit is contained in:
Bobby Holley 2012-10-16 15:07:54 +02:00
parent 12bf387728
commit 2d8eff9c4b
5 changed files with 12 additions and 156 deletions

View File

@ -200,14 +200,6 @@ public:
*/
static JSContext* GetContextFromDocument(nsIDocument *aDocument);
/**
* When a document's scope changes (e.g., from document.open(), call this
* function to move all content wrappers from the old scope to the new one.
*/
static nsresult ReparentContentWrappersInScope(JSContext *cx,
nsIScriptGlobalObject *aOldScope,
nsIScriptGlobalObject *aNewScope);
static bool IsCallerChrome();
static bool IsCallerTrustedForRead();

View File

@ -1721,23 +1721,6 @@ nsContentUtils::TraceSafeJSContext(JSTracer* aTrc)
}
}
nsresult
nsContentUtils::ReparentContentWrappersInScope(JSContext *cx,
nsIScriptGlobalObject *aOldScope,
nsIScriptGlobalObject *aNewScope)
{
JSObject *oldScopeObj = aOldScope->GetGlobalJSObject();
JSObject *newScopeObj = aNewScope->GetGlobalJSObject();
if (!newScopeObj || !oldScopeObj) {
// We can't really do anything without the JSObjects.
return NS_ERROR_NOT_AVAILABLE;
}
return sXPConnect->MoveWrappers(cx, oldScopeObj, newScopeObj);
}
nsPIDOMWindow *
nsContentUtils::GetWindowFromCaller()
{

View File

@ -1499,7 +1499,7 @@ nsHTMLDocument::Open(const nsAString& aContentTypeOrUrl,
static_cast<nsINode*>(this),
getter_AddRefs(ignored));
NS_ENSURE_SUCCESS(rv, rv);
rv = nsContentUtils::ReparentContentWrappersInScope(cx, oldScope, newScope);
rv = xpc->RescueOrphansInScope(cx, oldScope->GetGlobalJSObject());
NS_ENSURE_SUCCESS(rv, rv);
}
}

View File

@ -288,7 +288,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
%}
[uuid(d94c13ae-7585-4e7b-b7ad-482976bc6f1b)]
[uuid(e28a33ce-dfe9-4816-ae20-0f1dc8077230)]
interface nsIXPConnect : nsISupports
{
%{ C++
@ -524,9 +524,7 @@ interface nsIXPConnect : nsISupports
in JSObjectPtr aNewParent,
in nsISupports aCOMObj);
void
moveWrappers(in JSContextPtr aJSContext,
in JSObjectPtr aOldScope,
in JSObjectPtr aNewScope);
rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr aScope);
void clearAllWrappedNativeSecurityPolicies();

View File

@ -1551,150 +1551,33 @@ MoveableWrapperFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
return JS_DHASH_NEXT;
}
static nsresult
MoveWrapper(XPCCallContext& ccx, XPCWrappedNative *wrapper,
XPCWrappedNativeScope *newScope, XPCWrappedNativeScope *oldScope)
{
// First, check to see if this wrapper really needs to be
// reparented.
if (wrapper->GetScope() == newScope) {
// The wrapper already got moved, nothing to do here.
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));
// ClassInfo is implemented as singleton objects. If the identity
// object here is the same object as returned by the QI, then it
// is the singleton classinfo, so we don't need to reparent it.
if (SameCOMIdentity(identity, info))
info = nullptr;
if (!info)
return NS_OK;
XPCNativeScriptableCreateInfo sciProto;
XPCNativeScriptableCreateInfo sci;
const XPCNativeScriptableCreateInfo& sciWrapper =
XPCWrappedNative::GatherScriptableCreateInfo(identity, info,
sciProto, sci);
// If the wrapper doesn't want precreate, then we don't need to
// worry about reparenting it.
if (!sciWrapper.GetFlags().WantPreCreate())
return NS_OK;
JSObject *newParent = oldScope->GetGlobalJSObject();
rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
newParent,
&newParent);
if (NS_FAILED(rv))
return rv;
if (newParent == oldScope->GetGlobalJSObject()) {
// The old scope still works for this wrapper. We have to
// assume that the wrapper will continue to return the old
// scope from PreCreate, so don't move it.
return NS_OK;
}
// These are pretty special circumstances. Make sure that the parent here
// is a bonafide WN with a proper parent chain.
MOZ_ASSERT(!js::IsCrossCompartmentWrapper(newParent));
MOZ_ASSERT(IS_WRAPPER_CLASS(js::GetObjectClass(newParent)));
if (!IS_WN_WRAPPER_OBJECT(newParent))
NS_ENSURE_STATE(MorphSlimWrapper(ccx, newParent));
XPCWrappedNative *parentWrapper =
static_cast<XPCWrappedNative*>(js::GetObjectPrivate(newParent));
rv = parentWrapper->RescueOrphans(ccx);
NS_ENSURE_SUCCESS(rv, rv);
// The wrapper returned a new parent. If the new parent is in a
// different scope, then we need to reparent it, otherwise, the
// old scope is fine.
XPCWrappedNativeScope *betterScope = parentWrapper->GetScope();
if (betterScope == oldScope) {
// The wrapper asked for a different object, but that object
// was in the same scope. This means that the new parent
// simply hasn't been reparented yet, so reparent it first,
// and then continue reparenting the wrapper itself.
rv = MoveWrapper(ccx, parentWrapper, newScope, oldScope);
NS_ENSURE_SUCCESS(rv, rv);
// If the parent wanted to stay in the old scope, we have to stay with
// it. This can happen when doing document.write when the old detached
// about:blank document is still floating around in the scope. Leave it
// behind to die.
if (parentWrapper->GetScope() == oldScope)
return NS_OK;
NS_ASSERTION(parentWrapper->GetScope() == newScope,
"A _third_ scope? Oh dear...");
} else
NS_ASSERTION(betterScope == newScope, "Weird scope returned");
// Now, reparent the wrapper, since we know that it wants to be
// reparented.
nsRefPtr<XPCWrappedNative> junk;
rv = XPCWrappedNative::ReparentWrapperIfFound(ccx, oldScope,
newScope, parentWrapper->GetFlatJSObject(),
wrapper->GetIdentityObject(),
getter_AddRefs(junk));
return rv;
}
/* void moveWrappers(in JSContextPtr aJSContext, in JSObjectPtr aOldScope, in JSObjectPtr aNewScope); */
/* void rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr aScope); */
NS_IMETHODIMP
nsXPConnect::MoveWrappers(JSContext *aJSContext,
JSObject *aOldScope,
JSObject *aNewScope)
nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScope)
{
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
if (!ccx.IsValid())
return UnexpectedFailure(NS_ERROR_FAILURE);
XPCWrappedNativeScope *oldScope =
XPCWrappedNativeScope::FindInJSObjectScope(ccx, aOldScope);
if (!oldScope)
XPCWrappedNativeScope *scope =
XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
if (!scope)
return UnexpectedFailure(NS_ERROR_FAILURE);
XPCWrappedNativeScope *newScope =
XPCWrappedNativeScope::FindInJSObjectScope(ccx, aNewScope);
if (!newScope)
return UnexpectedFailure(NS_ERROR_FAILURE);
// First, look through the old scope and find all of the wrappers that
// we're going to move.
// First, look through the old scope and find all of the wrappers that we
// might need to rescue.
nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
{ // scoped lock
XPCAutoLock lock(GetRuntime()->GetMapLock());
Native2WrappedNativeMap *map = oldScope->GetWrappedNativeMap();
Native2WrappedNativeMap *map = scope->GetWrappedNativeMap();
wrappersToMove.SetCapacity(map->Count());
map->Enumerate(MoveableWrapperFinder, &wrappersToMove);
}
// Now that we have the wrappers, reparent them to the new scope.
for (uint32_t i = 0, stop = wrappersToMove.Length(); i < stop; ++i) {
nsresult rv = MoveWrapper(ccx, wrappersToMove[i], newScope, oldScope);
nsresult rv = wrappersToMove[i]->RescueOrphans(ccx);
NS_ENSURE_SUCCESS(rv, rv);
}