Bug 450449 - Backing out, bad merge.
authorBen Turner <bent.mozilla@gmail.com>
Mon, 08 Sep 2008 00:36:19 -0700
changeset 18952 b7bcdd0095407e1aaa42af7ee2d747762fc82d96
parent 18951 a96364d5b84e9d745db2054e70144f73ab1d2c11
child 18953 679778dd198fd2799c37c685bc2609dde8f4418a
push id1856
push userbturner@mozilla.com
push dateMon, 08 Sep 2008 07:36:26 +0000
treeherdermozilla-central@b7bcdd009540 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs450449
milestone1.9.1b1pre
Bug 450449 - Backing out, bad merge.
dom/public/idl/threads/nsIDOMThreads.idl
dom/src/threads/Makefile.in
dom/src/threads/nsAutoJSObjectHolder.h
dom/src/threads/nsDOMThreadService.cpp
dom/src/threads/nsDOMWorkerPool.cpp
dom/src/threads/nsDOMWorkerPool.h
dom/src/threads/nsDOMWorkerScriptLoader.cpp
dom/src/threads/nsDOMWorkerScriptLoader.h
dom/src/threads/nsDOMWorkerSecurityManager.cpp
dom/src/threads/nsDOMWorkerSecurityManager.h
dom/src/threads/nsDOMWorkerThread.cpp
dom/src/threads/nsDOMWorkerThread.h
dom/src/threads/test/Makefile.in
dom/src/threads/test/importScripts_worker.js
dom/src/threads/test/importScripts_worker_imported1.js
dom/src/threads/test/importScripts_worker_imported2.js
dom/src/threads/test/importScripts_worker_imported3.js
dom/src/threads/test/importScripts_worker_imported4.js
dom/src/threads/test/test_importScripts.html
--- a/dom/public/idl/threads/nsIDOMThreads.idl
+++ b/dom/public/idl/threads/nsIDOMThreads.idl
@@ -117,25 +117,16 @@ interface nsIDOMWorkerPool : nsISupports
   /**
    * Create a new worker object by evaluating the given script.
    *
    * @param aSourceScript (in DOMString)
    *        The script to compile. See below for details on the scope in which
    *        the script will run.
    */
   nsIDOMWorkerThread createWorker(in DOMString aSourceScript);
-
-  /**
-   * Create a new worker object by evaluating the given script.
-   *
-   * @param aSourceURL (in AString)
-   *        The script url to load and compile. See below for details on the
-   *        scope in which the script will run.
-   */
-  nsIDOMWorkerThread createWorkerFromURL(in AString aSourceURL);
 };
 
 [scriptable, uuid(0f2a52ea-afc9-49e6-86dd-2d0cb65b5dd5)]
 interface nsIDOMThreadService : nsISupports
 {
   /**
    * Creates a new DOM worker pool.
    */
--- a/dom/src/threads/Makefile.in
+++ b/dom/src/threads/Makefile.in
@@ -48,29 +48,27 @@ LIBRARY_NAME     = domthreads_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
 
 REQUIRES = \
   caps \
   content \
   js \
   layout \
-  necko \
   pref \
   string \
   widget \
   xpcom \
   xpconnect \
   $(NULL)
 
 CPPSRCS = \
   nsDOMThreadService.cpp \
   nsDOMWorkerBase.cpp \
   nsDOMWorkerPool.cpp \
-  nsDOMWorkerScriptLoader.cpp \
   nsDOMWorkerSecurityManager.cpp \
   nsDOMWorkerThread.cpp \
   nsDOMWorkerTimeout.cpp \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/dom/src/base \
   $(NULL)
deleted file mode 100644
--- a/dom/src/threads/nsAutoJSObjectHolder.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is worker threads.
- *
- * The Initial Developer of the Original Code is
- *   Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Ben Turner <bent.mozilla@gmail.com> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * 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 ***** */
-
-#ifndef __NSAUTOJSOBJECTHOLDER_H__
-#define __NSAUTOJSOBJECTHOLDER_H__
-
-#include "jsapi.h"
-
-/**
- * Simple class that looks and acts like a JSObject* except that it unroots
- * itself automatically if Root() is ever called. Designed to be rooted on the
- * context or runtime (but not both!). Also automatically nulls its JSObject*
- * on Unroot and asserts that Root has been called prior to assigning an object.
- */
-class nsAutoJSObjectHolder
-{
-public:
-  /**
-   * Default constructor, no holding.
-   */
-  nsAutoJSObjectHolder()
-  : mRt(NULL), mObj(NULL), mHeld(PR_FALSE) { }
-
-  /**
-   * Hold by rooting on the context's runtime in the constructor, passing the
-   * result out.
-   */
-  nsAutoJSObjectHolder(JSContext* aCx, JSBool* aRv = NULL,
-                       JSObject* aObj = NULL)
-  : mRt(NULL), mObj(aObj), mHeld(JS_FALSE) {
-    JSBool rv = Hold(aCx);
-    if (aRv) {
-      *aRv = rv;
-    }
-  }
-
-  /**
-   * Hold by rooting on the runtime in the constructor, passing the result out.
-   */
-  nsAutoJSObjectHolder(JSRuntime* aRt, JSBool* aRv = NULL,
-                       JSObject* aObj = NULL)
-  : mRt(aRt), mObj(aObj), mHeld(JS_FALSE) {
-    JSBool rv = Hold(aRt);
-    if (aRv) {
-      *aRv = rv;
-    }
-  }
-
-  /**
-   * Always release on destruction.
-   */
-  ~nsAutoJSObjectHolder() {
-    Release();
-  }
-
-  /**
-   * Hold by rooting on the context's runtime.
-   */
-  JSBool Hold(JSContext* aCx) {
-    return Hold(JS_GetRuntime(aCx));
-  }
-
-  /**
-   * Hold by rooting on the runtime.
-   */
-  JSBool Hold(JSRuntime* aRt) {
-    if (!mHeld) {
-      mHeld = JS_AddNamedRootRT(aRt, &mObj, "nsAutoRootedJSObject");
-      if (mHeld) {
-        mRt = aRt;
-      }
-    }
-    return mHeld;
-  }
-
-  /**
-   * Manually release.
-   */
-  void Release() {
-    NS_ASSERTION(!mHeld || mRt, "Bad!");
-    if (mHeld) {
-      mHeld = !JS_RemoveRootRT(mRt, &mObj);
-      if (!mHeld) {
-        mRt = NULL;
-      }
-      mObj = NULL;
-    }
-  }
-
-  /**
-   * Determine if Hold has been called.
-   */
-  JSBool IsHeld() {
-    return mHeld;
-  }
-
-  /**
-   * Pretend to be a JSObject*.
-   */
-  JSObject* get() const {
-    return mObj;
-  }
-
-  /**
-   * Pretend to be a JSObject*.
-   */
-  operator JSObject*() const {
-    return get();
-  }
-
-  /**
-   * Pretend to be a JSObject*. Assert if not held.
-   */
-  JSObject* operator=(JSObject* aOther) {
-    NS_ASSERTION(mHeld, "Not rooted!");
-    return mObj = aOther;
-  }
-
-private:
-  JSRuntime* mRt;
-  JSObject* mObj;
-  JSBool mHeld;
-};
-
-#endif /* __NSAUTOJSOBJECTHOLDER_H__ */
--- a/dom/src/threads/nsDOMThreadService.cpp
+++ b/dom/src/threads/nsDOMThreadService.cpp
@@ -37,18 +37,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsDOMThreadService.h"
 
 // Interfaces
 #include "nsIComponentManager.h"
 #include "nsIConsoleService.h"
-#include "nsIDocument.h"
-#include "nsIDOMDocument.h"
 #include "nsIEventTarget.h"
 #include "nsIGenericFactory.h"
 #include "nsIJSContextStack.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIObserverService.h"
 #include "nsIScriptError.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIServiceManager.h"
@@ -85,24 +83,16 @@ PRLogModuleInfo *gDOMThreadsLog = nsnull
 
 PR_STATIC_ASSERT(THREADPOOL_MAX_THREADS >= 1);
 
 // The maximum number of idle threads in the internal thread pool
 #define THREADPOOL_IDLE_THREADS 3
 
 PR_STATIC_ASSERT(THREADPOOL_MAX_THREADS >= THREADPOOL_IDLE_THREADS);
 
-// As we suspend threads for various reasons (navigating away from the page,
-// loading scripts, etc.) we open another slot in the thread pool for another
-// worker to use. We can't do this forever so we set an absolute cap on the
-// number of threads we'll allow to prevent DOS attacks.
-#define THREADPOOL_THREAD_CAP 20
-
-PR_STATIC_ASSERT(THREADPOOL_THREAD_CAP >= THREADPOOL_MAX_THREADS);
-
 // The number of times our JS operation callback will be called before yielding
 // the thread
 #define CALLBACK_YIELD_THRESHOLD 100
 
 // A "bad" value for the NSPR TLS functions.
 #define BAD_TLS_INDEX (PRUintn)-1
 
 // Don't know why nsISupports.idl defines this out...
@@ -391,42 +381,37 @@ DOMWorkerOperationCallback(JSContext* aC
 {
   nsDOMWorkerThread* worker = (nsDOMWorkerThread*)JS_GetContextPrivate(aCx);
 
   // Want a strong ref here to make sure that the monitor we wait on won't go
   // away.
   nsRefPtr<nsDOMWorkerPool> pool;
 
   PRBool wasSuspended = PR_FALSE;
-  PRBool extraThreadAllowed = PR_FALSE;
   jsrefcount suspendDepth = 0;
 
   while (1) {
     // Kill execution if we're canceled.
     if (worker->IsCanceled()) {
       LOG(("Forcefully killing JS for worker [0x%p]",
            static_cast<void*>(worker)));
 
       if (wasSuspended) {
-        if (extraThreadAllowed) {
-          gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
-        }
+        gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
         JS_ResumeRequest(aCx, suspendDepth);
       }
 
       // Kill exectuion of the currently running JS.
       return PR_FALSE;
     }
 
     // Break out if we're not suspended.
     if (!worker->IsSuspended()) {
       if (wasSuspended) {
-        if (extraThreadAllowed) {
-          gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
-        }
+        gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
         JS_ResumeRequest(aCx, suspendDepth);
       }
       break;
     }
 
     if (!wasSuspended) {
       // Make sure we can get the monitor we need to wait on. It's possible that
       // the worker was canceled since we checked above.
@@ -437,20 +422,18 @@ DOMWorkerOperationCallback(JSContext* aC
 
       pool = worker->Pool();
 
       // Make sure to suspend our request while we block like this, otherwise we
       // prevent GC for everyone.
       suspendDepth = JS_SuspendRequest(aCx);
 
       // Since we're going to block this thread we should open up a new thread
-      // in the thread pool for other workers. Must check the return value to
-      // make sure we don't decrement when we failed.
-      extraThreadAllowed =
-        NS_SUCCEEDED(gDOMThreadService->ChangeThreadPoolMaxThreads(1));
+      // in the thread pool for other workers.
+      gDOMThreadService->ChangeThreadPoolMaxThreads(1);
 
       // Only do all this setup once.
       wasSuspended = PR_TRUE;
     }
 
     nsAutoMonitor mon(pool->Monitor());
     mon.Wait();
   }
@@ -777,24 +760,16 @@ nsDOMThreadService::CreateJSContext()
   JSAutoContextDestroyer cx(JS_NewContext(rt, 8192));
   NS_ENSURE_TRUE(cx, nsnull);
 
   JS_SetErrorReporter(cx, DOMWorkerErrorReporter);
 
   JS_SetOperationCallback(cx, DOMWorkerOperationCallback,
                           100 * JS_OPERATION_WEIGHT_BASE);
 
-  static JSSecurityCallbacks securityCallbacks = {
-    nsDOMWorkerSecurityManager::JSCheckAccess,
-    NULL,
-    NULL
-  };
-
-  JS_SetContextSecurityCallbacks(cx, &securityCallbacks);
-
   nsresult rv = nsContentUtils::XPConnect()->
     SetSecurityManagerForJSContext(cx, gWorkerSecurityManager, 0);
   NS_ENSURE_SUCCESS(rv, nsnull);
 
   return cx.forget();
 }
 
 #define LOOP_OVER_POOLS(_func, _args)                     \
@@ -853,21 +828,16 @@ nsDOMThreadService::ChangeThreadPoolMaxT
   PRUint32 currentThreadCount;
   nsresult rv = mThreadPool->GetThreadLimit(&currentThreadCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRInt32 newThreadCount = (PRInt32)currentThreadCount + (PRInt32)aDelta;
   NS_ASSERTION(newThreadCount >= THREADPOOL_MAX_THREADS,
                "Can't go below initial thread count!");
 
-  if (newThreadCount > THREADPOOL_THREAD_CAP) {
-    NS_WARNING("Thread pool cap reached!");
-    return NS_ERROR_FAILURE;
-  }
-
   rv = mThreadPool->SetThreadLimit((PRUint32)newThreadCount);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsIJSRuntimeService*
 nsDOMThreadService::JSRuntimeService()
@@ -1003,23 +973,17 @@ nsDOMThreadService::OnThreadShuttingDown
  */
 NS_IMETHODIMP
 nsDOMThreadService::CreatePool(nsIDOMWorkerPool** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   NS_ENSURE_TRUE(mThreadPool, NS_ERROR_ILLEGAL_DURING_SHUTDOWN);
 
-  nsIDOMDocument* domDocument = nsContentUtils::GetDocumentFromCaller();
-  NS_ENSURE_TRUE(domDocument, NS_ERROR_UNEXPECTED);
-
-  nsCOMPtr<nsIDocument> callingDocument(do_QueryInterface(domDocument));
-  NS_ENSURE_TRUE(callingDocument, NS_ERROR_NO_INTERFACE);
-
-  nsRefPtr<nsDOMWorkerPool> pool(new nsDOMWorkerPool(callingDocument));
+  nsRefPtr<nsDOMWorkerPool> pool(new nsDOMWorkerPool());
   NS_ENSURE_TRUE(pool, NS_ERROR_OUT_OF_MEMORY);
 
   nsresult rv = pool->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(!mPools.Contains(pool), "Um?!");
   mPools.AppendElement(pool);
 
--- a/dom/src/threads/nsDOMWorkerPool.cpp
+++ b/dom/src/threads/nsDOMWorkerPool.cpp
@@ -64,22 +64,20 @@
 #define LOOP_OVER_WORKERS(_func, _args)                   \
   PR_BEGIN_MACRO                                          \
     PRUint32 workerCount = mWorkers.Length();             \
     for (PRUint32 i = 0; i < workerCount; i++) {          \
       mWorkers[i]-> _func _args ;                         \
     }                                                     \
   PR_END_MACRO
 
-nsDOMWorkerPool::nsDOMWorkerPool(nsIDocument* aDocument)
-: mParentGlobal(nsnull),
-  mParentDocument(aDocument)
+nsDOMWorkerPool::nsDOMWorkerPool()
+: mParentGlobal(nsnull)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aDocument, "Must have a document!");
 }
 
 nsDOMWorkerPool::~nsDOMWorkerPool()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   LOOP_OVER_WORKERS(Cancel, ());
 
@@ -231,24 +229,16 @@ nsDOMWorkerPool::ResumeWorkersForGlobal(
     LOOP_OVER_WORKERS(Resume, ());
     Resume();
 
     nsAutoMonitor mon(mMonitor);
     mon.NotifyAll();
   }
 }
 
-nsIDocument*
-nsDOMWorkerPool::GetParentDocument()
-{
-  NS_ASSERTION(NS_IsMainThread(),
-               "Don't touch the non-threadsafe document off the main thread!");
-  return mParentDocument;
-}
-
 NS_IMETHODIMP
 nsDOMWorkerPool::PostMessage(const nsAString& aMessage)
 {
   nsresult rv = PostMessageInternal(aMessage);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
@@ -281,52 +271,28 @@ NS_IMETHODIMP
 nsDOMWorkerPool::GetErrorListener(nsIDOMWorkerErrorListener** aListener)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_IF_ADDREF(*aListener = mErrorListener);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWorkerPool::CreateWorker(const nsAString& aFullScript,
+nsDOMWorkerPool::CreateWorker(const nsAString& fullScript,
                               nsIDOMWorkerThread** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  NS_ENSURE_ARG(!aFullScript.IsEmpty());
+  NS_ENSURE_ARG(!fullScript.IsEmpty());
   NS_ENSURE_ARG_POINTER(_retval);
 
-  nsRefPtr<nsDOMWorkerThread> worker =
-    new nsDOMWorkerThread(this, aFullScript, PR_FALSE);
+  nsRefPtr<nsDOMWorkerThread> worker(new nsDOMWorkerThread(this, fullScript));
   NS_ENSURE_TRUE(worker, NS_ERROR_OUT_OF_MEMORY);
 
   nsresult rv = worker->Init();
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(!mWorkers.Contains(worker), "Um?!");
   mWorkers.AppendElement(worker);
 
   NS_ADDREF(*_retval = worker);
   return NS_OK;
 }
-
-NS_IMETHODIMP
-nsDOMWorkerPool::CreateWorkerFromURL(const nsAString& aScriptURL,
-                                     nsIDOMWorkerThread** _retval)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  NS_ENSURE_ARG(!aScriptURL.IsEmpty());
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  nsRefPtr<nsDOMWorkerThread> worker =
-    new nsDOMWorkerThread(this, aScriptURL, PR_TRUE);
-  NS_ENSURE_TRUE(worker, NS_ERROR_OUT_OF_MEMORY);
-
-  nsresult rv = worker->Init();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_ASSERTION(!mWorkers.Contains(worker), "Um?!");
-  mWorkers.AppendElement(worker);
-
-  NS_ADDREF(*_retval = worker);
-  return NS_OK;
-}
--- a/dom/src/threads/nsDOMWorkerPool.h
+++ b/dom/src/threads/nsDOMWorkerPool.h
@@ -47,42 +47,39 @@
 
 // Other includes
 #include "jsapi.h"
 #include "nsStringGlue.h"
 #include "nsTPtrArray.h"
 #include "prmon.h"
 
 class nsDOMWorkerThread;
-class nsIDocument;
 class nsIScriptError;
 class nsIScriptGlobalObject;
 
 /**
  * The pool is almost always touched only on the main thread.
  */
 class nsDOMWorkerPool : public nsDOMWorkerBase,
                         public nsIDOMWorkerPool,
                         public nsIClassInfo
 {
   friend class nsDOMThreadService;
   friend class nsDOMWorkerFunctions;
   friend class nsDOMWorkerPoolWeakRef;
-  friend class nsDOMWorkerScriptLoader;
-  friend class nsDOMWorkerStreamObserver;
   friend class nsDOMWorkerThread;
   friend class nsReportErrorRunnable;
   friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMWORKERPOOL
   NS_DECL_NSICLASSINFO
 
-  nsDOMWorkerPool(nsIDocument* aDocument);
+  nsDOMWorkerPool();
 
   // For nsDOMWorkerBase
   virtual nsDOMWorkerPool* Pool() {
     return this;
   }
 
 private:
   virtual ~nsDOMWorkerPool();
@@ -104,24 +101,19 @@ private:
   void CancelWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
   void SuspendWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
   void ResumeWorkersForGlobal(nsIScriptGlobalObject* aGlobalObject);
 
   PRMonitor* Monitor() {
     return mMonitor;
   }
 
-  nsIDocument* GetParentDocument();
-
   // Weak reference to the window that created and owns this pool.
   nsISupports* mParentGlobal;
 
-  // Weak reference to the document that created this pool.
-  nsIDocument* mParentDocument;
-
   // Weak array of workers. The idea is that workers can be garbage collected
   // independently of the owning pool and other workers.
   nsTPtrArray<nsDOMWorkerThread> mWorkers;
 
   // An error handler function, may be null.
   nsCOMPtr<nsIDOMWorkerErrorListener> mErrorListener;
 
   // Monitor for suspending and resuming workers.
deleted file mode 100644
--- a/dom/src/threads/nsDOMWorkerScriptLoader.cpp
+++ /dev/null
@@ -1,790 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is worker threads.
- *
- * The Initial Developer of the Original Code is
- *   Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Ben Turner <bent.mozilla@gmail.com> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * 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 "nsDOMWorkerScriptLoader.h"
-
-// Interfaces
-#include "nsIContentPolicy.h"
-#include "nsIIOService.h"
-#include "nsIRequest.h"
-#include "nsIScriptSecurityManager.h"
-#include "nsIStreamLoader.h"
-
-// Other includes
-#include "nsAutoLock.h"
-#include "nsContentErrors.h"
-#include "nsContentPolicyUtils.h"
-#include "nsContentUtils.h"
-#include "nsISupportsPrimitives.h"
-#include "nsNetError.h"
-#include "nsNetUtil.h"
-#include "nsScriptLoader.h"
-#include "nsThreadUtils.h"
-#include "pratom.h"
-
-// DOMWorker includes
-#include "nsDOMWorkerPool.h"
-#include "nsDOMThreadService.h"
-#include "nsDOMWorkerTimeout.h"
-
-#define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
-
-nsDOMWorkerScriptLoader::nsDOMWorkerScriptLoader()
-: mWorker(nsnull),
-  mTarget(nsnull),
-  mCx(NULL),
-  mScriptCount(0),
-  mCanceled(PR_FALSE),
-  mTrackedByWorker(PR_FALSE)
-{
-  // Created on worker thread.
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-}
-
-nsDOMWorkerScriptLoader::~nsDOMWorkerScriptLoader()
-{
-  // Can't touch mWorker's lock
-  if (!mCanceled) {
-    // Destroyed on worker thread, unless canceled (and then who knows!).
-    NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
-    if (mTrackedByWorker) {
-      jsrefcount suspendDepth;
-      if (mCx) {
-        suspendDepth = JS_SuspendRequest(mCx);
-      }
-
-      nsAutoLock lock(mWorker->Lock());
-  #ifdef DEBUG
-      PRBool removed =
-  #endif
-      mWorker->mScriptLoaders.RemoveElement(this);
-      NS_ASSERTION(removed, "Something is wrong here!");
-
-      if (mCx) {
-        JS_ResumeRequest(mCx, suspendDepth);
-      }
-    }
-  }
-}
-
-NS_IMPL_ISUPPORTS_INHERITED1(nsDOMWorkerScriptLoader, nsRunnable,
-                                                      nsIStreamLoaderObserver)
-
-nsresult
-nsDOMWorkerScriptLoader::LoadScripts(nsDOMWorkerThread* aWorker,
-                                     JSContext* aCx,
-                                     const nsTArray<nsString>& aURLs)
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(aWorker, "Null worker!");
-  NS_ASSERTION(aCx, "Null context!");
-
-  NS_ASSERTION(!mWorker, "Not designed to be used more than once!");
-
-  mWorker = aWorker;
-  mCx = aCx;
-
-  mTarget = NS_GetCurrentThread();
-  NS_ASSERTION(mTarget, "This should never be null!");
-
-  {
-    JSAutoSuspendRequest asr(aCx);
-    nsAutoLock lock(mWorker->Lock());
-    mTrackedByWorker = nsnull != mWorker->mScriptLoaders.AppendElement(this);
-    NS_ASSERTION(mTrackedByWorker, "Failed to add loader to worker's array!");
-  }
-
-  if (mCanceled) {
-    return NS_ERROR_ABORT;
-  }
-
-  mScriptCount = aURLs.Length();
-  if (!mScriptCount) {
-    return NS_ERROR_INVALID_ARG;
-  }
-
-  // Do all the memory work for these arrays now rather than checking for
-  // failures all along the way.
-  PRBool success = mLoadInfos.SetCapacity(mScriptCount);
-  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
-
-  // Need one runnable per script and then an extra for the finished
-  // notification.
-  success = mPendingRunnables.SetCapacity(mScriptCount + 1);
-  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
-
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    ScriptLoadInfo* newInfo = mLoadInfos.AppendElement();
-    NS_ASSERTION(newInfo, "Shouldn't fail if SetCapacity succeeded above!");
-
-    newInfo->url.Assign(aURLs[index]);
-    if (newInfo->url.IsEmpty()) {
-      return NS_ERROR_INVALID_ARG;
-    }
-
-    success = newInfo->scriptObj.Hold(aCx);
-    NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
-  }
-
-  // Don't want timeouts, etc., from queuing up while we're waiting on the
-  // network or compiling.
-  AutoSuspendWorkerEvents aswe(this);
-
-  nsresult rv = DoRunLoop();
-
-  {
-    JSAutoSuspendRequest asr(aCx);
-    nsAutoLock lock(mWorker->Lock());
-#ifdef DEBUG
-    PRBool removed =
-#endif
-    mWorker->mScriptLoaders.RemoveElement(this);
-    NS_ASSERTION(removed, "Something is wrong here!");
-    mTrackedByWorker = PR_FALSE;
-   }
-
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  // Verify that all scripts downloaded and compiled.
-  rv = VerifyScripts();
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  rv = ExecuteScripts();
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::LoadScript(nsDOMWorkerThread* aWorker,
-                                    JSContext* aCx,
-                                    const nsString& aURL)
-{
-  nsAutoTArray<nsString, 1> url;
-  url.AppendElement(aURL);
-
-  return LoadScripts(aWorker, aCx, url);
-}
-
-nsresult
-nsDOMWorkerScriptLoader::DoRunLoop()
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
-  volatile PRBool done = PR_FALSE;
-  mDoneRunnable = new ScriptLoaderDone(this, &done);
-  NS_ENSURE_TRUE(mDoneRunnable, NS_ERROR_OUT_OF_MEMORY);
-
-  nsresult rv = NS_DispatchToMainThread(this);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!(done || mCanceled)) {
-    // Since we're going to lock up this thread we might as well allow the
-    // thread service to schedule another worker on a new thread.
-    nsDOMThreadService* threadService = nsDOMThreadService::get();
-    PRBool changed = NS_SUCCEEDED(threadService->ChangeThreadPoolMaxThreads(1));
-
-    while (!(done || mCanceled)) {
-      JSAutoSuspendRequest asr(mCx);
-      NS_ProcessNextEvent(mTarget);
-    }
-
-    if (changed) {
-      threadService->ChangeThreadPoolMaxThreads(-1);
-    }
-  }
-
-  return mCanceled ? NS_ERROR_ABORT : NS_OK;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::VerifyScripts()
-{
-  nsresult rv = NS_OK;
-
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    ScriptLoadInfo& loadInfo = mLoadInfos[index];
-    NS_ASSERTION(loadInfo.done, "Inconsistent state!");
-
-    if (NS_SUCCEEDED(loadInfo.result) && loadInfo.scriptObj) {
-      continue;
-    }
-
-    NS_ASSERTION(!loadInfo.scriptObj, "Inconsistent state!");
-
-    // Flag failure before worrying about whether or not to report an error.
-    rv = NS_FAILED(loadInfo.result) ? loadInfo.result : NS_ERROR_FAILURE;
-
-    // If loadInfo.result is a success code then the compiler probably reported
-    // an error already. Also we don't really care about NS_BINDING_ABORTED
-    // since that's the code we set when some other script had a problem and the
-    // rest were canceled.
-    if (NS_SUCCEEDED(loadInfo.result) || loadInfo.result == NS_BINDING_ABORTED) {
-      continue;
-    }
-
-    // Ok, this is the script that caused us to fail.
-
-    // Only throw an error there is no other pending exception.
-    if (!JS_IsExceptionPending(mCx)) {
-      NS_ConvertUTF16toUTF8 url(loadInfo.url);
-      JS_ReportError(mCx, "Failed to compile script: %s", url.get());
-    }
-    break;
-  }
-
-  return rv;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::ExecuteScripts()
-{
-  // Now execute all the scripts.
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
-    JSScript* script =
-      static_cast<JSScript*>(JS_GetPrivate(mCx, loadInfo.scriptObj));
-    NS_ASSERTION(script, "This shouldn't ever be null!");
-
-    JSObject* global = mWorker->mGlobal ?
-                       mWorker->mGlobal :
-                       JS_GetGlobalObject(mCx);
-    NS_ENSURE_STATE(global);
-
-    // Because we may have nested calls to this function we don't want the
-    // execution to automatically report errors. We let them propagate instead.
-    uint32 oldOpts =
-      JS_SetOptions(mCx, JS_GetOptions(mCx) | JSOPTION_DONT_REPORT_UNCAUGHT);
-
-    jsval val;
-    PRBool success = JS_ExecuteScript(mCx, global, script, &val);
-
-    JS_SetOptions(mCx, oldOpts);
-
-    if (!success) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-  return NS_OK;
-}
-
-void
-nsDOMWorkerScriptLoader::Cancel()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  NS_ASSERTION(!mCanceled, "Cancel called more than once!");
-  mCanceled = PR_TRUE;
-
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
-    nsIRequest* request =
-      static_cast<nsIRequest*>(loadInfo.channel.get());
-    if (request) {
-#ifdef DEBUG
-      nsresult rv =
-#endif
-      request->Cancel(NS_BINDING_ABORTED);
-      NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to cancel channel!");
-    }
-  }
-
-  nsAutoTArray<ScriptLoaderRunnable*, 10> runnables;
-  {
-    nsAutoLock lock(mWorker->Lock());
-    runnables.AppendElements(mPendingRunnables);
-    mPendingRunnables.Clear();
-  }
-
-  PRUint32 runnableCount = runnables.Length();
-  for (PRUint32 index = 0; index < runnableCount; index++) {
-    runnables[index]->Revoke();
-  }
-
-  // We're about to post a revoked event to the worker thread, which seems
-  // silly, but we have to do this because the worker thread may be sleeping
-  // waiting on its event queue.
-  NotifyDone();
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::Run()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  // We may have been canceled already.
-  if (mCanceled) {
-    return NS_BINDING_ABORTED;
-  }
-
-  nsresult rv = RunInternal();
-  if (NS_SUCCEEDED(rv)) {
-    return rv;
-  }
-
-  // Ok, something failed beyond a normal cancel.
-
-  // If necko is holding a ref to us then we'll end up notifying in the
-  // OnStreamComplete method, not here.
-  PRBool needsNotify = PR_TRUE;
-
-  // Cancel any async channels that were already opened.
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
-    nsIRequest* request = static_cast<nsIRequest*>(loadInfo.channel.get());
-    if (request) {
-#ifdef DEBUG
-      nsresult rvInner =
-#endif
-      request->Cancel(NS_BINDING_ABORTED);
-      NS_WARN_IF_FALSE(NS_SUCCEEDED(rvInner), "Failed to cancel channel!");
-
-      // Necko is holding a ref to us so make sure that the OnStreamComplete
-      // code sends the done event.
-      needsNotify = PR_FALSE;
-    }
-    else {
-      // Make sure to set this so that the OnStreamComplete code will dispatch
-      // the done event.
-      loadInfo.done = PR_TRUE;
-    }
-  }
-
-  if (needsNotify) {
-    NotifyDone();
-  }
-
-  return rv;
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::OnStreamComplete(nsIStreamLoader* aLoader,
-                                          nsISupports* aContext,
-                                          nsresult aStatus,
-                                          PRUint32 aStringLen,
-                                          const PRUint8* aString)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  // We may have been canceled already.
-  if (mCanceled) {
-    return NS_BINDING_ABORTED;
-  }
-
-  nsresult rv = OnStreamCompleteInternal(aLoader, aContext, aStatus, aStringLen,
-                                         aString);
-
-  // Dispatch the done event if we've received all the data.
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    if (!mLoadInfos[index].done) {
-      // Some async load is still outstanding, don't notify yet.
-      break;
-    }
-
-    if (index == mScriptCount - 1) {
-      // All loads complete, signal the thread.
-      NotifyDone();
-    }
-  }
-
-  return rv;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::RunInternal()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  // Things we need to make all this work...
-  nsIDocument* parentDoc = mWorker->Pool()->GetParentDocument();
-  NS_ASSERTION(parentDoc, "Null parent document?!");
-
-  // All of these can potentially be null, but that should be ok. We'll either
-  // succeed without them or fail below.
-  nsIURI* parentBaseURI = parentDoc->GetBaseURI();
-  nsCOMPtr<nsILoadGroup> loadGroup(parentDoc->GetDocumentLoadGroup());
-  nsCOMPtr<nsIIOService> ios(do_GetIOService());
-
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    ScriptLoadInfo& loadInfo = mLoadInfos[index];
-    nsresult& rv = loadInfo.result;
-
-    nsCOMPtr<nsIURI>& uri = loadInfo.finalURI;
-    rv = nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
-                                                   loadInfo.url, parentDoc,
-                                                   parentBaseURI);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
-    NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
-
-    rv =
-      secMan->CheckLoadURIWithPrincipal(parentDoc->NodePrincipal(), uri,
-                                        nsIScriptSecurityManager::ALLOW_CHROME);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
-    rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_SCRIPT,
-                                   uri,
-                                   parentDoc->NodePrincipal(),
-                                   parentDoc,
-                                   NS_LITERAL_CSTRING("text/javascript"),
-                                   nsnull,
-                                   &shouldLoad,
-                                   nsContentUtils::GetContentPolicy(),
-                                   secMan);
-    if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
-      if (NS_FAILED(rv) || shouldLoad != nsIContentPolicy::REJECT_TYPE) {
-        return NS_ERROR_CONTENT_BLOCKED;
-      }
-      return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
-    }
-
-    // We need to know which index we're on in OnStreamComplete so we know where
-    // to put the result.
-    nsCOMPtr<nsISupportsPRUint32> indexSupports =
-      do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = indexSupports->SetData(index);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // We don't care about progress so just use the simple stream loader for
-    // OnStreamComplete notification only.
-    nsCOMPtr<nsIStreamLoader> loader;
-    rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = NS_NewChannel(getter_AddRefs(loadInfo.channel), uri, ios, loadGroup);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = loadInfo.channel->AsyncOpen(loader, indexSupports);
-    if (NS_FAILED(rv)) {
-      // Null this out so we don't try to cancel it later.
-      loadInfo.channel = nsnull;
-      return rv;
-    }
-  }
-
-  return NS_OK;
-}
-
-nsresult
-nsDOMWorkerScriptLoader::OnStreamCompleteInternal(nsIStreamLoader* aLoader,
-                                                  nsISupports* aContext,
-                                                  nsresult aStatus,
-                                                  PRUint32 aStringLen,
-                                                  const PRUint8* aString)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  nsCOMPtr<nsISupportsPRUint32> indexSupports(do_QueryInterface(aContext));
-  NS_ENSURE_TRUE(indexSupports, NS_ERROR_NO_INTERFACE);
-
-  PRUint32 index = PR_UINT32_MAX;
-  indexSupports->GetData(&index);
-
-  if (index >= mScriptCount) {
-    NS_NOTREACHED("This really can't fail or we'll hang!");
-    return NS_ERROR_FAILURE;
-  }
-
-  ScriptLoadInfo& loadInfo = mLoadInfos[index];
-
-  NS_ASSERTION(!loadInfo.done, "Got complete on the same load twice!");
-  loadInfo.done = PR_TRUE;
-
-#ifdef DEBUG
-  // Make sure we're seeing the channel that we expect.
-  nsCOMPtr<nsIRequest> request;
-  nsresult rvDebug = aLoader->GetRequest(getter_AddRefs(request));
-
-  // When we cancel sometimes we get null here. That should be ok, but only if
-  // we're canceled.
-  NS_ASSERTION(NS_SUCCEEDED(rvDebug) || mCanceled, "GetRequest failed!");
-
-  if (NS_SUCCEEDED(rvDebug)) {
-    nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
-    NS_ASSERTION(channel, "QI failed!");
-
-    nsCOMPtr<nsISupports> thisChannel(do_QueryInterface(channel));
-    NS_ASSERTION(thisChannel, "QI failed!");
-
-    nsCOMPtr<nsISupports> ourChannel(do_QueryInterface(loadInfo.channel));
-    NS_ASSERTION(ourChannel, "QI failed!");
-
-    NS_ASSERTION(thisChannel == ourChannel, "Wrong channel!");
-  }
-#endif
-
-  // Use an alias to keep rv and loadInfo.result in sync.
-  nsresult& rv = loadInfo.result = aStatus;
-
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  if (!(aStringLen && aString)) {
-    return rv = NS_ERROR_UNEXPECTED;
-  }
-
-  nsIDocument* parentDoc = mWorker->Pool()->GetParentDocument();
-  NS_ASSERTION(parentDoc, "Null parent document?!");
-
-  // Use the regular nsScriptLoader for this grunt work! Should be just fine
-  // because we're running on the main thread.
-  rv = nsScriptLoader::ConvertToUTF16(loadInfo.channel, aString, aStringLen,
-                                      EmptyString(), parentDoc,
-                                      loadInfo.scriptText);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-
-  if (loadInfo.scriptText.IsEmpty()) {
-    return rv = NS_ERROR_FAILURE;
-  }
-
-  nsCString filename;
-  loadInfo.finalURI->GetSpec(filename);
-
-  if (filename.IsEmpty()) {
-    filename.Assign(NS_LossyConvertUTF16toASCII(loadInfo.url));
-  }
-  else {
-    // This will help callers figure out what their script url resolved to in
-    // case of errors.
-    loadInfo.url.Assign(NS_ConvertUTF8toUTF16(filename));
-  }
-
-  nsRefPtr<ScriptCompiler> compiler =
-    new ScriptCompiler(this, mCx, loadInfo.scriptText, filename,
-                       loadInfo.scriptObj);
-  NS_ASSERTION(compiler, "Out of memory!");
-  if (!compiler) {
-    return rv = NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  rv = mTarget->Dispatch(compiler, NS_DISPATCH_NORMAL);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return rv;
-}
-
-void
-nsDOMWorkerScriptLoader::NotifyDone()
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  if (!mDoneRunnable) {
-    // We've already completed, no need to cancel anything.
-    return;
-  }
-
-  for (PRUint32 index = 0; index < mScriptCount; index++) {
-    ScriptLoadInfo& loadInfo = mLoadInfos[index];
-    // Null both of these out because they aren't threadsafe and must be
-    // destroyed on this thread.
-    loadInfo.channel = nsnull;
-    loadInfo.finalURI = nsnull;
-
-    if (mCanceled) {
-      // Simulate a complete, yet failed, load.
-      loadInfo.done = PR_TRUE;
-      loadInfo.result = NS_BINDING_ABORTED;
-    }
-  }
-
-#ifdef DEBUG
-  nsresult rv =
-#endif
-  mTarget->Dispatch(mDoneRunnable, NS_DISPATCH_NORMAL);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Couldn't dispatch done event!");
-
-  mDoneRunnable = nsnull;
-}
-
-void
-nsDOMWorkerScriptLoader::SuspendWorkerEvents()
-{
-  NS_ASSERTION(mWorker, "No worker yet!");
-  mWorker->SuspendTimeouts();
-}
-
-void
-nsDOMWorkerScriptLoader::ResumeWorkerEvents()
-{
-  NS_ASSERTION(mWorker, "No worker yet!");
-  mWorker->ResumeTimeouts();
-}
-
-nsDOMWorkerScriptLoader::
-ScriptLoaderRunnable::ScriptLoaderRunnable(nsDOMWorkerScriptLoader* aLoader)
-: mRevoked(PR_FALSE),
-  mLoader(aLoader)
-{
-  nsAutoLock lock(aLoader->Lock());
-#ifdef DEBUG
-  nsDOMWorkerScriptLoader::ScriptLoaderRunnable** added =
-#endif
-  aLoader->mPendingRunnables.AppendElement(this);
-  NS_ASSERTION(added, "This shouldn't fail because we SetCapacity earlier!");
-}
-
-nsDOMWorkerScriptLoader::
-ScriptLoaderRunnable::~ScriptLoaderRunnable()
-{
-  if (!mRevoked) {
-    nsAutoLock lock(mLoader->Lock());
-#ifdef DEBUG
-    PRBool removed =
-#endif
-    mLoader->mPendingRunnables.RemoveElement(this);
-    NS_ASSERTION(removed, "Someone has changed the array!");
-  }
-}
-
-void
-nsDOMWorkerScriptLoader::ScriptLoaderRunnable::Revoke()
-{
-  mRevoked = PR_TRUE;
-}
-
-nsDOMWorkerScriptLoader::
-ScriptCompiler::ScriptCompiler(nsDOMWorkerScriptLoader* aLoader,
-                               JSContext* aCx,
-                               const nsString& aScriptText,
-                               const nsCString& aFilename,
-                               nsAutoJSObjectHolder& aScriptObj)
-: ScriptLoaderRunnable(aLoader),
-  mCx(aCx),
-  mScriptText(aScriptText),
-  mFilename(aFilename),
-  mScriptObj(aScriptObj)
-{
-  NS_ASSERTION(aCx, "Null context!");
-  NS_ASSERTION(!aScriptText.IsEmpty(), "No script to compile!");
-  NS_ASSERTION(aScriptObj.IsHeld(), "Should be held!");
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::ScriptCompiler::Run()
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
-  if (mRevoked) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(!mScriptObj, "Already have a script object?!");
-  NS_ASSERTION(mScriptObj.IsHeld(), "Not held?!");
-  NS_ASSERTION(!mScriptText.IsEmpty(), "Shouldn't have empty source here!");
-
-  JSAutoRequest ar(mCx);
-
-  JSObject* global = JS_GetGlobalObject(mCx);
-  NS_ENSURE_STATE(global);
-
-  // Because we may have nested calls to this function we don't want the
-  // execution to automatically report errors. We let them propagate instead.
-  uint32 oldOpts =
-    JS_SetOptions(mCx, JS_GetOptions(mCx) | JSOPTION_DONT_REPORT_UNCAUGHT);
-
-  JSScript* script = JS_CompileUCScript(mCx, global, mScriptText.BeginReading(),
-                                        mScriptText.Length(), mFilename.get(),
-                                        1);
-  JS_SetOptions(mCx, oldOpts);
-
-  if (!script) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mScriptObj = JS_NewScriptObject(mCx, script);
-  NS_ENSURE_STATE(mScriptObj);
-
-  return NS_OK;
-}
-
-nsDOMWorkerScriptLoader::
-ScriptLoaderDone::ScriptLoaderDone(nsDOMWorkerScriptLoader* aLoader,
-                                   volatile PRBool* aDoneFlag)
-: ScriptLoaderRunnable(aLoader),
-  mDoneFlag(aDoneFlag)
-{
-  NS_ASSERTION(aDoneFlag && !*aDoneFlag, "Bad setup!");
-}
-
-NS_IMETHODIMP
-nsDOMWorkerScriptLoader::ScriptLoaderDone::Run()
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
-  if (mRevoked) {
-    return NS_OK;
-  }
-
-  *mDoneFlag = PR_TRUE;
-  return NS_OK;
-}
-
-nsDOMWorkerScriptLoader::
-AutoSuspendWorkerEvents::AutoSuspendWorkerEvents(nsDOMWorkerScriptLoader* aLoader)
-: mLoader(aLoader)
-{
-  NS_ASSERTION(aLoader, "Don't hand me null!");
-  aLoader->SuspendWorkerEvents();
-}
-
-nsDOMWorkerScriptLoader::
-AutoSuspendWorkerEvents::~AutoSuspendWorkerEvents()
-{
-  mLoader->ResumeWorkerEvents();
-}
deleted file mode 100644
--- a/dom/src/threads/nsDOMWorkerScriptLoader.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is worker threads.
- *
- * The Initial Developer of the Original Code is
- *   Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2008
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Ben Turner <bent.mozilla@gmail.com> (Original Author)
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * 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 ***** */
-
-#ifndef __NSDOMWORKERSCRIPTLOADER_H__
-#define __NSDOMWORKERSCRIPTLOADER_H__
-
-// Bases
-#include "nsThreadUtils.h"
-#include "nsIStreamLoader.h"
-
-// Interfaces
-#include "nsIChannel.h"
-#include "nsIURI.h"
-
-// Other includes
-#include "jsapi.h"
-#include "nsAutoPtr.h"
-#include "nsAutoJSObjectHolder.h"
-#include "nsCOMPtr.h"
-#include "nsStringGlue.h"
-#include "nsTArray.h"
-#include "prlock.h"
-
-// DOMWorker includes
-#include "nsDOMWorkerThread.h"
-
-/**
- * This class takes a list of script URLs, downloads the scripts, compiles the
- * scripts, and then finally executes them. Due to platform limitations all
- * network operations must happen on the main thread so this object sends events
- * back and forth from the worker thread to the main thread. The flow goes like
- * this:
- *
- *  1. (Worker thread) nsDOMWorkerScriptLoader created.
- *  2. (Worker thread) LoadScript(s) called. Some simple argument validation is
- *                     performed (currently limited to ensuring that all
- *                     arguments are strings). nsDOMWorkerScriptLoader is then
- *                     dispatched to the main thread.
- *  3. (Main thread)   Arguments validated as URIs, security checks performed,
- *                     content policy consulted. Network loads begin.
- *  4. (Necko thread)  Necko stuff!
- *  5. (Main thread)   Completed downloads are packaged in a ScriptCompiler
- *                     runnable and sent to the worker thread.
- *  6. (Worker thread) ScriptCompiler runnables are processed (i.e. their
- *                     scripts are compiled) in the order in which the necko
- *                     downloads completed.
- *  7. (Worker thread) After all loads complete and all compilation succeeds
- *                     the scripts are executed in the order that the URLs were
- *                     given to LoadScript(s).
- *
- * Currently if *anything* after 2 fails then we cancel any pending loads and
- * bail out entirely.
- */
-class nsDOMWorkerScriptLoader : public nsRunnable,
-                                public nsIStreamLoaderObserver
-{
-  friend class AutoSuspendWorkerEvents;
-  friend class nsDOMWorkerFunctions;
-  friend class nsDOMWorkerThread;
-  friend class ScriptLoaderRunnable;
-
-public:
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIRUNNABLE
-  NS_DECL_NSISTREAMLOADEROBSERVER
-
-  nsDOMWorkerScriptLoader();
-
-  nsresult LoadScripts(nsDOMWorkerThread* aWorker,
-                       JSContext* aCx,
-                       const nsTArray<nsString>& aURLs);
-
-  nsresult LoadScript(nsDOMWorkerThread* aWorker,
-                       JSContext* aCx,
-                       const nsString& aURL);
-
-  void Cancel();
-
-private:
-  ~nsDOMWorkerScriptLoader();
-
-  nsresult DoRunLoop();
-  nsresult VerifyScripts();
-  nsresult ExecuteScripts();
-
-  nsresult RunInternal();
-
-  nsresult OnStreamCompleteInternal(nsIStreamLoader* aLoader,
-                                    nsISupports* aContext,
-                                    nsresult aStatus,
-                                    PRUint32 aStringLen,
-                                    const PRUint8* aString);
-
-  void NotifyDone();
-
-  void SuspendWorkerEvents();
-  void ResumeWorkerEvents();
-
-  PRLock* Lock() {
-    return mWorker->Lock();
-  }
-
-  class ScriptLoaderRunnable : public nsRunnable
-  {
-  protected:
-    // Meant to be inherited.
-    ScriptLoaderRunnable(nsDOMWorkerScriptLoader* aLoader);
-    virtual ~ScriptLoaderRunnable();
-
-  public:
-    void Revoke();
-
-  protected:
-    PRBool mRevoked;
-
-  private:
-    nsDOMWorkerScriptLoader* mLoader;
-  };
-
-  class ScriptCompiler : public ScriptLoaderRunnable
-  {
-  public:
-    NS_DECL_NSIRUNNABLE
-
-    ScriptCompiler(nsDOMWorkerScriptLoader* aLoader,
-                   JSContext* aCx,
-                   const nsString& aScriptText,
-                   const nsCString& aFilename,
-                   nsAutoJSObjectHolder& aScriptObj);
-
-  private:
-    JSContext* mCx;
-    nsString mScriptText;
-    nsCString mFilename;
-    nsAutoJSObjectHolder& mScriptObj;
-  };
-
-  class ScriptLoaderDone : public ScriptLoaderRunnable
-  {
-  public:
-    NS_DECL_NSIRUNNABLE
-
-    ScriptLoaderDone(nsDOMWorkerScriptLoader* aLoader,
-                     volatile PRBool* aDoneFlag);
-
-  private:
-    volatile PRBool* mDoneFlag;
-  };
-
-  class AutoSuspendWorkerEvents
-  {
-  public:
-    AutoSuspendWorkerEvents(nsDOMWorkerScriptLoader* aLoader);
-    ~AutoSuspendWorkerEvents();
-
-  private:
-    nsDOMWorkerScriptLoader* mLoader;
-  };
-
-  struct ScriptLoadInfo
-  {
-    ScriptLoadInfo() : done(PR_FALSE), result(NS_ERROR_NOT_INITIALIZED) { }
-
-    nsString url;
-    nsString scriptText;
-    PRBool done;
-    nsresult result;
-    nsCOMPtr<nsIURI> finalURI;
-    nsCOMPtr<nsIChannel> channel;
-    nsAutoJSObjectHolder scriptObj;
-  };
-
-  nsDOMWorkerThread* mWorker;
-  nsIThread* mTarget;
-  JSContext* mCx;
-
-  nsRefPtr<ScriptLoaderDone> mDoneRunnable;
-
-  PRUint32 mScriptCount;
-  nsTArray<ScriptLoadInfo> mLoadInfos;
-
-  PRPackedBool mCanceled;
-  PRPackedBool mTrackedByWorker;
-
-  // Protected by mWorker's lock!
-  nsTArray<ScriptLoaderRunnable*> mPendingRunnables;
-};
-
-#endif /* __NSDOMWORKERSCRIPTLOADER_H__ */
--- a/dom/src/threads/nsDOMWorkerSecurityManager.cpp
+++ b/dom/src/threads/nsDOMWorkerSecurityManager.cpp
@@ -83,18 +83,8 @@ nsDOMWorkerSecurityManager::CanAccess(PR
                                       JSObject* aJSObject,
                                       nsISupports* aObj,
                                       nsIClassInfo* aClassInfo,
                                       jsval aName,
                                       void** aPolicy)
 {
   return NS_OK;
 }
