Bug 425551: Improve script blocker code and use it to prevent async DOM events from keeping link elements alive past CC. Patch by bent. r/sr=sicking
authorjonas@sicking.cc
Tue, 08 Apr 2008 19:06:27 -0700
changeset 14102 bddcea48423e3d8bc68f5e6171f8141dccf9eda4
parent 14101 2f02dcde22b3b3af8c13919fb5a1a8e965fe53a3
child 14103 350686802a9678875509521466cf3d0a37d9771d
push id11
push userbsmedberg@mozilla.com
push dateTue, 15 Apr 2008 18:11:53 +0000
treeherdermozilla-central@40e4b99f0dea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs425551
milestone1.9pre
Bug 425551: Improve script blocker code and use it to prevent async DOM events from keeping link elements alive past CC. Patch by bent. r/sr=sicking
content/base/public/nsIDocument.h
content/base/src/Makefile.in
content/base/src/nsAttrAndChildArray.cpp
content/base/src/nsContentSink.cpp
content/base/src/nsContentUtils.cpp
content/base/src/nsDocument.cpp
content/base/src/nsGenericDOMDataNode.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsObjectLoadingContent.cpp
content/events/public/nsPLDOMEvent.h
content/events/src/nsPLDOMEvent.cpp
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsHTMLFormElement.cpp
content/html/content/src/nsHTMLHeadingElement.cpp
content/html/content/src/nsHTMLInputElement.cpp
content/html/content/src/nsHTMLLinkElement.cpp
content/html/content/src/nsHTMLOptionElement.cpp
content/html/content/src/nsHTMLTextAreaElement.cpp
content/html/document/src/nsHTMLContentSink.cpp
content/html/document/src/nsHTMLDocument.cpp
content/mathml/content/src/nsMathMLElement.cpp
content/svg/content/src/nsSVGUseElement.cpp
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLInsertionPoint.cpp
content/xbl/src/nsXBLPrototypeBinding.cpp
content/xml/document/src/nsXMLContentSink.cpp
content/xtf/src/nsXTFElementWrapper.cpp
content/xul/content/src/nsXULElement.cpp
content/xul/templates/src/nsXULContentBuilder.cpp
editor/libeditor/html/nsHTMLAnonymousUtils.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/base/nsPresShell.cpp
layout/generic/nsFrameSetFrame.cpp
layout/style/nsCSSStyleRule.cpp
layout/style/nsCSSStyleSheet.cpp
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1057,55 +1057,16 @@ private:
   // optimizations. This will be set once this document is touched
   // from JS, and it will be unset once the JSObject is finalized.
   JSObject *mJSObject;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
 
 /**
- * Helper class to automatically handle batching of document updates.  This
- * class will call BeginUpdate on construction and EndUpdate on destruction on
- * the given document with the given update type.  The document could be null,
- * in which case no updates will be called.  The constructor also takes a
- * boolean that can be set to false to prevent notifications.
- */
-class mozAutoDocUpdate
-{
-public:
-  mozAutoDocUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType,
-                   PRBool aNotify) :
-    mDocument(aNotify ? aDocument : nsnull),
-    mUpdateType(aUpdateType)
-  {
-    if (mDocument) {
-      mDocument->BeginUpdate(mUpdateType);
-    }
-  }
-
-  ~mozAutoDocUpdate()
-  {
-    if (mDocument) {
-      mDocument->EndUpdate(mUpdateType);
-    }
-  }
-
-private:
-  nsCOMPtr<nsIDocument> mDocument;
-  nsUpdateType mUpdateType;
-};
-
-#define MOZ_AUTO_DOC_UPDATE_PASTE2(tok,line) tok##line
-#define MOZ_AUTO_DOC_UPDATE_PASTE(tok,line) \
-  MOZ_AUTO_DOC_UPDATE_PASTE2(tok,line)
-#define MOZ_AUTO_DOC_UPDATE(doc,type,notify) \
-  mozAutoDocUpdate MOZ_AUTO_DOC_UPDATE_PASTE(_autoDocUpdater_, __LINE__) \
-  (doc,type,notify)
-
-/**
  * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
  * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
  * object is deleted.
  */
 class mozAutoSubtreeModified
 {
 public:
   /**
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -97,16 +97,17 @@ EXPORTS		= \
 		nsGkAtoms.h \
 		nsNodeInfoManager.h \
 		nsPropertyTable.h \
 		nsScriptLoader.h \
 		nsStubDocumentObserver.h \
 		nsStubImageDecoderObserver.h \
 		nsStubMutationObserver.h \
 		nsTextFragment.h \
+		mozAutoDocUpdate.h \
 		$(NULL)
 
 CPPSRCS		= \
 		mozSanitizingSerializer.cpp \
 		nsAtomListUtils.cpp \
 		nsAttrAndChildArray.cpp \
 		nsAttrValue.cpp \
 		nsCCUncollectableMarker.cpp \
--- a/content/base/src/nsAttrAndChildArray.cpp
+++ b/content/base/src/nsAttrAndChildArray.cpp
@@ -637,16 +637,17 @@ nsAttrAndChildArray::Clear()
     NS_RELEASE(mImpl->mMappedAttrs);
   }
 
   PRUint32 i, slotCount = AttrSlotCount();
   for (i = 0; i < slotCount && mImpl->mBuffer[i * ATTRSIZE]; ++i) {
     ATTRS(mImpl)[i].~InternalAttr();
   }
 
+  nsAutoScriptBlocker scriptBlocker;
   PRUint32 end = slotCount * ATTRSIZE + ChildCount();
   for (i = slotCount * ATTRSIZE; i < end; ++i) {
     nsIContent* child = static_cast<nsIContent*>(mImpl->mBuffer[i]);
     // making this PR_FALSE so tree teardown doesn't end up being
     // O(N*D) (number of nodes times average depth of tree).
     child->UnbindFromTree(PR_FALSE); // XXX is it better to let the owner do this?
     NS_RELEASE(child);
   }
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -88,16 +88,17 @@
 #include "nsWidgetsCID.h"
 #include "nsIDOMNSDocument.h"
 #include "nsIRequest.h"
 #include "nsNodeUtils.h"
 #include "nsIDOMNode.h"
 #include "nsThreadUtils.h"
 #include "nsPresShellIterator.h"
 #include "nsPIDOMWindow.h"
+#include "mozAutoDocUpdate.h"
 
 PRLogModuleInfo* gContentSinkLogModuleInfo;
 
 class nsScriptLoaderObserverProxy : public nsIScriptLoaderObserver
 {
 public:
   nsScriptLoaderObserverProxy(nsIScriptLoaderObserver* aInner)
     : mInner(do_GetWeakReference(aInner))
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -157,16 +157,18 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_
 #endif
 #include "nsCycleCollectionParticipant.h"
 
 // for ReportToConsole
 #include "nsIStringBundle.h"
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 
+#include "mozAutoDocUpdate.h"
+
 const char kLoadAsData[] = "loadAsData";
 
 static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 nsIDOMScriptObjectFactory *nsContentUtils::sDOMScriptObjectFactory = nsnull;
 nsIXPConnect *nsContentUtils::sXPConnect;
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -155,16 +155,18 @@ static NS_DEFINE_CID(kDOMEventGroupCID, 
 #include "nsIJSContextStack.h"
 #include "nsIXPConnect.h"
 #include "nsCycleCollector.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsIContentPolicy.h"
 
 #include "nsFrameLoader.h"
 
+#include "mozAutoDocUpdate.h"
+
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
 #define FORCE_PR_LOG 1
 #endif
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gDocumentLeakPRLog;
@@ -826,16 +828,18 @@ nsDocument::~nsDocument()
 
     mSubDocuments = nsnull;
   }
 
   // Destroy link map now so we don't waste time removing
   // links one by one
   DestroyLinkMap();
 
+  nsAutoScriptBlocker scriptBlocker;
+
   PRInt32 indx; // must be signed
   PRUint32 count = mChildren.ChildCount();
   for (indx = PRInt32(count) - 1; indx >= 0; --indx) {
     mChildren.ChildAt(indx)->UnbindFromTree();
     mChildren.RemoveChildAt(indx);
   }
   mCachedRootContent = nsnull;
 
@@ -1080,16 +1084,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
   // Tear down linkmap. This is a performance optimization so that we
   // don't waste time removing links one by one as they are removed
   // from the doc.
   tmp->DestroyLinkMap();
 
+  nsAutoScriptBlocker scriptBlocker;
+
   // Unlink the mChildren nsAttrAndChildArray.
   for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()) - 1; 
        indx >= 0; --indx) {
     tmp->mChildren.ChildAt(indx)->UnbindFromTree();
     tmp->mChildren.RemoveChildAt(indx);
   }
 
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootContent)
--- a/content/base/src/nsGenericDOMDataNode.cpp
+++ b/content/base/src/nsGenericDOMDataNode.cpp
@@ -57,16 +57,17 @@
 #include "nsDOMString.h"
 #include "nsIDOMUserDataHandler.h"
 #include "nsChangeHint.h"
 #include "nsEventDispatcher.h"
 #include "nsCOMArray.h"
 #include "nsNodeUtils.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
+#include "mozAutoDocUpdate.h"
 
 #include "pldhash.h"
 #include "prprf.h"
 
 nsGenericDOMDataNode::nsGenericDOMDataNode(nsINodeInfo *aNodeInfo)
   : nsIContent(aNodeInfo)
 {
 }
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -133,16 +133,18 @@
 #ifdef ACCESSIBILITY
 #include "nsIAccessibilityService.h"
 #include "nsIAccessibleEvent.h"
 #endif /* ACCESSIBILITY */
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsCCUncollectableMarker.h"
 
+#include "mozAutoDocUpdate.h"
+
 #ifdef MOZ_SVG
 PRBool NS_SVG_TestFeature(const nsAString &fstr);
 #endif /* MOZ_SVG */
 
 #ifdef DEBUG_waterson
 
 /**
  * List a content tree to stdout. Meant to be called from gdb.
@@ -2038,17 +2040,18 @@ nsGenericElement::BindToTree(nsIDocument
                   !aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
                   "Parent in document but flagged as forcing XBL");
   NS_PRECONDITION(aBindingParent != this || IsNativeAnonymous(),
                   "Only native anonymous content should have itself as its "
                   "own binding parent");
   NS_PRECONDITION(!IsNativeAnonymous() || aBindingParent == this,
                   "Native anonymous content must have itself as its "
                   "own binding parent");
-  
+  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "Need a script blocker!");
+
   if (!aBindingParent && aParent) {
     aBindingParent = aParent->GetBindingParent();
   }
 
 #ifdef MOZ_XUL
   // First set the binding parent
   nsXULElement* xulElem = nsXULElement::FromContent(this);
   if (xulElem) {
@@ -2170,16 +2173,17 @@ nsGenericElement::BindToTree(nsIDocument
 }
 
 void
 nsGenericElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   NS_PRECONDITION(aDeep || (!GetCurrentDoc() && !GetBindingParent()),
                   "Shallow unbind won't clear document and binding parent on "
                   "kids!");
+  NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "Need a script blocker!");
   // Make sure to unbind this node before doing the kids
   nsIDocument *document =
     HasFlag(NODE_FORCE_XBL_BINDINGS) ? GetOwnerDoc() : GetCurrentDoc();
   if (document) {
     // Notify XBL- & nsIAnonymousContentCreator-generated
     // anonymous content that the document is changing.
     document->BindingManager()->ChangeDocumentFor(this, document, nsnull);
 
@@ -3451,23 +3455,27 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
 
   if (tmp->HasProperties() && tmp->IsNodeOfType(nsINode::eXUL)) {
     tmp->DeleteProperty(nsGkAtoms::contextmenulistener);
     tmp->DeleteProperty(nsGkAtoms::popuplistener);
   }
 
   // Unlink child content (and unbind our subtree).
   {
-    PRUint32 i;
-    PRUint32 kids = tmp->mAttrsAndChildren.ChildCount();
-    for (i = kids; i > 0; i--) {
-      // We could probably do a non-deep unbind here when IsInDoc is false
-      // for better performance.
-      tmp->mAttrsAndChildren.ChildAt(i-1)->UnbindFromTree();
-      tmp->mAttrsAndChildren.RemoveChildAt(i-1);    
+    PRUint32 childCount = tmp->mAttrsAndChildren.ChildCount();
+    if (childCount) {
+      // Don't allow script to run while we're unbinding everything.
+      nsAutoScriptBlocker scriptBlocker;
+      while (childCount-- > 0) {
+        // Once we have XPCOMGC we shouldn't need to call UnbindFromTree.
+        // We could probably do a non-deep unbind here when IsInDoc is false
+        // for better performance.
+        tmp->mAttrsAndChildren.ChildAt(childCount)->UnbindFromTree();
+        tmp->mAttrsAndChildren.RemoveChildAt(childCount);
+      }
     }
   }  
 
   // Unlink any DOM slots of interest.
   {
     nsDOMSlots *slots = tmp->GetExistingDOMSlots();
     if (slots) {
       if (slots->mAttributeMap) {
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -72,16 +72,18 @@
 #include "nsIDOMNode.h"
 
 #include "nsContentUtils.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsDOMClassInfo.h"
 
+#include "mozAutoDocUpdate.h"
+
 #ifdef DEBUG_chb
 static void PrintReqURL(imgIRequest* req) {
   if (!req) {
     printf("(null req)\n");
     return;
   }
 
   nsCOMPtr<nsIURI> uri;
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -78,16 +78,17 @@
 #include "nsPresShellIterator.h"
 #include "nsMimeTypes.h"
 #include "nsStyleUtil.h"
 
 // Concrete classes
 #include "nsFrameLoader.h"
 
 #include "nsObjectLoadingContent.h"
+#include "mozAutoDocUpdate.h"
 
 static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID);
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc");
 #endif
 
 #define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args)
--- a/content/events/public/nsPLDOMEvent.h
+++ b/content/events/public/nsPLDOMEvent.h
@@ -61,15 +61,16 @@ public:
   { }
 
   nsPLDOMEvent(nsIDOMNode *aEventNode, nsIDOMEvent *aEvent)
     : mEventNode(aEventNode), mEvent(aEvent)
   { }
 
   NS_IMETHOD Run();
   nsresult PostDOMEvent();
+  nsresult RunDOMEventWhenSafe();
 
   nsCOMPtr<nsIDOMNode>  mEventNode;
   nsCOMPtr<nsIDOMEvent> mEvent;
   nsString              mEventType;
 };
 
 #endif
--- a/content/events/src/nsPLDOMEvent.cpp
+++ b/content/events/src/nsPLDOMEvent.cpp
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsPLDOMEvent.h"
 #include "nsIDOMEvent.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMDocumentEvent.h"
 #include "nsIDOMEventTarget.h"
+#include "nsContentUtils.h"
 
 NS_IMETHODIMP nsPLDOMEvent::Run()
 {
   if (!mEventNode) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIDOMEvent> domEvent(mEvent);
@@ -71,8 +72,13 @@ NS_IMETHODIMP nsPLDOMEvent::Run()
 
   return NS_OK;
 }
 
 nsresult nsPLDOMEvent::PostDOMEvent()
 {
   return NS_DispatchToCurrentThread(this);
 }
+
+nsresult nsPLDOMEvent::RunDOMEventWhenSafe()
+{
+  return nsContentUtils::AddScriptRunner(this) ? NS_OK : NS_ERROR_FAILURE;
+}
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -105,16 +105,17 @@
 
 #include "nsIDOMText.h"
 
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
 #include "nsEventDispatcher.h"
 #include "nsLayoutUtils.h"
 #include "nsContentCreatorFunctions.h"
+#include "mozAutoDocUpdate.h"
 
 class nsINodeInfo;
 class nsIDOMNodeList;
 class nsRuleWalker;
 
 static nsIFrame*
 GetStyledFrameFor(nsGenericHTMLElement* aElement)
 {
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -82,16 +82,18 @@
 #include "nsIRadioVisitor.h"
 #include "nsIRadioGroupContainer.h"
 
 #include "nsLayoutUtils.h"
 
 #include "nsUnicharUtils.h"
 #include "nsEventDispatcher.h"
 
+#include "mozAutoDocUpdate.h"
+
 static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
 
 class nsFormControlList;
 
 /**
  * hashkey wrapper using nsAString KeyType
  *
  * @see nsTHashtable::EntryType for specification
--- a/content/html/content/src/nsHTMLHeadingElement.cpp
+++ b/content/html/content/src/nsHTMLHeadingElement.cpp
@@ -37,16 +37,17 @@
 #include "nsIDOMHTMLHeadingElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsGenericHTMLElement.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsMappedAttributes.h"
 #include "nsRuleData.h"
+#include "mozAutoDocUpdate.h"
 
 class nsHTMLHeadingElement : public nsGenericHTMLElement,
                              public nsIDOMHTMLHeadingElement
 {
 public:
   nsHTMLHeadingElement(nsINodeInfo *aNodeInfo);
   virtual ~nsHTMLHeadingElement();
 
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -106,16 +106,18 @@
 #include "nsIFileStreams.h"
 #include "nsNetUtil.h"
 #include "nsDOMFile.h"
 
 // input type=image
 #include "nsImageLoadingContent.h"
 #include "nsIDOMWindowInternal.h"
 
+#include "mozAutoDocUpdate.h"
+
 // XXX align=left, hspace, vspace, border? other nav4 attrs
 
 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
 //
 // Accessors for mBitField
 //
 #define BF_DISABLED_CHANGED 0
 #define BF_HANDLING_CLICK 1
--- a/content/html/content/src/nsHTMLLinkElement.cpp
+++ b/content/html/content/src/nsHTMLLinkElement.cpp
@@ -204,20 +204,16 @@ nsHTMLLinkElement::BindToTree(nsIDocumen
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   UpdateStyleSheetInternal(nsnull);
 
-  // XXXbz we really shouldn't fire the event until after we've finished with
-  // the outermost BindToTree...  In particular, this can effectively cause us
-  // to reenter this code, or for some part of the document to become unbound
-  // inside the event!
   CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded"));
 
   return rv;  
 }
 
 NS_IMETHODIMP
 nsHTMLLinkElement::LinkAdded()
 {
@@ -238,20 +234,18 @@ nsHTMLLinkElement::UnbindFromTree(PRBool
   nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
   if (oldDoc) {
     GetCurrentDoc()->ForgetLink(this);
     // If this link is ever reinserted into a document, it might
     // be under a different xml:base, so forget the cached state now
     mLinkState = eLinkState_Unknown;
   }
 
-  // XXXbz we really shouldn't fire the event until after we've finished with
-  // the outermost UnbindFromTree...  In particular, this can effectively cause
-  // us to reenter this code, or to be bound to a different tree inside the
-  // event!
+  // Once we have XPCOMGC we shouldn't need to call UnbindFromTree during Unlink
+  // and so this messy event dispatch can go away.
   CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
   UpdateStyleSheetInternal(oldDoc);
 }
 
 void
 nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
                                           const nsAString& aEventName)
@@ -271,17 +265,17 @@ nsHTMLLinkElement::CreateAndDispatchEven
   if (!nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
                                        nsGkAtoms::rev) &&
       FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::rel,
                       strings, eIgnoreCase) != ATTR_VALUE_NO_MATCH)
     return;
 
   nsRefPtr<nsPLDOMEvent> event = new nsPLDOMEvent(this, aEventName);
   if (event) {
-    event->PostDOMEvent();
+    event->RunDOMEventWhenSafe();
   }
 }
 
 nsresult
 nsHTMLLinkElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            PRBool aNotify)
 {
--- a/content/html/content/src/nsHTMLOptionElement.cpp
+++ b/content/html/content/src/nsHTMLOptionElement.cpp
@@ -64,16 +64,17 @@
 #include "nsIFrame.h"
 #include "nsIDOMHTMLSelectElement.h"
 #include "nsNodeInfoManager.h"
 #include "nsCOMPtr.h"
 #include "nsIEventStateManager.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsContentCreatorFunctions.h"
+#include "mozAutoDocUpdate.h"
 
 /**
  * Implementation of &lt;option&gt;
  */
 class nsHTMLOptionElement : public nsGenericHTMLElement,
                             public nsIDOMHTMLOptionElement,
                             public nsIDOMNSHTMLOptionElement,
                             public nsIJSNativeInitializer,
--- a/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -70,16 +70,17 @@
 #include "nsPresState.h"
 #include "nsIDOMText.h"
 #include "nsReadableUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsLayoutUtils.h"
 #include "nsLayoutErrors.h"
 #include "nsStubMutationObserver.h"
 #include "nsDOMError.h"
+#include "mozAutoDocUpdate.h"
 
 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
 
 #define NS_NO_CONTENT_DISPATCH (1 << 0)
 
 class nsHTMLTextAreaElement : public nsGenericHTMLFormElement,
                               public nsIDOMHTMLTextAreaElement,
                               public nsIDOMNSHTMLTextAreaElement,
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -116,16 +116,17 @@
 #include "nsIPrompt.h"
 #include "nsLayoutCID.h"
 #include "nsIDocShellTreeItem.h"
 
 #include "nsEscape.h"
 #include "nsIElementObserver.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
+#include "mozAutoDocUpdate.h"
 
 #ifdef NS_DEBUG
 static PRLogModuleInfo* gSinkLogModuleInfo;
 
 #define SINK_TRACE_NODE(_bit, _msg, _tag, _sp, _obj) \
   _obj->SinkTraceNode(_bit, _msg, _tag, _sp, this)
 
 #else
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -135,16 +135,17 @@
 #include "nsIEditingSession.h"
 #include "nsIEditor.h"
 #include "nsNodeInfoManager.h"
 #include "nsIEditor.h"
 #include "nsIEditorDocShell.h"
 #include "nsIEditorStyleSheets.h"
 #include "nsIInlineSpellChecker.h"
 #include "nsRange.h"
+#include "mozAutoDocUpdate.h"
 
 #define NS_MAX_DOCUMENT_WRITE_DEPTH 20
 
 #define DETECTOR_CONTRACTID_MAX 127
 static char g_detector_contractid[DETECTOR_CONTRACTID_MAX + 1];
 static PRBool gInitDetector = PR_FALSE;
 static PRBool gPlugDetector = PR_FALSE;
 
--- a/content/mathml/content/src/nsMathMLElement.cpp
+++ b/content/mathml/content/src/nsMathMLElement.cpp
@@ -46,16 +46,17 @@
 #include "nsMappedAttributes.h"
 #include "nsStyleConsts.h"
 #include "nsIDocument.h"
 #include "nsIEventStateManager.h"
 #include "nsPresShellIterator.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
 #include "nsDOMClassInfoID.h"
+#include "mozAutoDocUpdate.h"
 
 //----------------------------------------------------------------------
 // nsISupports methods:
 
 NS_IMETHODIMP 
 nsMathMLElement::QueryInterface(REFNSIID aIID, void** aInstancePtr)
 {
   NS_PRECONDITION(aInstancePtr, "null out param");
--- a/content/svg/content/src/nsSVGUseElement.cpp
+++ b/content/svg/content/src/nsSVGUseElement.cpp
@@ -60,16 +60,17 @@ nsSVGElement::LengthInfo nsSVGUseElement
 NS_IMPL_NS_NEW_SVG_ELEMENT(Use)
 
 //----------------------------------------------------------------------
 // nsISupports methods
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGUseElement)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsSVGUseElement,
                                                 nsSVGUseElementBase)
