diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index 7c5fa009d29..a482fbe75f5 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -100,8 +100,11 @@ enum { NODE_IS_INSERTION_PARENT = 0x00001000U, + // Keep track of whether this node is in the middle of binding teardown + NODE_IS_IN_BINDING_TEARDOWN = 0x00002000U, + // Four bits for the script-type ID - NODE_SCRIPT_TYPE_OFFSET = 13, + NODE_SCRIPT_TYPE_OFFSET = 14, NODE_SCRIPT_TYPE_SIZE = 4, diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index 8a0e916b030..3a8db62f1c4 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -186,6 +186,11 @@ XBLResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, return JS_FALSE; } + if (content->HasFlag(NODE_IS_IN_BINDING_TEARDOWN)) { + // Don't evaluate fields now! + return JS_TRUE; + } + // This mirrors code in nsXBLProtoImpl::InstallImplementation nsIDocument* doc = content->GetOwnerDoc(); if (!doc) { @@ -1045,7 +1050,7 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen if (mPrototypeBinding->HasImplementation()) { nsIScriptGlobalObject *global = aOldDocument->GetScopeObject(); if (global) { - nsIScriptContext *context = global->GetContext(); + nsCOMPtr context = global->GetContext(); if (context) { JSContext *cx = (JSContext *)context->GetNativeContext(); @@ -1062,8 +1067,6 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen if (NS_FAILED(rv)) return; - mPrototypeBinding->UndefineFields(cx, scriptObject); - // XXX Stay in sync! What if a layered binding has an // ?! // XXXbz what does that comment mean, really? It seems to date @@ -1115,6 +1118,13 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen break; } + // Do this after unhooking the proto to avoid extra walking along + // the proto chain as the JS engine tries to resolve the properties + // we're removing. + mBoundElement->SetFlags(NODE_IS_IN_BINDING_TEARDOWN); + mPrototypeBinding->UndefineFields(cx, scriptObject); + mBoundElement->UnsetFlags(NODE_IS_IN_BINDING_TEARDOWN); + // Don't remove the reference from the document to the // wrapper here since it'll be removed by the element // itself when that's taken out of the document. diff --git a/content/xbl/test/Makefile.in b/content/xbl/test/Makefile.in index 29bd04f77d4..97934fcd2f0 100644 --- a/content/xbl/test/Makefile.in +++ b/content/xbl/test/Makefile.in @@ -55,6 +55,7 @@ _TEST_FILES = \ test_bug378866.xhtml \ test_bug397934.xhtml \ test_bug398135.xhtml \ + test_bug400705.xhtml \ bug310107-resource.xhtml \ $(NULL) diff --git a/content/xbl/test/test_bug400705.xhtml b/content/xbl/test/test_bug400705.xhtml new file mode 100644 index 00000000000..05451953712 --- /dev/null +++ b/content/xbl/test/test_bug400705.xhtml @@ -0,0 +1,49 @@ + + + + Test for Bug 400705 + + + + + + + window.countera++ + window.counterb++ + + + + + +Mozilla Bug 400705 +

+ +
+
+
+ + +