-
-JSBool
-nsDOMWorkerSecurityManager::JSCheckAccess(JSContext *cx,
-                                          JSObject *obj,
-                                          jsval id,
-                                          JSAccessMode mode,
-                                          jsval *vp)
-{
-  return JS_TRUE;
-}
--- a/dom/src/threads/nsDOMWorkerSecurityManager.h
+++ b/dom/src/threads/nsDOMWorkerSecurityManager.h
@@ -35,22 +35,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __NSDOMWORKERSECURITYMANAGER_H__
 #define __NSDOMWORKERSECURITYMANAGER_H__
 
 #include "nsIXPCSecurityManager.h"
-#include "jsapi.h"
 
 class nsDOMWorkerSecurityManager : public nsIXPCSecurityManager
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIXPCSECURITYMANAGER
-
-  static JSBool JSCheckAccess(JSContext *cx, JSObject *obj, jsval id,
-                              JSAccessMode mode, jsval *vp);
-
 };
 
 #endif /* __NSDOMWORKERSECURITYMANAGER_H__ */
--- a/dom/src/threads/nsDOMWorkerThread.cpp
+++ b/dom/src/threads/nsDOMWorkerThread.cpp
@@ -49,21 +49,19 @@
 // Other includes
 #ifdef MOZ_SHARK
 #include "jsdbgapi.h"
 #endif
 #include "nsAutoLock.h"
 #include "nsContentUtils.h"
 #include "nsJSUtils.h"
 #include "nsJSEnvironment.h"