+  nsAutoScriptBlocker scriptBlocker;
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginal)
   tmp->DestroyAnonymousContent();
   tmp->RemoveListener();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsSVGUseElement,
                                                   nsSVGUseElementBase)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginal)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mClone)
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -340,16 +340,18 @@ nsXBLBinding::InstallAnonymousContent(ns
   // quite simply does not matter.  aAnonParent is just a way of keeping refs
   // to all its kids, which are anonymous content from the point of view of
   // aElement.
   // (2) The children's parent back pointer should not be to this synthetic root
   // but should instead point to the enclosing parent element.
   nsIDocument* doc = aElement->GetCurrentDoc();
   PRBool allowScripts = AllowScripts();
 
+  nsAutoScriptBlocker scriptBlocker;
+
   PRUint32 childCount = aAnonParent->GetChildCount();
   for (PRUint32 i = 0; i < childCount; i++) {
     nsIContent *child = aAnonParent->GetChildAt(i);
     child->UnbindFromTree();
     nsresult rv =
       child->BindToTree(doc, aElement, mBoundElement, allowScripts);
     if (NS_FAILED(rv)) {
       // Oh, well... Just give up.
@@ -1134,16 +1136,17 @@ nsXBLBinding::ChangeDocument(nsIDocument
       if (mInsertionPointTable)
         mInsertionPointTable->Enumerate(ChangeDocumentForDefaultContent,
                                         nsnull);
 
 #ifdef MOZ_XUL
       nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(aOldDocument));
 #endif
 
+      nsAutoScriptBlocker scriptBlocker;
       anonymous->UnbindFromTree(); // Kill it.
 
 #ifdef MOZ_XUL
       // To make XUL templates work (and other XUL-specific stuff),
       // we'll need to notify it using its add & remove APIs. Grab the
       // interface now...
       if (xuldoc)
         xuldoc->RemoveSubtreeFromDocument(anonymous);
--- a/content/xbl/src/nsXBLInsertionPoint.cpp
+++ b/content/xbl/src/nsXBLInsertionPoint.cpp
@@ -32,16 +32,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsXBLInsertionPoint.h"
+#include "nsContentUtils.h"
 
 nsXBLInsertionPoint::nsXBLInsertionPoint(nsIContent* aParentElement,
                                          PRUint32 aIndex,
                                          nsIContent* aDefaultContent)
   : mParentElement(aParentElement),
     mIndex(aIndex),
     mDefaultContentTemplate(aDefaultContent)
 {
@@ -120,16 +121,18 @@ nsXBLInsertionPoint::UnbindDefaultConten
 {
   if (!mDefaultContent) {
     return;
   }
 
   // Hold a strong ref while doing this, just in case
   nsCOMPtr<nsIContent> defContent = mDefaultContent;
 
+  nsAutoScriptBlocker scriptBlocker;
+
   // Unbind the _kids_ of the default content, not just the default content
   // itself, since they are bound to some other parent.  Basically we want to
   // undo the mess that InstallAnonymousContent created.
   PRUint32 childCount = mDefaultContent->GetChildCount();
   for (PRUint32 i = 0; i < childCount; i++) {
     defContent->GetChildAt(i)->UnbindFromTree();
   }
 
--- a/content/xbl/src/nsXBLPrototypeBinding.cpp
+++ b/content/xbl/src/nsXBLPrototypeBinding.cpp
@@ -136,16 +136,17 @@ private:
 // info to figure out the position of an insertion point.
 // The same insertion point may be in the insertion point table for multiple
 // keys, so we refcount the entries.
 
 class nsXBLInsertionPointEntry {
 public:
   ~nsXBLInsertionPointEntry() {
     if (mDefaultContent) {
+      nsAutoScriptBlocker scriptBlocker;
       // mDefaultContent is a sort of anonymous content within the XBL
       // document, and we own and manage it.  Unhook it here, since we're going
       // away.
       mDefaultContent->UnbindFromTree();
     }      
   }
 
   NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLInsertionPointEntry)
@@ -243,16 +244,17 @@ private:
 
 PRUint32 nsXBLInsertionPointEntry::gRefCnt = 0;
 nsFixedSizeAllocator* nsXBLInsertionPointEntry::kPool;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXBLInsertionPointEntry)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsXBLInsertionPointEntry)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mInsertionParent)
   if (tmp->mDefaultContent) {
+    nsAutoScriptBlocker scriptBlocker;
     // mDefaultContent is a sort of anonymous content within the XBL
     // document, and we own and manage it.  Unhook it here, since we're going
     // away.
     tmp->mDefaultContent->UnbindFromTree();
     tmp->mDefaultContent = nsnull;
   }      
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsXBLInsertionPointEntry)
@@ -1280,16 +1282,17 @@ nsXBLPrototypeBinding::ConstructInsertio
     // it clones the binding template.
     parent->RemoveChildAt(index, PR_FALSE);
 
     // See if the insertion point contains default content.  Default content must
     // be cached in our insertion point entry, since it will need to be cloned
     // in situations where no content ends up being placed at the insertion point.
     PRUint32 defaultCount = child->GetChildCount();
     if (defaultCount > 0) {
+      nsAutoScriptBlocker scriptBlocker;
       // Annotate the insertion point with our default content.
       xblIns->SetDefaultContent(child);
 
       // Reconnect back to our parent for access later.  This makes "inherits" easier
       // to work with on default content.
       // XXXbz this is somewhat screwed up, since it's sort of like anonymous
       // content... but not.
       nsresult rv =
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -91,16 +91,17 @@
 #include "nsContentCreatorFunctions.h"
 #include "nsIContentPolicy.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentErrors.h"
 #include "nsIDOMProcessingInstruction.h"
 #include "nsNodeUtils.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsEventDispatcher.h"
+#include "mozAutoDocUpdate.h"
 
 #ifdef MOZ_SVG
 #include "nsGUIEvent.h"
 #endif
 
 #define kXSLType "text/xsl"
 
 // XXX Open Issues:
--- a/content/xtf/src/nsXTFElementWrapper.cpp
+++ b/content/xtf/src/nsXTFElementWrapper.cpp
@@ -57,16 +57,17 @@
 #include "nsIDOMAttr.h"
 #include "nsIAttribute.h"
 #include "nsDOMAttributeMap.h"
 #include "nsUnicharUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIXPConnect.h"
 #include "nsXTFWeakTearoff.h"
+#include "mozAutoDocUpdate.h"
 
 nsXTFElementWrapper::nsXTFElementWrapper(nsINodeInfo* aNodeInfo,
                                          nsIXTFElement* aXTFElement)
     : nsXTFElementWrapperBase(aNodeInfo),
       mXTFElement(aXTFElement),
       mNotificationMask(0),
       mIntrinsicState(0),
       mTmpAttrName(nsGkAtoms::_asterix) // XXX this is a hack, but names
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -146,16 +146,17 @@
 
 #include "nsReadableUtils.h"
 #include "nsITimelineService.h"
 #include "nsIFrame.h"
 #include "nsNodeInfoManager.h"
 #include "nsXBLBinding.h"
 #include "nsEventDispatcher.h"
 #include "nsPresShellIterator.h"
+#include "mozAutoDocUpdate.h"
 
 /**
  * Three bits are used for XUL Element's lazy state.
  */
 #define XUL_ELEMENT_CHILDREN_MUST_BE_REBUILT \
   (nsXULElement::eChildrenMustBeRebuilt << XUL_ELEMENT_LAZY_STATE_OFFSET)
 
 #define XUL_ELEMENT_TEMPLATE_CONTENTS_BUILT \
--- a/content/xul/templates/src/nsXULContentBuilder.cpp
+++ b/content/xul/templates/src/nsXULContentBuilder.cpp
@@ -61,16 +61,17 @@
 #include "nsXULElement.h"
 #include "nsXULTemplateBuilder.h"
 #include "nsSupportsArray.h"
 #include "nsNodeInfoManager.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentUtils.h"
 #include "nsAttrName.h"
 #include "nsNodeUtils.h"
+#include "mozAutoDocUpdate.h"
 
 #include "jsapi.h"
 #include "pldhash.h"
 #include "rdf.h"
 
 //----------------------------------------------------------------------
 //
 // Return values for EnsureElementHasGenericChild()
--- a/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
+++ b/editor/libeditor/html/nsHTMLAnonymousUtils.cpp
@@ -54,16 +54,17 @@
 #include "nsIDOMNSHTMLElement.h"
 #include "nsIDOMEventTarget.h"
 
 #include "nsIDOMCSSValue.h"
 #include "nsIDOMCSSPrimitiveValue.h"
 #include "nsIDOMCSSStyleDeclaration.h"
 #include "nsIMutationObserver.h"
 #include "nsUnicharUtils.h"
+#include "nsContentUtils.h"
 
 // retrieve an integer stored into a CSS computed float value
 static PRInt32 GetCSSFloatValue(nsIDOMCSSStyleDeclaration * aDecl,
                                 const nsAString & aProperty)
 {
   NS_ENSURE_ARG_POINTER(aDecl);
 
   nsCOMPtr<nsIDOMCSSValue> value;
@@ -177,22 +178,26 @@ nsHTMLEditor::CreateAnonymousElement(con
 
   // add an _moz_anonclass attribute if needed
   if (!aAnonClass.IsEmpty()) {
     res = newElement->SetAttribute(NS_LITERAL_STRING("_moz_anonclass"),
                                    aAnonClass);
     if (NS_FAILED(res)) return res;
   }
 
-  // establish parenthood of the element
-  newContent->SetNativeAnonymous();
-  res = newContent->BindToTree(doc, parentContent, newContent, PR_TRUE);
-  if (NS_FAILED(res)) {
-    newContent->UnbindFromTree();
-    return res;
+  {
+    nsAutoScriptBlocker scriptBlocker;
+
+    // establish parenthood of the element
+    newContent->SetNativeAnonymous();
+    res = newContent->BindToTree(doc, parentContent, newContent, PR_TRUE);
+    if (NS_FAILED(res)) {
+      newContent->UnbindFromTree();
+      return res;
+    }
   }
 
   nsElementDeletionObserver* observer =
     new nsElementDeletionObserver(newContent, parentContent);
   if (!observer) {
     newContent->UnbindFromTree();
     return NS_ERROR_OUT_OF_MEMORY;
   }
@@ -232,16 +237,17 @@ nsHTMLEditor::DeleteRefToAnonymousNode(n
 {
   // call ContentRemoved() for the anonymous content
   // node so its references get removed from the frame manager's
   // undisplay map, and its layout frames get destroyed!
 
   if (aElement) {
     nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
     if (content) {
+      nsAutoScriptBlocker scriptBlocker;
       // Need to check whether aShell has been destroyed (but not yet deleted).
       // In that case presContext->GetPresShell() returns nsnull.
       // See bug 338129.
       if (aShell && aShell->GetPresContext() &&
           aShell->GetPresContext()->GetPresShell() == aShell) {
         nsCOMPtr<nsIDocumentObserver> docObserver = do_QueryInterface(aShell);
         if (docObserver) {
           // Call BeginUpdate() so that the nsCSSFrameConstructor/PresShell
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -13447,16 +13447,18 @@ nsCSSFrameConstructor::ProcessPendingRes
 
   NS_ASSERTION(lastRestyle - restylesToProcess == PRInt32(count),
                "Enumeration screwed up somehow");
 
   // Clear the hashtable so we don't end up trying to process a restyle we're
   // already processing, sending us into an infinite loop.
   mPendingRestyles.Clear();
 
+  nsAutoScriptBlocker scriptBlocker;
+
   // Make sure to not rebuild quote or counter lists while we're
   // processing restyles
   BeginUpdate();
 
   for (RestyleEnumerateData* currentRestyle = restylesToProcess;
        currentRestyle != lastRestyle;
        ++currentRestyle) {
     ProcessOneRestyle(currentRestyle->mContent,
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1699,16 +1699,18 @@ PresShell::Destroy()
   // pending reflows before we destroy the frame manager, since
   // apparently frame destruction sometimes spins the event queue when
   // plug-ins are involved(!).
   mReflowEvent.Revoke();
 
   CancelAllPendingReflows();
   CancelPostedReflowCallbacks();
 
+  nsAutoScriptBlocker scriptBlocker;
+
   // Destroy the frame manager. This will destroy the frame hierarchy
   mFrameConstructor->WillDestroyFrameTree();
   FrameManager()->Destroy();
 
   NS_WARN_IF_FALSE(!mWeakFrames, "Weak frames alive after destroying FrameManager");
   while (mWeakFrames) {
     mWeakFrames->Clear(this);
   }
@@ -4600,16 +4602,17 @@ PresShell::DoFlushPendingNotifications(m
       mFrameConstructor->ProcessPendingRestyles();
     }
 
     // There might be more pending constructors now, but we're not going to
     // worry about them.  They can't be triggered during reflow, so we should
     // be good.
     
     if (aType >= Flush_Layout && !mIsDestroying) {
+      nsAutoScriptBlocker scriptBlocker;
       mFrameConstructor->RecalcQuotesAndCounters();
       ProcessReflowCommands(aInterruptibleReflow);
     }
 
     PRUint32 updateFlags = NS_VMREFRESH_NO_SYNC;
     if (aType >= Flush_Display) {
       // Flushing paints, so perform the invalidates and drawing
       // immediately
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -70,16 +70,17 @@
 #include "nsINameSpaceManager.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsAutoPtr.h"
 #include "nsStyleSet.h"
 #include "nsIContent.h"
 #include "nsDisplayList.h"
 #include "nsNodeUtils.h"
+#include "mozAutoDocUpdate.h"
 
 // masks for mEdgeVisibility
 #define LEFT_VIS   0x0001
 #define RIGHT_VIS  0x0002
 #define TOP_VIS    0x0004
 #define BOTTOM_VIS 0x0008
 #define ALL_VIS    0x000F
 #define NONE_VIS   0x0000
--- a/layout/style/nsCSSStyleRule.cpp
+++ b/layout/style/nsCSSStyleRule.cpp
@@ -71,16 +71,17 @@
 #include "nsRuleNode.h"
 #include "nsUnicharUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsIPrincipal.h"
 #include "nsComponentManagerUtils.h"
 
 #include "nsContentUtils.h"
 #include "nsContentErrors.h"
+#include "mozAutoDocUpdate.h"
 
 #define NS_IF_CLONE(member_)                                                  \
   PR_BEGIN_MACRO                                                              \
     if (member_) {                                                            \
       result->member_ = member_->Clone();                                     \
       if (!result->member_) {                                                 \
         delete result;                                                        \
         return nsnull;                                                        \
--- a/layout/style/nsCSSStyleSheet.cpp
+++ b/layout/style/nsCSSStyleSheet.cpp
@@ -69,16 +69,17 @@
 #include "nsICSSLoader.h"
 #include "nsICSSLoaderObserver.h"
 #include "nsINameSpaceManager.h"
 #include "nsXMLNameSpaceMap.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIJSContextStack.h"
 #include "nsIScriptSecurityManager.h"
+#include "mozAutoDocUpdate.h"
 
 // -------------------------------
 // Style Rule List for the DOM
 //
 class CSSRuleListImpl : public nsIDOMCSSRuleList
 {
 public:
   CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet);