Back out bug 591981 to see if it caused a performance regression. a=backout
authorJonas Sicking <jonas@sicking.cc>
Mon, 20 Sep 2010 15:47:57 -0700
changeset 54374 2b4ecab1e93a0631ef8fa068cac48e8f0bb436aa
parent 54373 925c97269a4ca6131387c5a7b750fceecb15eaa3
child 54376 f4978004fda110ae7874899d8ef9bb64dc4b4618
push idunknown
push userunknown
push dateunknown
reviewersbackout
bugs591981
milestone2.0b7pre
Back out bug 591981 to see if it caused a performance regression. a=backout
content/base/public/nsIScriptElement.h
content/base/src/nsContentSink.cpp
content/base/src/nsScriptElement.cpp
content/base/src/nsScriptElement.h
content/base/src/nsScriptLoader.cpp
content/base/src/nsScriptLoader.h
content/base/test/test_bug28293.html
content/base/test/test_bug28293.xhtml
content/html/content/src/nsHTMLScriptElement.cpp
content/html/content/test/test_bug300691-2.html
content/svg/content/src/nsSVGScriptElement.cpp
content/test/reftest/bug591981-1.html
content/test/reftest/bug591981-2.html
content/test/reftest/bug591981-ref.html
content/test/reftest/bug591981-script.js
content/test/reftest/reftest.list
dom/tests/mochitest/bugs/child_bug260264.html
dom/tests/mochitest/bugs/grandchild_bug260264.html
dom/tests/mochitest/bugs/test_bug260264.html
dom/tests/mochitest/bugs/utils_bug260264.js
--- a/content/base/public/nsIScriptElement.h
+++ b/content/base/public/nsIScriptElement.h
@@ -40,38 +40,36 @@
 #define nsIScriptElement_h___
 
 #include "nsISupports.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsIScriptLoaderObserver.h"
 #include "nsWeakPtr.h"
 #include "nsIParser.h"