-#include "nsThreadUtils.h"
 
 // DOMWorker includes
 #include "nsDOMWorkerPool.h"
-#include "nsDOMWorkerScriptLoader.h"
 #include "nsDOMThreadService.h"
 #include "nsDOMWorkerTimeout.h"
 
 #define LOG(_args) PR_LOG(gDOMThreadsLog, PR_LOG_DEBUG, _args)
 
 // XXX Could make these functions of nsDOMWorkerThread instead.
 class nsDOMWorkerFunctions
 {
@@ -91,19 +89,16 @@ public:
                             jsval* aArgv, jsval* aRval) {
     return MakeTimeout(aCx, aObj, aArgc, aArgv, aRval, PR_TRUE);
   }
 
   // Used for both clearTimeout() and clearInterval().
   static JSBool KillTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
                             jsval* aArgv, jsval* aRval);
 
-  static JSBool LoadScripts(JSContext* aCx, JSObject* aObj, uintN aArgc,
-                            jsval* aArgv, jsval* aRval);
-
 private:
   // Internal helper for SetTimeout and SetInterval.
   static JSBool MakeTimeout(JSContext* aCx, JSObject* aObj, uintN aArgc,
                             jsval* aArgv, jsval* aRval, PRBool aIsInterval);
 };
 
 JSBool
 nsDOMWorkerFunctions::Dump(JSContext* aCx,
@@ -159,21 +154,17 @@ nsDOMWorkerFunctions::PostMessage(JSCont
 
   JSString* str;
   if (aArgc && (str = JS_ValueToString(aCx, aArgv[0])) && str) {
     rv = pool->PostMessageInternal(nsDependentJSString(str), worker);
   }
   else {
     rv = pool->PostMessageInternal(EmptyString(), worker);
   }
-
-  if (NS_FAILED(rv)) {
-    JS_ReportError(aCx, "Failed to post message!");
-    return JS_FALSE;
-  }
+  NS_ENSURE_SUCCESS(rv, JS_FALSE);
 
   return JS_TRUE;
 }
 
 JSBool
 nsDOMWorkerFunctions::MakeTimeout(JSContext* aCx,
                                   JSObject* /* aObj */,
                                   uintN aArgc,
@@ -188,26 +179,20 @@ nsDOMWorkerFunctions::MakeTimeout(JSCont
   if (worker->IsCanceled()) {
     return JS_FALSE;
   }
 
   PRUint32 id = ++worker->mNextTimeoutId;
 
   nsAutoPtr<nsDOMWorkerTimeout>
     timeout(new nsDOMWorkerTimeout(worker, id));
-  if (!timeout) {
-    JS_ReportOutOfMemory(aCx);
-    return JS_FALSE;
-  }
+  NS_ENSURE_TRUE(timeout, JS_FALSE);
 
   nsresult rv = timeout->Init(aCx, aArgc, aArgv, aIsInterval);
-  if (NS_FAILED(rv)) {
-    JS_ReportError(aCx, "Failed to initialize timeout!");
-    return JS_FALSE;
-  }
+  NS_ENSURE_SUCCESS(rv, JS_FALSE);
 
   timeout.forget();
 
   *aRval = INT_TO_JSVAL(id);
   return JS_TRUE;
 }
 
 JSBool
@@ -236,86 +221,24 @@ nsDOMWorkerFunctions::KillTimeout(JSCont
     JS_ReportError(aCx, "First argument must be a timeout id");
     return JS_FALSE;
   }
 
   worker->CancelTimeout(PRUint32(id));
   return JS_TRUE;
 }
 
-JSBool JS_DLL_CALLBACK
-nsDOMWorkerFunctions::LoadScripts(JSContext* aCx,
-                                  JSObject* /* aObj */,
-                                  uintN aArgc,
-                                  jsval* aArgv,
-                                  jsval* /* aRval */)
-{
-  nsDOMWorkerThread* worker =
-    static_cast<nsDOMWorkerThread*>(JS_GetContextPrivate(aCx));
-  NS_ASSERTION(worker, "This should be set by the DOM thread service!");
-
-  if (worker->IsCanceled()) {
-    return JS_FALSE;
-  }
-
-  if (!aArgc) {
-    JS_ReportError(aCx, "Function must have at least one argument!");
-    return JS_FALSE;
-  }
-
-  nsAutoTArray<nsString, 5> urls;
-
-  if (!urls.SetCapacity((PRUint32)aArgc)) {
-    JS_ReportOutOfMemory(aCx);
-    return JS_FALSE;
-  }
-
-  for (uintN index = 0; index < aArgc; index++) {
-    jsval val = aArgv[index];
-
-    if (!JSVAL_IS_STRING(val)) {
-      JS_ReportError(aCx, "Argument %d must be a string", index);
-      return JS_FALSE;
-    }
-
-    JSString* str = JS_ValueToString(aCx, val);
-    if (!str) {
-      JS_ReportError(aCx, "Couldn't convert argument %d to a string", index);
-      return JS_FALSE;
-    }
-
-    nsString* newURL = urls.AppendElement();
-    NS_ASSERTION(newURL, "Shouldn't fail if SetCapacity succeeded above!");
-
-    newURL->Assign(nsDependentJSString(str));
-  }
-
-  nsRefPtr<nsDOMWorkerScriptLoader> loader = new nsDOMWorkerScriptLoader();
-  if (!loader) {
-    JS_ReportOutOfMemory(aCx);
-    return JS_FALSE;
-  }
-
-  nsresult rv = loader->LoadScripts(worker, aCx, urls);
-  if (NS_FAILED(rv)) {
-    return JS_FALSE;
-  }
-
-  return JS_TRUE;
-}
-
 JSFunctionSpec gDOMWorkerFunctions[] = {
   { "dump",                  nsDOMWorkerFunctions::Dump,              1, 0, 0 },
   { "debug",                 nsDOMWorkerFunctions::DebugDump,         1, 0, 0 },
   { "postMessageToPool",     nsDOMWorkerFunctions::PostMessage,       1, 0, 0 },
   { "setTimeout",            nsDOMWorkerFunctions::SetTimeout,        1, 0, 0 },
   { "clearTimeout",          nsDOMWorkerFunctions::KillTimeout,       1, 0, 0 },
   { "setInterval",           nsDOMWorkerFunctions::SetInterval,       1, 0, 0 },
   { "clearInterval",         nsDOMWorkerFunctions::KillTimeout,       1, 0, 0 },
-  { "loadScripts",           nsDOMWorkerFunctions::LoadScripts,       1, 0, 0 },
 #ifdef MOZ_SHARK
   { "startShark",            js_StartShark,                           0, 0, 0 },
   { "stopShark",             js_StopShark,                            0, 0, 0 },
   { "connectShark",          js_ConnectShark,                         0, 0, 0 },
   { "disconnectShark",       js_DisconnectShark,                      0, 0, 0 },
 #endif
   { nsnull,                  nsnull,                                  0, 0, 0 }
 };
@@ -378,49 +301,53 @@ nsDOMWorkerThreadContext::GetThisThread(
     NS_ENSURE_TRUE(mWeakRef, NS_ERROR_OUT_OF_MEMORY);
   }
 
   NS_ADDREF(*aThisThread = mWeakRef);
   return NS_OK;
 }
 
 nsDOMWorkerThread::nsDOMWorkerThread(nsDOMWorkerPool* aPool,
-                                     const nsAString& aSource,
-                                     PRBool aSourceIsURL)
+                                     const nsAString& aSource)
 : mPool(aPool),
