diff --git a/content/base/src/nsScriptLoader.cpp b/content/base/src/nsScriptLoader.cpp
index 33415dd23c490937ac280fd4e05a1a3b878a05c9..e51a3eaa643f7c9427aa4a6254891884970bdf0d 100644
--- a/content/base/src/nsScriptLoader.cpp
+++ b/content/base/src/nsScriptLoader.cpp
@@ -853,7 +853,7 @@ nsScriptLoader::AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest)
   // This reference will be consumed by OffThreadScriptLoaderCallback.
   NS_ADDREF(runnable);
 
-  if (!JS::CompileOffThread(cx, global, options,
+  if (!JS::CompileOffThread(cx, options,
                             aRequest->mScriptText.get(), aRequest->mScriptText.Length(),
                             OffThreadScriptLoaderCallback,
                             static_cast<void*>(runnable))) {
diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp
index 9fd1de91d4e76e4c8f2fc7b559a291e05abc1857..05d50ecea921cd1efbd8de423b9e74b9372a0751 100644
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -2662,7 +2662,7 @@ nsXULPrototypeScript::Compile(const char16_t* aText,
     }
 
     if (aOffThreadReceiver && JS::CanCompileOffThread(cx, options, aTextLength)) {
-        if (!JS::CompileOffThread(cx, scope, options,
+        if (!JS::CompileOffThread(cx, options,
                                   static_cast<const jschar*>(aText), aTextLength,
                                   OffThreadScriptReceiverCallback,
                                   static_cast<void*>(aOffThreadReceiver))) {
diff --git a/js/src/jit-test/tests/debug/onNewScript-off-main-thread.js b/js/src/jit-test/tests/debug/onNewScript-off-main-thread.js
index 08267f85230799cc99673a15c37ac7eaeff00995..b59307bb8efaf9bcf85ebcdc0e0e27ab85fc53b8 100644
--- a/js/src/jit-test/tests/debug/onNewScript-off-main-thread.js
+++ b/js/src/jit-test/tests/debug/onNewScript-off-main-thread.js
@@ -14,5 +14,5 @@ dbg.onNewScript = function (s) {
 
 log = '';
 g.offThreadCompileScript('"t" + "wine"');
-assertEq(runOffThreadScript(), 'twine');
+assertEq(g.runOffThreadScript(), 'twine');
 assertEq(log, 's');
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 23ed775eac281460970096fc41f8b9e14ba45d4b..a74f809559c0c714164e441e0c571df56cc8c2f5 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -4519,12 +4519,12 @@ JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, si
 }
 
 JS_PUBLIC_API(bool)
-JS::CompileOffThread(JSContext *cx, Handle<JSObject*> obj, const ReadOnlyCompileOptions &options,
+JS::CompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options,
                      const jschar *chars, size_t length,
                      OffThreadCompileCallback callback, void *callbackData)
 {
     JS_ASSERT(CanCompileOffThread(cx, options, length));
-    return StartOffThreadParseScript(cx, options, chars, length, obj, callback, callbackData);
+    return StartOffThreadParseScript(cx, options, chars, length, callback, callbackData);
 }
 
 JS_PUBLIC_API(JSScript *)
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index d77fdf0d7116acecfbd5f115dc6f863160c95a84..5c48ebcb75d74ed88e4950975bfde2540d538d15 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3641,8 +3641,8 @@ CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t
  * for the compilation. The callback will be invoked while off the main thread,
  * so must ensure that its operations are thread safe. Afterwards,
  * FinishOffThreadScript must be invoked on the main thread to get the result
- * script or nullptr. If maybecx is specified, this method will also report
- * any error or warnings generated during the parse.
+ * script or nullptr. If maybecx is not specified, the resources will be freed,
+ * but no script will be returned.
  *
  * The characters passed in to CompileOffThread must remain live until the
  * callback is invoked, and the resulting script will be rooted until the call
@@ -3650,7 +3650,7 @@ CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t
  */
 
 extern JS_PUBLIC_API(bool)
-CompileOffThread(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &options,
+CompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options,
                  const jschar *chars, size_t length,
                  OffThreadCompileCallback callback, void *callbackData);
 
diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp
index e40639852b0e6e5b54b25a22c33fcc0cfcbb4fb5..b5e42357ee93b325f7130d5bcbbff4ced893f693 100644
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -176,10 +176,10 @@ static const JSClass workerGlobalClass = {
 };
 
 ParseTask::ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
-                     const jschar *chars, size_t length, JSObject *scopeChain,
+                     const jschar *chars, size_t length,
                      JS::OffThreadCompileCallback callback, void *callbackData)
   : cx(cx), options(initCx), chars(chars), length(length),
-    alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), scopeChain(initCx, scopeChain),
+    alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     exclusiveContextGlobal(initCx, exclusiveContextGlobal), optionsElement(initCx),
     optionsIntroductionScript(initCx), callback(callback), callbackData(callbackData),
     script(nullptr), errors(cx), overRecursed(false)
@@ -293,7 +293,7 @@ js::OffThreadParsingMustWaitForGC(JSRuntime *rt)
 
 bool
 js::StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
-                              const jschar *chars, size_t length, HandleObject scopeChain,
+                              const jschar *chars, size_t length,
                               JS::OffThreadCompileCallback callback, void *callbackData)
 {
     // Suppress GC so that calls below do not trigger a new incremental GC
@@ -351,7 +351,7 @@ js::StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &optio
 
     ScopedJSDeletePtr<ParseTask> task(
         cx->new_<ParseTask>(workercx.get(), global, cx, chars, length,
-                            scopeChain, callback, callbackData));
+                            callback, callbackData));
     if (!task)
         return false;
 
@@ -615,7 +615,7 @@ CallNewScriptHookForAllScripts(JSContext *cx, HandleScript script)
 JSScript *
 GlobalWorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token)
 {
-    ParseTask *parseTask = nullptr;
+    ScopedJSDeletePtr<ParseTask> parseTask;
 
     // The token is a ParseTask* which should be in the finished list.
     // Find and remove its entry.
@@ -635,6 +635,23 @@ GlobalWorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void
     // Mark the zone as no longer in use by an ExclusiveContext, and available
     // to be collected by the GC.
     rt->clearUsedByExclusiveThread(parseTask->cx->zone());
+    if (!maybecx) {
+        return nullptr;
+    }
+    JSContext *cx = maybecx;
+    JS_ASSERT(cx->compartment());
+
+    // Make sure we have all the constructors we need for the prototype
+    // remapping below, since we can't GC while that's happening.
+    Rooted<GlobalObject*> global(cx, &cx->global()->as<GlobalObject>());
+    if (!GlobalObject::ensureConstructor(cx, global, JSProto_Object) ||
+        !GlobalObject::ensureConstructor(cx, global, JSProto_Array) ||
+        !GlobalObject::ensureConstructor(cx, global, JSProto_Function) ||
+        !GlobalObject::ensureConstructor(cx, global, JSProto_RegExp) ||
+        !GlobalObject::ensureConstructor(cx, global, JSProto_Iterator))
+    {
+        return nullptr;
+    }
 
     // Point the prototypes of any objects in the script's compartment to refer
     // to the corresponding prototype in the new compartment. This will briefly
@@ -652,41 +669,41 @@ GlobalWorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void
         JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject());
         if (key == JSProto_Null)
             continue;
+        JS_ASSERT(key == JSProto_Object || key == JSProto_Array ||
+                  key == JSProto_Function || key == JSProto_RegExp ||
+                  key == JSProto_Iterator);
 
-        JSObject *newProto = GetBuiltinPrototypePure(&parseTask->scopeChain->global(), key);
+        JSObject *newProto = GetBuiltinPrototypePure(global, key);
         JS_ASSERT(newProto);
 
         object->setProtoUnchecked(newProto);
     }
 
     // Move the parsed script and all its contents into the desired compartment.
-    gc::MergeCompartments(parseTask->cx->compartment(), parseTask->scopeChain->compartment());
+    gc::MergeCompartments(parseTask->cx->compartment(), cx->compartment());
     parseTask->finish();
 
     RootedScript script(rt, parseTask->script);
+    assertSameCompartment(cx, script);
 
-    // If we have a context, report any error or warnings generated during the
-    // parse, and inform the debugger about the compiled scripts.
-    if (maybecx) {
-        AutoCompartment ac(maybecx, parseTask->scopeChain);
-        for (size_t i = 0; i < parseTask->errors.length(); i++)
-            parseTask->errors[i]->throwError(maybecx);
-        if (parseTask->overRecursed)
-            js_ReportOverRecursed(maybecx);
-
-        if (script) {
-            // The Debugger only needs to be told about the topmost script that was compiled.
-            GlobalObject *compileAndGoGlobal = nullptr;
-            if (script->compileAndGo())
-                compileAndGoGlobal = &script->global();
-            Debugger::onNewScript(maybecx, script, compileAndGoGlobal);
-
-            // The NewScript hook needs to be called for all compiled scripts.
-            CallNewScriptHookForAllScripts(maybecx, script);
-        }
+    // Report any error or warnings generated during the parse, and inform the
+    // debugger about the compiled scripts.
+    for (size_t i = 0; i < parseTask->errors.length(); i++)
+        parseTask->errors[i]->throwError(cx);
+    if (parseTask->overRecursed)
+        js_ReportOverRecursed(cx);
+
+    if (script) {
+        // The Debugger only needs to be told about the topmost script that was compiled.
+        GlobalObject *compileAndGoGlobal = nullptr;
+        if (script->compileAndGo())
+            compileAndGoGlobal = &script->global();
+        Debugger::onNewScript(cx, script, compileAndGoGlobal);
+
+        // The NewScript hook needs to be called for all compiled scripts.
+        CallNewScriptHookForAllScripts(cx, script);
     }
 
-    js_delete(parseTask);
     return script;
 }
 
@@ -1071,7 +1088,7 @@ js::CancelOffThreadParses(JSRuntime *rt)
 
 bool
 js::StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
-                              const jschar *chars, size_t length, HandleObject scopeChain,
+                              const jschar *chars, size_t length,
                               JS::OffThreadCompileCallback callback, void *callbackData)
 {
     MOZ_ASSUME_UNREACHABLE("Off thread compilation not available in non-THREADSAFE builds");
diff --git a/js/src/jsworkers.h b/js/src/jsworkers.h
index e33158743f2a3d7a2d84cd5d40ffb38f31f89ac7..74b6f1e7ca149f5f2f02fed86026b8164ba1b285 100644
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -300,7 +300,7 @@ CancelOffThreadParses(JSRuntime *runtime);
  */
 bool
 StartOffThreadParseScript(JSContext *cx, const ReadOnlyCompileOptions &options,
-                          const jschar *chars, size_t length, HandleObject scopeChain,
+                          const jschar *chars, size_t length,
                           JS::OffThreadCompileCallback callback, void *callbackData);
 
 /*
@@ -391,11 +391,6 @@ struct ParseTask
     size_t length;
     LifoAlloc alloc;
 
-    // Rooted pointer to the scope in the target compartment which the
-    // resulting script will be merged into. This is not safe to use off the
-    // main thread.
-    PersistentRootedObject scopeChain;
-
     // Rooted pointer to the global object used by 'cx'.
     PersistentRootedObject exclusiveContextGlobal;
 
@@ -421,8 +416,8 @@ struct ParseTask
     Vector<frontend::CompileError *> errors;
     bool overRecursed;
 
-    ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal, JSContext *initCx,
-              const jschar *chars, size_t length, JSObject *scopeChain,
+    ParseTask(ExclusiveContext *cx, JSObject *exclusiveContextGlobal,
+              JSContext *initCx, const jschar *chars, size_t length,
               JS::OffThreadCompileCallback callback, void *callbackData);
     bool init(JSContext *cx, const ReadOnlyCompileOptions &options);
 
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 0f764e9ec1af4fb1bb310455520a6f98d57d7933..c091948a318c1d4d6eb38c761bbfc0a911eee157 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3665,7 +3665,7 @@ OffThreadCompileScript(JSContext *cx, unsigned argc, jsval *vp)
         return false;
     }
 
-    if (!JS::CompileOffThread(cx, cx->global(), options, chars, length,
+    if (!JS::CompileOffThread(cx, options, chars, length,
                               OffThreadCompileScriptCallback, nullptr))
     {
         offThreadState.abandon(cx);