-#include "nsContentCreatorFunctions.h"
 
 #define NS_ISCRIPTELEMENT_IID \
 { 0x6d625b30, 0xfac4, 0x11de, \
 { 0x8a, 0x39, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
 
 /**
  * Internal interface implemented by script elements
  */
 class nsIScriptElement : public nsIScriptLoaderObserver {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
 
-  nsIScriptElement(PRUint32 aFromParser)
+  nsIScriptElement()
     : mLineNumber(0),
-      mAlreadyStarted(PR_FALSE),
+      mIsEvaluated(PR_FALSE),
       mMalformed(PR_FALSE),
       mDoneAddingChildren(PR_TRUE),
       mFrozen(PR_FALSE),
       mDefer(PR_FALSE),
       mAsync(PR_FALSE),
-      mParserCreated((PRUint8)aFromParser),
       mCreatorParser(nsnull)
   {
   }
 
   /**
    * Content type identifying the scripting language. Can be empty, in
    * which case javascript will be assumed.
    */
@@ -114,25 +112,16 @@ public:
    * Is the script async. Currently only supported by HTML scripts.
    */
   PRBool GetScriptAsync()
   {
     NS_PRECONDITION(mFrozen, "Not ready for this call yet!");
     return mAsync;  
   }
 
-  /**
-   * Returns a constant defined in nsContentCreatorFunctions.h. Non-zero
-   * values mean parser-created and zero means not parser-created.
-   */
-  PRUint32 GetParserCreated()
-  {
-    return mParserCreated;
-  }
-
   void SetScriptLineNumber(PRUint32 aLineNumber)
   {
     mLineNumber = aLineNumber;
   }
   PRUint32 GetScriptLineNumber()
   {
     return mLineNumber;
   }
@@ -143,25 +132,17 @@ public:
   }
   PRBool IsMalformed()
   {
     return mMalformed;
   }
 
   void PreventExecution()
   {
-    mAlreadyStarted = PR_TRUE;
-  }
-
-  void LoseParserInsertedness()
-  {
-    mFrozen = PR_FALSE;
-    mUri = nsnull;
-    mCreatorParser = nsnull;
-    mParserCreated = NS_NOT_FROM_PARSER;
+    mIsEvaluated = PR_TRUE;
   }
 
   void SetCreatorParser(nsIParser* aParser)
   {
     mCreatorParser = getter_AddRefs(NS_GetWeakReference(aParser));
   }
 
   /**
@@ -199,17 +180,17 @@ protected:
   /**
    * The start line number of the script.
    */
   PRUint32 mLineNumber;
   
   /**
    * The "already started" flag per HTML5.
    */
-  PRPackedBool mAlreadyStarted;
+  PRPackedBool mIsEvaluated;
   
   /**
    * The script didn't have an end tag.
    */
   PRPackedBool mMalformed;
   
   /**
    * False if parser-inserted but the parser hasn't triggered running yet.
@@ -227,21 +208,16 @@ protected:
   PRPackedBool mDefer;
   
   /**
    * The effective asyncness.
    */
   PRPackedBool mAsync;
   
   /**
-   * Whether this element was parser-created.
-   */
-  PRUint8 mParserCreated;
-
-  /**
    * The effective src (or null if no src).
    */
   nsCOMPtr<nsIURI> mUri;
   
   /**
    * The creator parser of a non-defer, non-async parser-inserted script.
    */
   nsWeakPtr mCreatorParser;
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -361,18 +361,18 @@ nsContentSink::ScriptAvailable(nsresult 
                                nsIScriptElement *aElement,
                                PRBool aIsInline,
                                nsIURI *aURI,
                                PRInt32 aLineNo)
 {
   PRUint32 count = mScriptElements.Count();
 
   // aElement will not be in mScriptElements if a <script> was added
-  // using the DOM during loading or if DoneAddingChildren did not return
-  // NS_ERROR_HTMLPARSER_BLOCK.
+  // using the DOM during loading, or if the script was inline and thus
+  // never blocked.
   NS_ASSERTION(count == 0 ||
                mScriptElements.IndexOf(aElement) == PRInt32(count - 1) ||
                mScriptElements.IndexOf(aElement) == -1,
                "script found at unexpected position");
 
   // Check if this is the element we were waiting for
   if (count == 0 || aElement != mScriptElements[count - 1]) {
     return NS_OK;
--- a/content/base/src/nsScriptElement.cpp
+++ b/content/base/src/nsScriptElement.cpp
@@ -173,32 +173,32 @@ nsresult
 nsScriptElement::MaybeProcessScript()
 {
   nsCOMPtr<nsIContent> cont =
     do_QueryInterface((nsIScriptElement*) this);
 
   NS_ASSERTION(cont->DebugGetSlots()->mMutationObservers.Contains(this),
                "You forgot to add self as observer");
 
-  if (mAlreadyStarted || !mDoneAddingChildren || !cont->IsInDoc() ||
+  if (mIsEvaluated || !mDoneAddingChildren || !cont->IsInDoc() ||
       mMalformed || !HasScriptContent()) {
     return NS_OK;
   }
 
   FreezeUriAsyncDefer();
 
   if (InNonScriptingContainer(cont)) {
     // Make sure to flag ourselves as evaluated
-    mAlreadyStarted = PR_TRUE;
+    mIsEvaluated = PR_TRUE;
     return NS_OK;
   }
 
   nsresult scriptresult = NS_OK;
   nsRefPtr<nsScriptLoader> loader = cont->GetOwnerDoc()->ScriptLoader();
-  mAlreadyStarted = PR_TRUE;
+  mIsEvaluated = PR_TRUE;
   scriptresult = loader->ProcessScriptElement(this);
 
   // The only error we don't ignore is NS_ERROR_HTMLPARSER_BLOCK
   // However we don't want to override other success values
   // (such as NS_CONTENT_SCRIPT_IS_EVENTHANDLER)
   if (NS_FAILED(scriptresult) &&
       scriptresult != NS_ERROR_HTMLPARSER_BLOCK) {
     scriptresult = NS_OK;
--- a/content/base/src/nsScriptElement.h
+++ b/content/base/src/nsScriptElement.h
@@ -54,21 +54,16 @@ public:
   NS_DECL_NSISCRIPTLOADEROBSERVER
 
   // nsIMutationObserver
   NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
   NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
 
-  nsScriptElement(PRUint32 aFromParser)
-    : nsIScriptElement(aFromParser)
-  {
-  }
-
 protected:
   // Internal methods
 
   /**
    * Check if this element contains any script, linked or inline
    */
   virtual PRBool HasScriptContent() = 0;
 
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -70,17 +70,16 @@
 #include "nsIParser.h"
 #include "nsThreadUtils.h"
 #include "nsDocShellCID.h"
 #include "nsIContentSecurityPolicy.h"
 #include "prlog.h"
 #include "nsIChannelPolicy.h"
 #include "nsChannelPolicy.h"
 #include "nsCRT.h"
-#include "nsContentCreatorFunctions.h"
 
 #include "mozilla/FunctionTimer.h"
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gCspPRLog;
 #endif
 
 using namespace mozilla::dom;
@@ -113,16 +112,17 @@ public:
 
   PRBool IsPreload()
   {
     return mElement == nsnull;
   }
 
   nsCOMPtr<nsIScriptElement> mElement;
   PRPackedBool mLoading;             // Are we still waiting for a load to complete?
+  PRPackedBool mDefer;               // Is execution defered?
   PRPackedBool mIsInline;            // Is the script inline or loaded?
   nsString mScriptText;              // Holds script for loaded scripts
   PRUint32 mJSVersion;
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIURI> mFinalURI;
   PRInt32 mLineNo;
 };
 
@@ -135,35 +135,31 @@ NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLo
 //
 //////////////////////////////////////////////////////////////
 
 nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
   : mDocument(aDocument),
     mBlockerCount(0),
     mEnabled(PR_TRUE),
     mDeferEnabled(PR_FALSE),
-    mDocumentParsingDone(PR_FALSE)
+    mUnblockOnloadWhenDoneProcessing(PR_FALSE)
 {
   // enable logging for CSP
 #ifdef PR_LOGGING
   if (!gCspPRLog)
     gCspPRLog = PR_NewLogModule("CSP");
 #endif
 }
 
 nsScriptLoader::~nsScriptLoader()
 {
   mObservers.Clear();
 
-  if (mParserBlockingRequest) {
-    mParserBlockingRequest->FireScriptAvailable(NS_ERROR_ABORT);
-  }
-
-  for (PRInt32 i = 0; i < mDeferRequests.Count(); i++) {
-    mDeferRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
+  for (PRInt32 i = 0; i < mRequests.Count(); i++) {
+    mRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
   }
 
   for (PRInt32 i = 0; i < mAsyncRequests.Count(); i++) {
     mAsyncRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
   }
 
   // Unblock the kids, in case any of them moved to a different document
   // subtree in the meantime and therefore aren't actually going away.
@@ -338,33 +334,16 @@ PRBool
 nsScriptLoader::PreloadURIComparator::Equals(const PreloadInfo &aPi,
                                              nsIURI * const &aURI) const
 {
   PRBool same;
   return NS_SUCCEEDED(aPi.mRequest->mURI->Equals(aURI, &same)) &&
          same;
 }
 
-class nsScriptRequestProcessor : public nsRunnable
-{
-private:
-  nsRefPtr<nsScriptLoader> mLoader;
-  nsRefPtr<nsScriptLoadRequest> mRequest;
-public:
-  nsScriptRequestProcessor(nsScriptLoader* aLoader,
-                           nsScriptLoadRequest* aRequest)
-    : mLoader(aLoader)
-    , mRequest(aRequest)
-  {}
-  NS_IMETHODIMP Run()
-  {
-    return mLoader->ProcessRequest(mRequest);
-  }
-};
-
 nsresult
 nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement)
 {
   // We need a document to evaluate scripts.
   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
 
   // Check to see if scripts has been turned off.
   if (!mEnabled || !mDocument->IsScriptEnabled()) {
@@ -531,153 +510,145 @@ nsScriptLoader::ProcessScriptElement(nsI
       !nsContentUtils::IsChromeDoc(mDocument)) {
     NS_WARNING("Untrusted language called from non-chrome - ignored");
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsCOMPtr<nsIContent> eltContent(do_QueryInterface(aElement));
   eltContent->SetScriptTypeID(typeID);
 
-  // Step 9. in the HTML5 spec
+  PRBool hadPendingRequests = !!GetFirstPendingRequest();
 
+  // Did we preload this request?
   nsCOMPtr<nsIURI> scriptURI = aElement->GetScriptURI();
   nsRefPtr<nsScriptLoadRequest> request;
   if (scriptURI) {
-    // external script
     nsTArray<PreloadInfo>::index_type i =
       mPreloads.IndexOf(scriptURI.get(), 0, PreloadURIComparator());
     if (i != nsTArray<PreloadInfo>::NoIndex) {
-      // preloaded
-      // note that a script-inserted script can steal a preload!
       request = mPreloads[i].mRequest;
       request->mElement = aElement;
-      // XXX what if the charset attribute of the element and the charset
-      // of the preload don't match?
+      request->mJSVersion = version;
+      request->mDefer = mDeferEnabled && aElement->GetScriptDeferred() &&
+        !aElement->GetScriptAsync();
       mPreloads.RemoveElementAt(i);
+
       rv = CheckContentPolicy(mDocument, aElement, request->mURI, type);
-      NS_ENSURE_SUCCESS(rv, rv);
-    } else {
-      // not preloaded
-      request = new nsScriptLoadRequest(aElement, version);
-      NS_ENSURE_TRUE(request, NS_ERROR_OUT_OF_MEMORY);
-      request->mURI = scriptURI;
-      request->mIsInline = PR_FALSE;
-      request->mLoading = PR_TRUE;
-      rv = StartLoad(request, type);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    request->mJSVersion = version;
-
-    PRBool async = !aElement->GetParserCreated() || aElement->GetScriptAsync();
+      if (NS_FAILED(rv)) {
+        // Note, we're dropping our last ref to request here.
+        return rv;
+      }
 
-    // we now have a request that may or may not be still loading
-    if (!async && aElement->GetScriptDeferred()) {
-      // We don't want to run this yet.
-      // If we come here, the script is a parser-created script and it has
-      // the defer attribute but not the async attribute. Since a
-      // a parser-inserted script is being run, we came here by the parser
-      // running the script, which means the parser is still alive and the
-      // parse is ongoing.
-      NS_ASSERTION(mDocument->GetCurrentContentSink(),
-          "Defer script on a document without an active parser; bug 592366.");
-      mDeferRequests.AppendObject(request);
-      return NS_OK;
-    }
-    if (async) {
-      mAsyncRequests.AppendObject(request);
-      if (!request->mLoading) {
-        // The script is available already. Run it ASAP when the event
-        // loop gets a chance to spin.
-        ProcessPendingRequestsAsync();
-      }
-      return NS_OK;
-    }
-    if (!request->mLoading) {
-      // The request has already been loaded. If the script comes from the
-      // network stream, cheat for performance reasons and avoid a trip
-      // through the event loop.
-      if (aElement->GetParserCreated() == NS_FROM_PARSER_NETWORK) {
+      // Can we run the script now?
+      // This is true if we're done loading, the script isn't deferred and
+      // there are either no scripts or stylesheets to wait for, or the
+      // script is async
+      PRBool readyToRun =
+        !request->mLoading && !request->mDefer &&
+        ((!hadPendingRequests && ReadyToExecuteScripts()) ||
+         aElement->GetScriptAsync());
+
+      if (readyToRun && nsContentUtils::IsSafeToRunScript()) {
         return ProcessRequest(request);
       }
-      // Otherwise, we've got a document.written script, make a trip through
-      // the event loop to hide the preload effects from the scripts on the
-      // Web page.
-      NS_ASSERTION(!mParserBlockingRequest,
-          "There can be only one parser-blocking script at a time");
-      mParserBlockingRequest = request;
-      ProcessPendingRequestsAsync();
-      return NS_ERROR_HTMLPARSER_BLOCK;
-    }
-    // The script hasn't loaded yet and is parser-inserted and non-async.
-    // It'll be executed when it has loaded.
-    NS_ASSERTION(!mParserBlockingRequest,
-        "There can be only one parser-blocking script at a time");
-    mParserBlockingRequest = request;
-    return NS_ERROR_HTMLPARSER_BLOCK;
-  }
 
-  // inline script
-  nsCOMPtr<nsIContentSecurityPolicy> csp;
-  rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
-  NS_ENSURE_SUCCESS(rv, rv);
+      // Not done loading yet. Move into the real requests queue and wait.
+      if (aElement->GetScriptAsync()) {
+        mAsyncRequests.AppendObject(request);
+      }
+      else {
+        mRequests.AppendObject(request);
+      }
 
-  if (csp) {
-    PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader i ****with CSP****"));
-    PRBool inlineOK;
-    // this call will send violation reports when necessary
-    rv = csp->GetAllowsInlineScript(&inlineOK);
-    NS_ENSURE_SUCCESS(rv, rv);
+      if (readyToRun) {
+        nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this,
+          &nsScriptLoader::ProcessPendingRequests));
+      }
 
-    if (!inlineOK) {
-      PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP blocked inline scripts (2)"));
-      return NS_ERROR_FAILURE;
+      return request->mDefer || aElement->GetScriptAsync() ?
+        NS_OK : NS_ERROR_HTMLPARSER_BLOCK;
     }
   }
 
+  // Create a request object for this script
   request = new nsScriptLoadRequest(aElement, version);
   NS_ENSURE_TRUE(request, NS_ERROR_OUT_OF_MEMORY);
-  request->mJSVersion = version;
-  request->mLoading = PR_FALSE;
-  request->mIsInline = PR_TRUE;
-  request->mURI = mDocument->GetDocumentURI();
-  request->mLineNo = aElement->GetScriptLineNumber();
+
+  // First check to see if this is an external script
+  if (scriptURI) {
+    request->mDefer = mDeferEnabled && aElement->GetScriptDeferred() &&
+      !aElement->GetScriptAsync();
+    request->mURI = scriptURI;
+    request->mIsInline = PR_FALSE;
+    request->mLoading = PR_TRUE;
+
+    rv = StartLoad(request, type);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  } else {
+    // in-line script
+    nsCOMPtr<nsIContentSecurityPolicy> csp;
+    nsresult rv = mDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (csp) {
+      PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader i ****with CSP****"));
+      PRBool inlineOK;
+      // this call will send violation reports when necessary
+      rv = csp->GetAllowsInlineScript(&inlineOK);
+      NS_ENSURE_SUCCESS(rv, rv);
 
-  if (aElement->GetParserCreated() == NS_NOT_FROM_PARSER) {
-    NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
-        "A script-inserted script is inserted without an update batch?");
-    nsContentUtils::AddScriptRunner(new nsScriptRequestProcessor(this,
-                                                                 request));
+      if (!inlineOK) {
+        PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP blocked inline scripts (2)"));
+        return NS_ERROR_FAILURE;
+      }
+    }
+
+    request->mDefer = PR_FALSE;
+    request->mLoading = PR_FALSE;
+    request->mIsInline = PR_TRUE;
+    request->mURI = mDocument->GetDocumentURI();
+
+    request->mLineNo = aElement->GetScriptLineNumber();
+
+    // If we've got existing pending requests, add ourselves
+    // to this list.
+    if (!hadPendingRequests && ReadyToExecuteScripts() &&
+        nsContentUtils::IsSafeToRunScript()) {
+      return ProcessRequest(request);
+    }
+  }
+
+  // Add the request to our requests list
+  NS_ENSURE_TRUE(aElement->GetScriptAsync() ?
+                 mAsyncRequests.AppendObject(request) :
+                 mRequests.AppendObject(request),
+                 NS_ERROR_OUT_OF_MEMORY);
+
+  if (request->mDefer || aElement->GetScriptAsync()) {
     return NS_OK;
   }
-  if (aElement->GetParserCreated() == NS_FROM_PARSER_NETWORK &&
-      !ReadyToExecuteScripts()) {
-    NS_ASSERTION(!mParserBlockingRequest,
-        "There can be only one parser-blocking script at a time");
-    mParserBlockingRequest = request;
-    return NS_ERROR_HTMLPARSER_BLOCK;
+
+  // If there weren't any pending requests before, and this one is
+  // ready to execute, do that as soon as it's safe.
+  if (!request->mLoading && !hadPendingRequests && ReadyToExecuteScripts()) {
+    nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this,
+      &nsScriptLoader::ProcessPendingRequests));
   }
-  // We now have a document.written inline script or we have an inline script
-  // from the network but there is no style sheet that is blocking scripts.
-  // Don't check for style sheets blocking scripts in the document.write
-  // case to avoid style sheet network activity affecting when
-  // document.write returns. It's not really necessary to do this if
-  // there's no document.write currently on the call stack. However,
-  // this way matches IE more closely than checking if document.write
-  // is on the call stack.
-  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
-      "Not safe to run a parser-inserted script?");
-  return ProcessRequest(request);
+
+  // Added as pending request, now we can send blocking back
+  return NS_ERROR_HTMLPARSER_BLOCK;
 }
 
 nsresult
 nsScriptLoader::ProcessRequest(nsScriptLoadRequest* aRequest)
 {
-  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
-               "Processing requests when running scripts is unsafe.");
+  NS_ASSERTION(ReadyToExecuteScripts() && nsContentUtils::IsSafeToRunScript(),
+               "Caller forgot to check ReadyToExecuteScripts()");
 
   NS_ENSURE_ARG(aRequest);
   nsAFlatString* script;
   nsAutoString textData;
 
   NS_TIME_FUNCTION;
 
   nsCOMPtr<nsIDocument> doc;
@@ -828,71 +799,81 @@ nsScriptLoader::EvaluateScript(nsScriptL
   if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
     NS_ASSERTION(!::JS_IsExceptionPending(cx),
                  "JS_ReportPendingException wasn't called");
     ::JS_EndRequest(cx);
   }
   return rv;
 }
 
+nsScriptLoadRequest*
+nsScriptLoader::GetFirstPendingRequest()
+{
+  for (PRInt32 i = 0; i < mRequests.Count(); ++i) {
+    if (!mRequests[i]->mDefer) {
+      return mRequests[i];
+    }
+  }
+
+  return nsnull;
+}
+
 void
 nsScriptLoader::ProcessPendingRequestsAsync()
 {
-  if (mParserBlockingRequest || !mPendingChildLoaders.IsEmpty()) {
+  if (GetFirstPendingRequest() || !mPendingChildLoaders.IsEmpty()) {
     nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
       &nsScriptLoader::ProcessPendingRequests);
 
     NS_DispatchToCurrentThread(ev);
   }
 }
 
 void
 nsScriptLoader::ProcessPendingRequests()
 {
-  nsCOMPtr<nsScriptLoadRequest> request;
-  if (mParserBlockingRequest &&
-      !mParserBlockingRequest->mLoading &&
-      ReadyToExecuteScripts()) {
-    request.swap(mParserBlockingRequest);
-    // nsContentSink::ScriptAvailable unblocks the parser
-    ProcessRequest(request);
-  }
+  while (1) {
+    nsRefPtr<nsScriptLoadRequest> request;
+    if (ReadyToExecuteScripts()) {
+      request = GetFirstPendingRequest();
+      if (request && !request->mLoading) {
+        mRequests.RemoveObject(request);
+      }
+      else {
+        request = nsnull;
+      }
+    }
 
-  PRInt32 i = 0;
-  while (mEnabled && i < mAsyncRequests.Count()) {
-    if (!mAsyncRequests[i]->mLoading) {
-      request = mAsyncRequests[i];
-      mAsyncRequests.RemoveObjectAt(i);
-      ProcessRequest(request);
-      continue;
+    for (PRInt32 i = 0;
+         !request && mEnabled && i < mAsyncRequests.Count();
+         ++i) {
+      if (!mAsyncRequests[i]->mLoading) {
+        request = mAsyncRequests[i];
+        mAsyncRequests.RemoveObjectAt(i);
+      }
     }
-    ++i;
-  }
 
-  if (mDocumentParsingDone) {
-    while (mDeferRequests.Count() && !mDeferRequests[0]->mLoading) {
-      request = mDeferRequests[0];
-      mDeferRequests.RemoveObjectAt(0);
-      ProcessRequest(request);
-    }
+    if (!request)
+      break;
+
+    ProcessRequest(request);
   }
 
   while (!mPendingChildLoaders.IsEmpty() && ReadyToExecuteScripts()) {
     nsRefPtr<nsScriptLoader> child = mPendingChildLoaders[0];
     mPendingChildLoaders.RemoveElementAt(0);
     child->RemoveExecuteBlocker();
   }
 
-  if (mDocumentParsingDone && mDocument &&
-      !mParserBlockingRequest && !mAsyncRequests.Count() &&
-      !mDeferRequests.Count()) {
+  if (mUnblockOnloadWhenDoneProcessing && mDocument &&
+      !GetFirstPendingRequest() && !mAsyncRequests.Count()) {
     // No more pending scripts; time to unblock onload.
     // OK to unblock onload synchronously here, since callers must be
     // prepared for the world changing anyway.
-    mDocumentParsingDone = PR_FALSE;
+    mUnblockOnloadWhenDoneProcessing = PR_FALSE;
     mDocument->UnblockOnload(PR_TRUE);
   }
 }
 
 PRBool
 nsScriptLoader::ReadyToExecuteScripts()
 {
   // Make sure the SelfReadyToExecuteScripts check is first, so that
@@ -1047,23 +1028,19 @@ nsScriptLoader::OnStreamComplete(nsIStre
 {
   nsScriptLoadRequest* request = static_cast<nsScriptLoadRequest*>(aContext);
   NS_ASSERTION(request, "null request in stream complete handler");
   NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
 
   nsresult rv = PrepareLoadedRequest(request, aLoader, aStatus, aStringLen,
                                      aString);
   if (NS_FAILED(rv)) {
-    if (mDeferRequests.RemoveObject(request) ||
+    if (mRequests.RemoveObject(request) ||
         mAsyncRequests.RemoveObject(request)) {
       FireScriptAvailable(rv, request);
-    } else if (mParserBlockingRequest == request) {
-      mParserBlockingRequest = nsnull;
-      // nsContentSink::ScriptAvailable unblocks the parser
-      FireScriptAvailable(rv, request);
     } else {
       mPreloads.RemoveElement(request, PreloadRequestComparator());
     }
   }
 
   // Process our request and/or any pending ones
   ProcessPendingRequests();
 
@@ -1124,20 +1101,19 @@ nsScriptLoader::PrepareLoadedRequest(nsS
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
   // This assertion could fire errorously if we ran out of memory when
   // inserting the request in the array. However it's an unlikely case
   // so if you see this assertion it is likely something else that is
   // wrong, especially if you see it more than once.
-  NS_ASSERTION(mDeferRequests.IndexOf(aRequest) >= 0 ||
+  NS_ASSERTION(mRequests.IndexOf(aRequest) >= 0 ||
                mAsyncRequests.IndexOf(aRequest) >= 0 ||
-               mPreloads.Contains(aRequest, PreloadRequestComparator()) ||
-               mParserBlockingRequest,
+               mPreloads.Contains(aRequest, PreloadRequestComparator()),
                "aRequest should be pending!");
 
   // Mark this as loaded
   aRequest->mLoading = PR_FALSE;
 
   return NS_OK;
 }
 
@@ -1172,23 +1148,25 @@ nsScriptLoader::ShouldExecuteScript(nsID
 }
 
 void
 nsScriptLoader::ParsingComplete(PRBool aTerminated)
 {
   if (mDeferEnabled) {
     // Have to check because we apparently get ParsingComplete
     // without BeginDeferringScripts in some cases
-    mDocumentParsingDone = PR_TRUE;
+    mUnblockOnloadWhenDoneProcessing = PR_TRUE;
   }
   mDeferEnabled = PR_FALSE;
   if (aTerminated) {
-    mDeferRequests.Clear();
-    mAsyncRequests.Clear();
-    mParserBlockingRequest = nsnull;
+    mRequests.Clear();
+  } else {
+    for (PRUint32 i = 0; i < (PRUint32)mRequests.Count(); ++i) {
+      mRequests[i]->mDefer = PR_FALSE;
+    }
   }
 
   // Have to call this even if aTerminated so we'll correctly unblock
   // onload and all.
   ProcessPendingRequests();
 }
 
 void
@@ -1198,16 +1176,18 @@ nsScriptLoader::PreloadURI(nsIURI *aURI,
   nsRefPtr<nsScriptLoadRequest> request = new nsScriptLoadRequest(nsnull, 0);
   if (!request) {
     return;
   }
 
   request->mURI = aURI;
   request->mIsInline = PR_FALSE;
   request->mLoading = PR_TRUE;
+  request->mDefer = PR_FALSE; // This is computed later when we go to execute the
+                              // script.
   nsresult rv = StartLoad(request, aType);
   if (NS_FAILED(rv)) {
     return;
   }
 
   PreloadInfo *pi = mPreloads.AppendElement();
   pi->mRequest = request;
   pi->mCharset = aCharset;
--- a/content/base/src/nsScriptLoader.h
+++ b/content/base/src/nsScriptLoader.h
@@ -55,17 +55,16 @@
 class nsScriptLoadRequest;
 
 //////////////////////////////////////////////////////////////
 // Script loader implementation
 //////////////////////////////////////////////////////////////
 
 class nsScriptLoader : public nsIStreamLoaderObserver
 {
-  friend class nsScriptRequestProcessor;
 public:
   nsScriptLoader(nsIDocument* aDocument);
   virtual ~nsScriptLoader();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTREAMLOADEROBSERVER
 
   /**
@@ -220,30 +219,30 @@ public:
    */
   void ParsingComplete(PRBool aTerminated);
 
   /**
    * Returns the number of pending scripts, deferred or not.
    */
   PRUint32 HasPendingOrCurrentScripts()
   {
-    return mCurrentScript || mParserBlockingRequest;
+    return mCurrentScript || GetFirstPendingRequest();
   }
 
   /**
    * Adds aURI to the preload list and starts loading it.
    *
    * @param aURI The URI of the external script.
    * @param aCharset The charset parameter for the script.
    * @param aType The type parameter for the script.
    */
   virtual void PreloadURI(nsIURI *aURI, const nsAString &aCharset,
                           const nsAString &aType);
 
-private:
+protected:
   /**
    * Helper function to check the content policy for a given request.
    */
   static nsresult CheckContentPolicy(nsIDocument* aDocument,
                                      nsISupports *aContext,
                                      nsIURI *aURI,
                                      const nsAString &aType);
 
@@ -290,21 +289,23 @@ private:
                           const nsAFlatString& aScript);
 
   nsresult PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
                                 nsIStreamLoader* aLoader,
                                 nsresult aStatus,
                                 PRUint32 aStringLen,
                                 const PRUint8* aString);
 
+  // Returns the first pending (non deferred) request
+  nsScriptLoadRequest* GetFirstPendingRequest();
+
   nsIDocument* mDocument;                   // [WEAK]
   nsCOMArray<nsIScriptLoaderObserver> mObservers;
+  nsCOMArray<nsScriptLoadRequest> mRequests;
   nsCOMArray<nsScriptLoadRequest> mAsyncRequests;
-  nsCOMArray<nsScriptLoadRequest> mDeferRequests;
-  nsCOMPtr<nsScriptLoadRequest> mParserBlockingRequest;
 
   // In mRequests, the additional information here is stored by the element.
   struct PreloadInfo {
     nsRefPtr<nsScriptLoadRequest> mRequest;
     nsString mCharset;
   };
 
   struct PreloadRequestComparator {
@@ -320,12 +321,12 @@ private:
   nsTArray<PreloadInfo> mPreloads;
 
   nsCOMPtr<nsIScriptElement> mCurrentScript;
   // XXXbz do we want to cycle-collect these or something?  Not sure.
   nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
   PRUint32 mBlockerCount;
   PRPackedBool mEnabled;
   PRPackedBool mDeferEnabled;
-  PRPackedBool mDocumentParsingDone;
+  PRPackedBool mUnblockOnloadWhenDoneProcessing;
 };
 
 #endif //__nsScriptLoader_h__
--- a/content/base/test/test_bug28293.html
+++ b/content/base/test/test_bug28293.html
@@ -4,42 +4,46 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=28293
 -->
 <head>
   <title>Test for Bug 28293</title>
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script>
-scriptInsertedExternalExecuted = false;
 res = 'A';
 
 SimpleTest.waitForExplicitFinish();
 onload = function () {
 
   res+='2';
 
   s = document.createElement('script');
   s.textContent="res+='g';";
   s.defer = true;
   document.body.appendChild(s);
 
   res+='3';
 
   s = document.createElement('script');
+  s.src="file_bug28293.sjs?res+='h';";
+  s.defer = true;
+  document.body.appendChild(s);
+
+  s = document.createElement('script');
   s.textContent="res+='i';done()";
   s.defer = true;
   document.body.appendChild(s);
 
   res+='4';
 }
 
 function done() {
-  is(res, "AacBCDEFGeHIJb1M2g3i", "scripts executed in the wrong order");
-  ok(scriptInsertedExternalExecuted, "Dynamic script did not block load");
+  is(res, "AacBCDEFGeHIJfbd1M2g34hi", "scripts executed in the wrong order");
+  ok(!fHadExecuted, "Dynamic script executed too late");
   SimpleTest.finish();
 }
 </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=28293">Mozilla Bug 28293</a>
 
 <script defer>
@@ -51,16 +55,21 @@ res += 'c';
 </script>
 <script>
 res += 'B';
 </script>
 <script>
 res += 'C';
 
 s = document.createElement('script');
+s.src="file_bug28293.sjs?res+='d';";
+s.defer = true;
+document.body.appendChild(s);
+
+s = document.createElement('script');
 s.textContent="res+='D';";
 document.body.appendChild(s);
 
 res += 'E';
 </script>
 <script>
 res += 'F';
 document.addEventListener("DOMContentLoaded", function() {
@@ -73,15 +82,18 @@ res += 'G';
 </script>
 <script defer>
 res += 'e';
 </script>
 <script src="file_bug28293.sjs?res+='H';"></script>
 <script>
 res += 'I';
 s = document.createElement('script');
-s.src="file_bug28293.sjs?scriptInsertedExternalExecuted=true;";
+s.src="file_bug28293.sjs?fHadExecuted=(res.indexOf('f')>=0);";
 document.body.appendChild(s);
 res += 'J';
 </script>
+<script defer>
+res += 'f';
+</script>
 
 </body>
 </html>
--- a/content/base/test/test_bug28293.xhtml
+++ b/content/base/test/test_bug28293.xhtml
@@ -3,42 +3,46 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=28293
 -->
 <head>
   <title>Test for Bug 28293</title>
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script>
-scriptInsertedExternalExecuted = false;
 res = 'A';
 
 SimpleTest.waitForExplicitFinish();
 onload = function () {
 
   res+='2';
 
   s = document.createElement('script');
   s.textContent="res+='g';";
   s.defer = true;
   document.body.appendChild(s);
 
   res+='3';
 
   s = document.createElement('script');
+  s.src="file_bug28293.sjs?res+='h';";
+  s.defer = true;
+  document.body.appendChild(s);
+
+  s = document.createElement('script');
   s.textContent="res+='i';done()";
   s.defer = true;
   document.body.appendChild(s);
 
   res+='4';
 }
 
 function done() {
-  is(res, "AacBCDEFGeHIJb1M2g3i", "scripts executed in the wrong order");
-  ok(scriptInsertedExternalExecuted, "Dynamic script did not block load");
+  is(res, "AacBCDEFGeHIJfbd1M2g34hi", "scripts executed in the wrong order");
+  ok(!fHadExecuted, "Dynamic script executed too late");
   SimpleTest.finish();
 }
 </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=28293">Mozilla Bug 28293</a>
 
 <script defer="defer">
@@ -50,16 +54,21 @@ res += 'c';
 </script>
 <script>
 res += 'B';
 </script>
 <script>
 res += 'C';
 
 s = document.createElement('script');
+s.src="file_bug28293.sjs?res+='d';";
+s.defer = true;
+document.body.appendChild(s);
+
+s = document.createElement('script');
 s.textContent="res+='D';";
 document.body.appendChild(s);
 
 res += 'E';
 </script>
 <script>
 res += 'F';
 document.addEventListener("DOMContentLoaded", function() {
@@ -73,16 +82,19 @@ res += 'G';
 <script defer="defer">
 res += 'e';
 </script>
 <script src="file_bug28293.sjs?res+='H';"></script>
 <script>
 <![CDATA[
 res += 'I';
 s = document.createElement('script');
-s.src="file_bug28293.sjs?scriptInsertedExternalExecuted=true;";
+s.src="file_bug28293.sjs?fHadExecuted=(res.indexOf('f')>=0);";
 document.body.appendChild(s);
 res += 'J';
 ]]>
 </script>
+<script defer="defer">
+res += 'f';
+</script>
 
 </body>
 </html>
--- a/content/html/content/src/nsHTMLScriptElement.cpp
+++ b/content/html/content/src/nsHTMLScriptElement.cpp
@@ -358,17 +358,16 @@ protected:
 
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Script)
 
 
 nsHTMLScriptElement::nsHTMLScriptElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                                          PRUint32 aFromParser)
   : nsGenericHTMLElement(aNodeInfo)
-  , nsScriptElement(aFromParser)
 {
   mDoneAddingChildren = !aFromParser;
   AddMutationObserver(this);
 }
 
 nsHTMLScriptElement::~nsHTMLScriptElement()
 {
 }
@@ -424,17 +423,17 @@ nsHTMLScriptElement::Clone(nsINodeInfo *
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   nsCOMPtr<nsINode> kungFuDeathGrip = it;
   nsresult rv = CopyInnerTo(it);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The clone should be marked evaluated if we are.
-  it->mAlreadyStarted = mAlreadyStarted;
+  it->mIsEvaluated = mIsEvaluated;
   it->mLineNumber = mLineNumber;
   it->mMalformed = mMalformed;
 
   kungFuDeathGrip.swap(*aResult);
 
   return NS_OK;
 }
 
@@ -473,20 +472,21 @@ nsHTMLScriptElement::SetInnerHTML(const 
   return nsContentUtils::SetNodeTextContent(this, aInnerHTML, PR_TRUE);
 }
 
 nsresult
 nsHTMLScriptElement::DoneAddingChildren(PRBool aHaveNotified)
 {
   mDoneAddingChildren = PR_TRUE;
   nsresult rv = MaybeProcessScript();
-  if (!mAlreadyStarted) {
-    // Need to lose parser-insertedness here to allow another script to cause
+  if (!mIsEvaluated) {
+    // Need to thaw the script uri here to allow another script to cause
     // execution later.
-    LoseParserInsertedness();
+    mFrozen = PR_FALSE;
+    mUri = nsnull;
   }
   return rv;
 }
 
 PRBool
 nsHTMLScriptElement::IsDoneAddingChildren()
 {
   return mDoneAddingChildren;
@@ -550,17 +550,17 @@ nsHTMLScriptElement::MaybeProcessScript(
 {
   nsresult rv = nsScriptElement::MaybeProcessScript();
   if (rv == NS_CONTENT_SCRIPT_IS_EVENTHANDLER) {
     // Don't return NS_CONTENT_SCRIPT_IS_EVENTHANDLER since callers can't deal
     rv = NS_OK;
 
     // We tried to evaluate the script but realized it was an eventhandler
     // mEvaluated will already be set at this point
-    NS_ASSERTION(mAlreadyStarted, "should have set mIsEvaluated already");
+    NS_ASSERTION(mIsEvaluated, "should have set mIsEvaluated already");
     NS_ASSERTION(!mScriptEventHandler, "how could we have an SEH already?");
 
     mScriptEventHandler = new nsHTMLScriptEventHandler(this);
     NS_ENSURE_TRUE(mScriptEventHandler, NS_ERROR_OUT_OF_MEMORY);
 
     nsAutoString event_val;
     GetAttr(kNameSpaceID_None, nsGkAtoms::event, event_val);
     mScriptEventHandler->ParseEventString(event_val);
--- a/content/html/content/test/test_bug300691-2.html
+++ b/content/html/content/test/test_bug300691-2.html
@@ -4,25 +4,24 @@
 https://bugzilla.mozilla.org/show_bug.cgi?id=300691
 -->
 <head>
   <title>Test for Bug 300691</title>
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
-<body onload="done();">
+<body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=300691">Mozilla Bug 300691</a>
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script type="text/javascript">
-  SimpleTest.waitForExplicitFinish();
   // First, setup.  We'll be toggling these variables as we go.
   var test1Ran = false;
   var test2Ran = false;
   var test3Ran = false;
   var test4Ran = false;
   var test5Ran = false;
   var test6Ran = false;
   var test7Ran = false;
@@ -108,17 +107,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   $("test8").insertBefore(document.createTextNode("test8Ran = true"),
                           $("test8").firstChild);
   is(test8Ran, true, "Should be 8!");
 
   $("test9").firstChild.data = "test9Ran = true";
   is(test9Ran, true, "Should be 9!");
 </script>
 <script type="text/javascript">
-function done() {
   is(test1Ran, true, "Should have run!");
   is(test3Ran, false, "Already executed test3 script once");
   is(test4Ran, false,
      "Should have executed whitespace-only script already");
   is(test5Ran, false,
      "Should have executed once the whitespace node was added");
   is(test6Ran, false,
      "Should have executed once the whitespace node was added 2");
@@ -127,15 +125,13 @@ function done() {
   is(test12Ran, true, "Setting src should execute script");
   is(test13Ran, true, "Setting src attribute should execute script");
   is(test14aRan, true, "src attribute takes precedence over inline content");
   is(test14bRan, false, "src attribute takes precedence over inline content 2");
   is(test15aRan, true,
      "src attribute load should have started before the attribute got removed");
   is(test15bRan, false,
      "src attribute still got executed, so this shouldn't have been");
-  SimpleTest.finish();
-}
 </script>
 </pre>
 </body>
 </html>
 
--- a/content/svg/content/src/nsSVGScriptElement.cpp
+++ b/content/svg/content/src/nsSVGScriptElement.cpp
@@ -130,17 +130,16 @@ NS_INTERFACE_TABLE_HEAD(nsSVGScriptEleme
 NS_INTERFACE_MAP_END_INHERITING(nsSVGScriptElementBase)
 
 //----------------------------------------------------------------------
 // Implementation
 
 nsSVGScriptElement::nsSVGScriptElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                                        PRUint32 aFromParser)
   : nsSVGScriptElementBase(aNodeInfo)
-  , nsScriptElement(aFromParser)
 {
   mDoneAddingChildren = !aFromParser;
   AddMutationObserver(this);
 }
 
 //----------------------------------------------------------------------
 // nsIDOMNode methods
 
@@ -156,17 +155,17 @@ nsSVGScriptElement::Clone(nsINodeInfo *a
   }
 
   nsCOMPtr<nsINode> kungFuDeathGrip = it;
   nsresult rv = it->Init();
   rv |= CopyInnerTo(it);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The clone should be marked evaluated if we are.
-  it->mAlreadyStarted = mAlreadyStarted;
+  it->mIsEvaluated = mIsEvaluated;
   it->mLineNumber = mLineNumber;
   it->mMalformed = mMalformed;
 
   kungFuDeathGrip.swap(*aResult);
 
   return NS_OK;
 }
 
@@ -274,20 +273,21 @@ nsSVGScriptElement::GetStringInfo()
 //----------------------------------------------------------------------
 // nsIContent methods
 
 nsresult
 nsSVGScriptElement::DoneAddingChildren(PRBool aHaveNotified)
 {
   mDoneAddingChildren = PR_TRUE;
   nsresult rv = MaybeProcessScript();
-  if (!mAlreadyStarted) {
-    // Need to lose parser-insertedness here to allow another script to cause
+  if (!mIsEvaluated) {
+    // Need to thaw the script uri here to allow another script to cause
     // execution later.
-    LoseParserInsertedness();
+    mFrozen = PR_FALSE;
+    mUri = nsnull;
   }
   return rv;
 }
 
 PRBool
 nsSVGScriptElement::IsDoneAddingChildren()
 {
   return mDoneAddingChildren;
deleted file mode 100644
--- a/content/test/reftest/bug591981-1.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Script-inserted script</title>
-</head>
-<body>
-<div></div>
-<script>
-function log(text) {
-  var p = document.createElement("p");
-  p.appendChild(document.createTextNode(text));
-  document.getElementsByTagName("div")[0].appendChild(p);
-}
-
-var head = document.getElementsByTagName("head")[0];
-
-var external = document.createElement("script");
-external.src = "bug591981-script.js";
-head.insertBefore(external, head.firstChild); // what jQuery does
-
-var internal = document.createElement("script");
-var data = "log('internal')";
-try {
-  internal.text = data;
-} catch(e) {
-  internal.appendChild(document.createTextNode(data));
-}
-head.insertBefore(internal, head.firstChild); // what jQuery does
-
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/content/test/reftest/bug591981-2.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Script trying to execute parser-inserted non-executed scripts</title>
-</head>
-<body>
-<div></div>
-<script></script>
-<script></script>
-<script>
-function log(text) {
-  var p = document.createElement("p");
-  p.appendChild(document.createTextNode(text));
-  document.getElementsByTagName("div")[0].appendChild(p);
-}
-
-var head = document.getElementsByTagName("head")[0];
-
-var external = document.getElementsByTagName("script")[0];
-external.src = "bug591981-script.js";
-
-var internal = document.getElementsByTagName("script")[1];
-var data = "log('internal')";
-try {
-  internal.text = data;
-} catch(e) {
-  internal.appendChild(document.createTextNode(data));
-}
-
-</script>
-</body>
-</html>
deleted file mode 100644
--- a/content/test/reftest/bug591981-ref.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title>Script-inserted script</title>
-</head>
-<body>
-<div><p>internal</p><p>external</p></div>
-</body>
-</html>
deleted file mode 100644
--- a/content/test/reftest/bug591981-script.js
+++ /dev/null
@@ -1,1 +0,0 @@
-log("external");
--- a/content/test/reftest/reftest.list
+++ b/content/test/reftest/reftest.list
@@ -1,8 +1,6 @@
 == bug453105.html bug453105-ref.html
 == optiontext.html optiontext-ref.html
 == bug456008.xhtml bug456008-ref.html
 == bug439965.html bug439965-ref.html
 == bug427779.xml bug427779-ref.xml
 == bug559996.html bug559996-ref.html
-== bug591981-1.html bug591981-ref.html
-== bug591981-2.html bug591981-ref.html
--- a/dom/tests/mochitest/bugs/child_bug260264.html
+++ b/dom/tests/mochitest/bugs/child_bug260264.html
@@ -1,11 +1,10 @@
 <html>
   <head>
-    <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <script type="application/javascript" src="utils_bug260264.js"></script>
   </head>
   <body>
     <iframe id="frame"></iframe>
     <script type="application/javascript">
       document.getElementById("frame").src =
         alter_file(alter_host(location.href, "mochi.test:8888"),
                    "grandchild_bug260264.html");
--- a/dom/tests/mochitest/bugs/grandchild_bug260264.html
+++ b/dom/tests/mochitest/bugs/grandchild_bug260264.html
@@ -1,11 +1,10 @@
 <html>
   <head>
-    <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <script type="application/javascript" src="utils_bug260264.js"></script>
   </head>
   <body>
     <a id="nested link" href="javascript:(function(){})()">nested link</a>
     <script type="application/javascript">
       var event = location.hash.split("#").pop();
       send(document.getElementById("nested link"), event, function() {
         var popup = window.open("http://example.com"),
--- a/dom/tests/mochitest/bugs/test_bug260264.html
+++ b/dom/tests/mochitest/bugs/test_bug260264.html
@@ -2,17 +2,16 @@
 <html>
 <!--
 https://bugzilla.mozilla.org/show_bug.cgi?id=260264
 -->
 <head>
   <title>Test for Bug 260264</title>
   <script type="application/javascript" src="/MochiKit/packed.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
   <script type="application/javascript" src="utils_bug260264.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=260264">Mozilla Bug 260264</a>
 <p id="display">
   <a id="link" href="javascript:(function(){})()">link</a>
 </p>
--- a/dom/tests/mochitest/bugs/utils_bug260264.js
+++ b/dom/tests/mochitest/bugs/utils_bug260264.js
@@ -1,8 +1,15 @@
+(function() {
+  // For sendMouseEvent:
+  document.getElementsByTagName("head").item(0)
+    .appendChild(document.createElement("script")).src =
+      "/tests/SimpleTest/EventUtils.js";
+})();
+
 /**
  * Dispatches |handler| to |element|, as if fired in response to |event|.
  */
 function send(element, event, handler) {
   function unique_handler() { return handler.apply(this, arguments) }
   element.addEventListener(event, unique_handler, false);
   try { sendMouseEvent({ type: event }, element.id) }
   finally { element.removeEventListener(event, unique_handler, false) }