+  mSource(aSource),
+  mGlobal(nsnull),
   mCompiled(PR_FALSE),
   mCallbackCount(0),
   mNextTimeoutId(0),
   mLock(nsnull)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  if (aSourceIsURL) {
-    mSourceURL.Assign(aSource);
-    NS_ASSERTION(!mSourceURL.IsEmpty(), "Empty source url!");
-  }
-  else {
-    mSource.Assign(aSource);
-    NS_ASSERTION(!mSource.IsEmpty(), "Empty source string!");
-  }
+  NS_ASSERTION(!aSource.IsEmpty(), "Empty source string!");
 
   PR_INIT_CLIST(&mTimeouts);
 }
 
 nsDOMWorkerThread::~nsDOMWorkerThread()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!IsCanceled()) {
     nsRefPtr<nsDOMWorkerPool> pool = Pool();
     pool->NoteDyingWorker(this);
   }
 
   ClearTimeouts();
 
+  // Only clean up if we created a global object
+  if (mGlobal) {
+    JSRuntime* rt;
+    if (NS_SUCCEEDED(nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt))) {
+      JS_RemoveRootRT(rt, &mGlobal);
+    }
+    else {
+      NS_ERROR("This shouldn't fail!");
+    }
+  }
+
   if (mLock) {
     nsAutoLock::DestroyLock(mLock);
   }
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsDOMWorkerThread, nsIDOMWorkerThread,
                                                  nsIClassInfo)
 NS_IMPL_CI_INTERFACE_GETTER1(nsDOMWorkerThread, nsIDOMWorkerThread)
@@ -430,30 +357,23 @@ NS_IMPL_THREADSAFE_DOM_CI(nsDOMWorkerThr
 nsresult
 nsDOMWorkerThread::Init()
 {
   mLock = nsAutoLock::NewLock("nsDOMWorkerThread::mLock");
   NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ASSERTION(!mGlobal, "Already got a global?!");
 
-  JSRuntime* rt;
-  nsresult rv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRBool success = mGlobal.Hold(rt);
-  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
-
   // This is pretty cool - all we have to do to get our script executed is to
   // pass a no-op runnable to the thread service and it will make sure we have
   // a context and global object.
   nsCOMPtr<nsIRunnable> runnable(new nsRunnable());
   NS_ENSURE_TRUE(runnable, NS_ERROR_OUT_OF_MEMORY);
 
-  rv = nsDOMThreadService::get()->Dispatch(this, runnable);
+  nsresult rv = nsDOMThreadService::get()->Dispatch(this, runnable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 // From nsDOMWorkerBase
 nsresult
 nsDOMWorkerThread::HandleMessage(const nsAString& aMessage,
@@ -520,21 +440,25 @@ nsDOMWorkerThread::HandleMessage(const n
   JSObject* listener;
   rv = wrappedListener->GetJSObject(&listener);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // And call it.
   jsval rval;
   PRBool success = JS_CallFunctionValue(cx, mGlobal, OBJECT_TO_JSVAL(listener),
                                         2, argv, &rval);
-  if (!success && JS_IsExceptionPending(cx)) {
+  if (!success) {
     // Make sure any pending exceptions are converted to errors for the pool.
     JS_ReportPendingException(cx);
   }
 
+  // We shouldn't leave any pending exceptions - our error reporter should
+  // clear any exception it reports.
+  NS_ASSERTION(!JS_IsExceptionPending(cx), "Huh?!");
+
   return NS_OK;
 }
 
 // From nsDOMWorkerBase
 nsresult
 nsDOMWorkerThread::DispatchMessage(nsIRunnable* aRunnable)
 {
   nsresult rv = nsDOMThreadService::get()->Dispatch(this, aRunnable);
@@ -543,19 +467,16 @@ nsDOMWorkerThread::DispatchMessage(nsIRu
   return NS_OK;
 }
 
 void
 nsDOMWorkerThread::Cancel()
 {
   nsDOMWorkerBase::Cancel();
 
-  // Do this before waiting on the thread service below!
-  CancelScriptLoaders();
-
   // If we're suspended there's a good chance that we're already paused waiting
   // on the pool's monitor. Waiting on the thread service's lock will deadlock.
   if (!IsSuspended()) {
     nsDOMThreadService::get()->WaitForCanceledWorker(this);
   }
 
   ClearTimeouts();
 }
@@ -573,19 +494,17 @@ nsDOMWorkerThread::Resume()
   nsDOMWorkerBase::Resume();
   ResumeTimeouts();
 }
 
 PRBool
 nsDOMWorkerThread::SetGlobalForContext(JSContext* aCx)
 {
   PRBool success = CompileGlobalObject(aCx);
-  if (!success) {
-    return PR_FALSE;
-  }
+  NS_ENSURE_TRUE(success, PR_FALSE);
 
   JS_SetGlobalObject(aCx, mGlobal);
   return PR_TRUE;
 }
 
 PRBool
 nsDOMWorkerThread::CompileGlobalObject(JSContext* aCx)
 {
@@ -639,48 +558,42 @@ nsDOMWorkerThread::CompileGlobalObject(J
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
   // Set up a name for our worker object
   success = JS_DefineProperty(aCx, global, "threadContext",
                               OBJECT_TO_JSVAL(contextObj), nsnull, nsnull,
                               JSPROP_ENUMERATE);
   NS_ENSURE_TRUE(success, PR_FALSE);
 
-  jsval val;
-
-  // From here on out we have to remember to null mGlobal if something fails!
-  mGlobal = global;
+  JSScript* script = JS_CompileUCScript(aCx, global,
+                                        reinterpret_cast<const jschar*>
+                                            (mSource.BeginReading()),
+                                        mSource.Length(), nsnull, 1);
+  NS_ENSURE_TRUE(script, PR_FALSE);
 
-  if (mSource.IsEmpty()) {
-    NS_ASSERTION(!mSourceURL.IsEmpty(), "Must have a url here!");
-
-    nsRefPtr<nsDOMWorkerScriptLoader> loader = new nsDOMWorkerScriptLoader();
-    NS_ASSERTION(loader, "Out of memory!");
-    if (!loader) {
-      mGlobal = NULL;
-      return PR_FALSE;
-    }
+  JSRuntime* rt;
+  rv = nsDOMThreadService::JSRuntimeService()->GetRuntime(&rt);
+  NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
-    rv = loader->LoadScript(this, aCx, mSourceURL);
-    JS_ReportPendingException(aCx);
-    if (NS_FAILED(rv)) {
-      mGlobal = NULL;
-      return PR_FALSE;
-    }
+  mGlobal = global;
+  success = JS_AddNamedRootRT(rt, &mGlobal, "nsDOMWorkerThread Global Object");
+  if (!success) {
+    NS_WARNING("Failed to root global object for worker thread!");
+    mGlobal = nsnull;
+    return PR_FALSE;
   }
-  else {
-    NS_ASSERTION(!mSource.IsEmpty(), "No source text!");
 
-    // Evaluate and execute the script
-    success = JS_EvaluateUCScript(aCx, global, mSource.get(), mSource.Length(),
-                                  "DOMWorker inline script", 1, &val);
-    if (!success) {
-      mGlobal = NULL;
-      return PR_FALSE;
-    }
+  // Execute the script
+  jsval val;
+  success = JS_ExecuteScript(aCx, global, script, &val);
+  if (!success) {
+    NS_WARNING("Failed to evaluate script for worker thread!");
+    JS_RemoveRootRT(rt, &mGlobal);
+    mGlobal = nsnull;
+    return PR_FALSE;
   }
 
   // See if the message listener function was defined.
   nsCOMPtr<nsIDOMWorkerMessageListener> listener;
   if (JS_LookupProperty(aCx, global, "messageListener", &val) &&
       JSVAL_IS_OBJECT(val) &&
       NS_SUCCEEDED(xpc->WrapJS(aCx, JSVAL_TO_OBJECT(val),
                                NS_GET_IID(nsIDOMWorkerMessageListener),
@@ -827,35 +740,15 @@ nsDOMWorkerThread::ResumeTimeouts()
   PRTime now = PR_Now();
 
   PRUint32 count = timeouts.Length();
   for (PRUint32 i = 0; i < count; i++) {
     timeouts[i]->Resume(now);
   }
 }
 
-void
-nsDOMWorkerThread::CancelScriptLoaders()
-{
-  nsAutoTArray<nsDOMWorkerScriptLoader*, 20> loaders;
-
-  // Must call cancel on the loaders outside the lock!
-  {
-    nsAutoLock lock(mLock);
-    loaders.AppendElements(mScriptLoaders);
-
-    // Don't clear mScriptLoaders, they'll remove themselves as they get
-    // destroyed.
-  }
-
-  PRUint32 loaderCount = loaders.Length();
-  for (PRUint32 index = 0; index < loaderCount; index++) {
-    loaders[index]->Cancel();
-  }
-}
-
 NS_IMETHODIMP
 nsDOMWorkerThread::PostMessage(const nsAString& aMessage)
 {
   nsresult rv = PostMessageInternal(aMessage);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
--- a/dom/src/threads/nsDOMWorkerThread.h
+++ b/dom/src/threads/nsDOMWorkerThread.h
@@ -42,20 +42,18 @@
 
 // Bases
 #include "nsDOMWorkerBase.h"
 #include "nsIClassInfo.h"
 #include "nsIDOMThreads.h"
 
 // Other includes
 #include "jsapi.h"
-#include "nsAutoJSObjectHolder.h"
 #include "nsCOMPtr.h"
 #include "nsStringGlue.h"
-#include "nsTArray.h"
 #include "nsThreadUtils.h"
 #include "prclist.h"
 #include "prlock.h"
 
 // DOMWorker includes
 #include "nsDOMThreadService.h"
 
 // Macro to generate nsIClassInfo methods for these threadsafe DOM classes 
@@ -110,40 +108,37 @@ NS_IMETHODIMP                           
                                                                               \
 NS_IMETHODIMP                                                                 \
 _class::GetClassIDNoAlloc(nsCID* _classIDNoAlloc)                             \
 {                                                                             \
   return NS_ERROR_NOT_AVAILABLE;                                              \
 }
 
 class nsDOMWorkerPool;
-class nsDOMWorkerScriptLoader;
 class nsDOMWorkerTimeout;
 
 class nsDOMWorkerThread : public nsDOMWorkerBase,
                           public nsIDOMWorkerThread,
                           public nsIClassInfo
 {
   friend class nsDOMCreateJSContextRunnable;
   friend class nsDOMWorkerFunctions;
   friend class nsDOMWorkerPool;
   friend class nsDOMWorkerRunnable;
-  friend class nsDOMWorkerScriptLoader;
   friend class nsDOMWorkerTimeout;
 
   friend JSBool DOMWorkerOperationCallback(JSContext* aCx);
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMWORKERTHREAD
   NS_DECL_NSICLASSINFO
 
   nsDOMWorkerThread(nsDOMWorkerPool* aPool,
-                    const nsAString& aSource,
-                    PRBool aSourceIsURL);
+                    const nsAString& aSource);
 
   virtual nsDOMWorkerPool* Pool() {
     NS_ASSERTION(!IsCanceled(), "Don't touch Pool after we've been canceled!");
     return mPool;
   }
 
 private:
   virtual ~nsDOMWorkerThread();
@@ -169,32 +164,23 @@ private:
 
   void AddTimeout(nsDOMWorkerTimeout* aTimeout);
   void RemoveTimeout(nsDOMWorkerTimeout* aTimeout);
   void ClearTimeouts();
   void CancelTimeout(PRUint32 aId);
   void SuspendTimeouts();
   void ResumeTimeouts();
 
-  void CancelScriptLoaders();
-
-  PRLock* Lock() {
-    return mLock;
-  }
-
   nsDOMWorkerPool* mPool;
   nsString mSource;
-  nsString mSourceURL;
 
-  nsAutoJSObjectHolder mGlobal;
+  JSObject* mGlobal;
   PRBool mCompiled;
 
   PRUint32 mCallbackCount;
 
   PRUint32 mNextTimeoutId;
 
   PRLock* mLock;
   PRCList mTimeouts;
-
-  nsTArray<nsDOMWorkerScriptLoader*> mScriptLoaders;
 };
 
 #endif /* __NSDOMWORKERTHREAD_H__ */
--- a/dom/src/threads/test/Makefile.in
+++ b/dom/src/threads/test/Makefile.in
@@ -42,22 +42,16 @@ srcdir           = @srcdir@
 VPATH            = @srcdir@
 
 relativesrcdir   = dom/src/threads/tests
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = \
-  importScripts_worker.js \
-  importScripts_worker_imported1.js \
-  importScripts_worker_imported2.js \
-  importScripts_worker_imported3.js \
-  importScripts_worker_imported4.js \
-  test_importScripts.html \
   test_simpleThread.html \
   test_threadErrors.html \
   test_threadTimeouts.html \
   test_longThread.html \
   $(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker.js
+++ /dev/null
@@ -1,54 +0,0 @@
-function messageListener(message, source) {
-  switch (message) {
-    case 'start':
-      loadScripts("importScripts_worker_imported2.js");
-      importedScriptFunction2();
-      tryBadScripts();
-      source.postMessage('started');
-      break;
-    case 'stop':
-      tryBadScripts();
-      postMessageToPool('stopped');
-      break;
-    default:
-      throw new Error("Bad message: " + message);
-      break;
-  }
-}
-
-// This caused security exceptions in the past, make sure it doesn't!
-var constructor = {}.constructor;
-
-loadScripts("importScripts_worker_imported1.js");
-
-// Try to call a function defined in the imported script.
-importedScriptFunction();
-
-function tryBadScripts() {
-  var badScripts = [
-    // Has a syntax error
-    "importScripts_worker_imported3.js",
-    // Throws an exception
-    "importScripts_worker_imported4.js",
-    // Shouldn't exist!
-    "http://flippety.com/floppety/foo.js",
-    // Not a valid url
-    "http://flippety::foo_js ftw"
-  ];
-
-  for (var i = 0; i < badScripts.length; i++) {
-    var caughtException = false;
-    var url = badScripts[i];
-    try {
-      loadScripts(url);
-    }
-    catch (e) {
-      caughtException = true;
-    }
-    if (!caughtException) {
-      throw "Bad script didn't throw exception: " + url;
-    }
-  }
-}
-
-tryBadScripts();
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported1.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// This caused security exceptions in the past, make sure it doesn't!
-var myConstructor = {}.constructor;
-
-// Try to call a function defined in the imported script.
-function importedScriptFunction() {
-  dump("running importedScriptFunction\n");
-}
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported2.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// This caused security exceptions in the past, make sure it doesn't!
-var myConstructor2 = {}.constructor;
-
-// Try to call a function defined in the imported script.
-function importedScriptFunction2() {
-  dump("running importedScriptFunction2\n");
-}
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported3.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// Deliberate syntax error, should generate a worker exception!
-for (var index = 0; index < 100) {}
deleted file mode 100644
--- a/dom/src/threads/test/importScripts_worker_imported4.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// Deliberate throw, should generate a worker exception!
-throw new Error("Bah!");
deleted file mode 100644
--- a/dom/src/threads/test/test_importScripts.html
+++ /dev/null
@@ -1,49 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-Tests of DOM Worker Threads (Bug 437152)
--->
-<head>
-  <title>Test for DOM Worker Threads (Bug 437152)</title>
-  <script type="text/javascript" src="/MochiKit/MochiKit.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>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=437152">DOM Worker Threads Bug 437152</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script class="testbody" type="text/javascript">
-
-  var pool = navigator.newWorkerPool();
-  pool.messageListener = function(message, source) {
-    switch (message) {
-      case "started":
-        source.postMessage("stop");
-        break;
-      case "stopped":
-        SimpleTest.finish();
-        break;
-      default:
-        ok(false, "Unexpected message:" + message);
-        SimpleTest.finish();
-    }
-  };
-
-  pool.errorListener = function(error, source) {
-    ok(false, "Worker had an error:" + error);
-    SimpleTest.finish();
-  }
-
-  var worker = pool.createWorkerFromURL("importScripts_worker.js");
-  worker.postMessage("start");
-
-  SimpleTest.waitForExplicitFinish();
-</script>
-</pre>
-</body>
-</html>
-