Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Tue, 25 Jun 2019 12:39:48 +0300
changeset 480027 207bcf72dac70e275daee08aebfbb5df0900c9d0
parent 480026 5bfd0011c6e36abf95f1b7e9bbd8fe08b46564e1 (current diff)
parent 480024 4d57aaf5c4298fc9549df0b4f5ab375839daaf8b (diff)
child 480028 6972687fbe5a50899bc3d90439a6fe71d9bd3bc8
child 480124 b592d9101222eb142e0d933e88e0f9a5bdfe1f87
push id88438
push useraciure@mozilla.com
push dateTue, 25 Jun 2019 09:42:50 +0000
treeherderautoland@6972687fbe5a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone69.0a1
first release with
nightly linux32
207bcf72dac7 / 69.0a1 / 20190625094022 / files
nightly linux64
207bcf72dac7 / 69.0a1 / 20190625094022 / files
nightly mac
207bcf72dac7 / 69.0a1 / 20190625094022 / files
nightly win32
207bcf72dac7 / 69.0a1 / 20190625094022 / files
nightly win64
207bcf72dac7 / 69.0a1 / 20190625094022 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
js/xpconnect/tests/unit/subScriptWithEarlyError.js
js/xpconnect/tests/unit/test_asyncLoadSubScriptError.js
js/xpconnect/tests/unit/test_bug1150106.js
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -131,17 +131,18 @@ function Inspector(toolbox) {
   this.onPanelWindowResize = this.onPanelWindowResize.bind(this);
   this.onShowBoxModelHighlighterForNode =
     this.onShowBoxModelHighlighterForNode.bind(this);
   this.onSidebarHidden = this.onSidebarHidden.bind(this);
   this.onSidebarResized = this.onSidebarResized.bind(this);
   this.onSidebarSelect = this.onSidebarSelect.bind(this);
   this.onSidebarShown = this.onSidebarShown.bind(this);
   this.onSidebarToggle = this.onSidebarToggle.bind(this);
-  this.handleThreadState = this.handleThreadState.bind(this);
+  this.handleThreadPaused = this.handleThreadPaused.bind(this);
+  this.handleThreadResumed = this.handleThreadResumed.bind(this);
 
   this._target.on("will-navigate", this._onBeforeNavigate);
 }
 
 Inspector.prototype = {
   /**
    * open is effectively an asynchronous constructor
    */
@@ -152,18 +153,18 @@ Inspector.prototype = {
     // When replaying, we need to listen to changes in the target's pause state.
     if (this._target.isReplayEnabled()) {
       let dbg = this._toolbox.getPanel("jsdebugger");
       if (!dbg) {
         dbg = await this._toolbox.loadTool("jsdebugger");
       }
       this._replayResumed = !dbg.isPaused();
 
-      this._target.threadClient.on("paused", this.handleThreadState);
-      this._target.threadClient.on("resumed", this.handleThreadState);
+      this._target.threadClient.on("paused", this.handleThreadPaused);
+      this._target.threadClient.on("resumed", this.handleThreadResumed);
     }
 
     await Promise.all([
       this._getCssProperties(),
       this._getPageStyle(),
       this._getDefaultSelection(),
       this._getAccessibilityFront(),
       this._getChangesFront(),
@@ -1133,20 +1134,28 @@ Inspector.prototype = {
       this.setupToolbar();
     };
     this._pendingSelection = onNodeSelected;
     this._getDefaultNodeForSelection()
         .then(onNodeSelected, this._handleRejectionIfNotDestroyed);
   },
 
   /**
-   * When replaying, reset the inspector whenever the target paused or unpauses.
+   * When replaying, reset the inspector whenever the target pauses.
    */
-  handleThreadState(packet) {
-    this._replayResumed = packet.type != "paused";
+  handleThreadPaused() {
+    this._replayResumed = false;
+    this.onNewRoot();
+  },
+
+  /**
+   * When replaying, reset the inspector whenever the target resumes.
+   */
+  handleThreadResumed() {
+    this._replayResumed = true;
     this.onNewRoot();
   },
 
   /**
    * Handler for "markuploaded" event fired on a new root mutation and after the markup
    * view is initialized. Expands the current selected node and restores the saved
    * highlighter state.
    */
@@ -1374,18 +1383,18 @@ Inspector.prototype = {
   /**
    * Destroy the inspector.
    */
   destroy: function() {
     if (this._panelDestroyer) {
       return this._panelDestroyer;
     }
 
-    this._target.threadClient.off("paused", this.handleThreadState);
-    this._target.threadClient.off("resumed", this.handleThreadState);
+    this._target.threadClient.off("paused", this.handleThreadPaused);
+    this._target.threadClient.off("resumed", this.handleThreadResumed);
 
     if (this.walker) {
       this.walker.off("new-root", this.onNewRoot);
       this.pageStyle = null;
     }
 
     this.cancelUpdate();
 
--- a/devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-05.js
+++ b/devtools/client/webreplay/mochitest/browser_dbg_rr_breakpoints-05.js
@@ -11,16 +11,18 @@
 add_task(async function() {
   const dbg = await attachRecordingDebugger(
     "doc_rr_basic.html",
     { waitForRecording: true }
   );
 
   const {threadClient, tab, toolbox, target} = dbg;
 
+  await threadClient.interrupt();
+
   // Rewind to the beginning of the recording.
   await rewindToLine(threadClient, undefined);
 
   const bp = await setBreakpoint(threadClient, "doc_rr_basic.html", 21);
   await resumeToLine(threadClient, 21);
   await checkEvaluateInTopFrame(target, "number", 1);
   await resumeToLine(threadClient, 21);
   await checkEvaluateInTopFrame(target, "number", 2);
--- a/devtools/client/webreplay/mochitest/browser_rr_inspector-01.js
+++ b/devtools/client/webreplay/mochitest/browser_rr_inspector-01.js
@@ -18,16 +18,18 @@ function getContainerForNodeFront(nodeFr
 // Test basic inspector functionality in web replay: the inspector is able to
 // show contents when paused according to the child's current position.
 add_task(async function() {
   const dbg = await attachRecordingDebugger(
     "doc_inspector_basic.html",
     { waitForRecording: true }
   );
   const {threadClient, tab, toolbox} = dbg;
+
+  await threadClient.interrupt();
   await threadClient.resume();
 
   const {inspector} = await openInspector();
 
   let nodeFront = await getNodeFront("#maindiv", inspector);
   let container = getContainerForNodeFront(nodeFront, inspector);
   ok(!container, "No node container while unpaused");
 
--- a/devtools/client/webreplay/mochitest/browser_rr_inspector-02.js
+++ b/devtools/client/webreplay/mochitest/browser_rr_inspector-02.js
@@ -12,16 +12,18 @@ Services.scriptloader.loadSubScript(
 
 // Test that the element highlighter works when paused and replaying.
 add_task(async function() {
   const dbg = await attachRecordingDebugger(
     "doc_inspector_basic.html",
     { waitForRecording: true }
   );
   const {threadClient, tab, toolbox} = dbg;
+
+  await threadClient.interrupt();
   await threadClient.resume();
 
   await threadClient.interrupt();
   const bp = await setBreakpoint(threadClient, "doc_inspector_basic.html", 9);
   await rewindToLine(threadClient, 9);
 
   const {inspector, testActor} = await openInspector();
 
--- a/devtools/client/webreplay/mochitest/browser_rr_inspector-03.js
+++ b/devtools/client/webreplay/mochitest/browser_rr_inspector-03.js
@@ -28,16 +28,18 @@ function getComputedViewProperty(view, n
 
 // Test that styles for elements can be viewed when using web replay.
 add_task(async function() {
   const dbg = await attachRecordingDebugger(
     "doc_inspector_styles.html",
     { waitForRecording: true }
   );
   const {threadClient, tab, toolbox} = dbg;
+
+  await threadClient.interrupt();
   await threadClient.resume();
 
   await threadClient.interrupt();
 
   const {inspector, view} = await openComputedView();
   await checkBackgroundColor("body", "rgb(0, 128, 0)");
   await checkBackgroundColor("#maindiv", "rgb(0, 0, 255)");
 
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -1089,29 +1089,17 @@ const ThreadActor = ActorClassWithSpec(t
 
     try {
       if (resumeLimit) {
         await this._handleResumeLimit({resumeLimit, rewind});
       } else {
         this._clearSteppingHooks();
       }
 
-      // When replaying execution in a separate process we need to explicitly
-      // notify that process when to resume execution.
-      if (this.dbg.replaying) {
-        if (resumeLimit && resumeLimit.type == "warp") {
-          this.dbg.replayTimeWarp(resumeLimit.target);
-        } else if (rewind) {
-          this.dbg.replayResumeBackward();
-        } else {
-          this.dbg.replayResumeForward();
-        }
-      }
-
-      this.doResume();
+      this.doResume({ resumeLimit, rewind });
       return {};
     } catch (error) {
       return error instanceof Error
         ? {
             error: "unknownError",
             message: DevToolsUtils.safeErrorString(error) }
         // It is a known error, and the promise was rejected with an error
         // packet.
@@ -1119,17 +1107,29 @@ const ThreadActor = ActorClassWithSpec(t
     }
   },
 
   /**
    * Only resume and notify necessary observers. This should be used in cases
    * when we do not want to notify the front end of a resume, for example when
    * we are shutting down.
    */
-  doResume() {
+  doResume({ resumeLimit, rewind } = {}) {
+    // When replaying execution in a separate process we need to explicitly
+    // notify that process when to resume execution.
+    if (this.dbg.replaying) {
+      if (resumeLimit && resumeLimit.type == "warp") {
+        this.dbg.replayTimeWarp(resumeLimit.target);
+      } else if (rewind) {
+        this.dbg.replayResumeBackward();
+      } else {
+        this.dbg.replayResumeForward();
+      }
+    }
+
     this.maybePauseOnExceptions();
     this._state = "running";
 
     // Drop the actors in the pause actor pool.
     this.conn.removeActorPool(this._pausePool);
 
     this._pausePool = null;
     this._pauseActor = null;
--- a/devtools/shared/specs/thread.js
+++ b/devtools/shared/specs/thread.js
@@ -19,16 +19,18 @@ const threadSpec = generateActorSpec({
 
   events: {
     paused: {
       actor: Option(0, "nullable:string"),
       frame: Option(0, "nullable:json"),
       why: Option(0, "nullable:json"),
       poppedFrames: Option(0, "nullable:json"),
       error: Option(0, "nullable:json"),
+      recordingEndpoint: Option(0, "nullable:json"),
+      executionPoint: Option(0, "nullable:json"),
     },
     resumed: {},
     detached: {},
     willInterrupt: {},
     newSource: {
       source: Option(0, "json"),
     },
     progress: {
--- a/js/xpconnect/idl/mozIJSSubScriptLoader.idl
+++ b/js/xpconnect/idl/mozIJSSubScriptLoader.idl
@@ -5,16 +5,21 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIURI;
 interface nsIPrincipal;
 interface nsIObserver;
 
+/**
+ * Interface for synchronous script loads from local file: or jar: sources.
+ * For asynchronous script loads, ChromeUtils.compileScript() should be used
+ * instead.
+ */
 [scriptable, builtinclass, uuid(19533e7b-f321-4ef1-bc59-6e812dc2a733)]
 interface mozIJSSubScriptLoader : nsISupports
 {
     /**
      * This method should only be called from JS!
      * In JS, the signature looks like:
      * rv loadSubScript (url [, obj] [, charset]);
      * @param url the url of the UTF-8-encoded sub-script, it MUST be either a
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -9,67 +9,59 @@
 #include "mozJSLoaderUtils.h"
 
 #include "nsIURI.h"
 #include "nsIIOService.h"
 #include "nsIChannel.h"
 #include "nsIInputStream.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
-#include "nsIFileURL.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "xpcprivate.h"                   // xpc::OptionsBase
 #include "js/CompilationAndEvaluation.h"  // JS::Compile{,ForNonSyntacticScope}DontInflate
 #include "js/SourceText.h"                // JS::Source{Ownership,Text}
 #include "js/Wrapper.h"
 
 #include "mozilla/ContentPrincipal.h"
-#include "mozilla/dom/Promise.h"
-#include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/ScriptLoader.h"
-#include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/ScriptPreloader.h"
 #include "mozilla/SystemPrincipal.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "mozilla/Unused.h"
 #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
 #include "nsContentUtils.h"
 #include "nsString.h"
-#include "nsCycleCollectionParticipant.h"
 #include "GeckoProfiler.h"
 
 using namespace mozilla::scache;
 using namespace JS;
 using namespace xpc;
 using namespace mozilla;
 using namespace mozilla::dom;
 
 class MOZ_STACK_CLASS LoadSubScriptOptions : public OptionsBase {
  public:
   explicit LoadSubScriptOptions(JSContext* cx = xpc_GetSafeJSContext(),
                                 JSObject* options = nullptr)
       : OptionsBase(cx, options),
         target(cx),
         ignoreCache(false),
-        async(false),
         wantReturnValue(false) {}
 
   virtual bool Parse() override {
     return ParseObject("target", &target) &&
            ParseBoolean("ignoreCache", &ignoreCache) &&
-           ParseBoolean("async", &async) &&
            ParseBoolean("wantReturnValue", &wantReturnValue);
   }
 
   RootedObject target;
   bool ignoreCache;
-  bool async;
   bool wantReturnValue;
 };
 
 /* load() error msgs, XXX localize? */
 #define LOAD_ERROR_NOSERVICE "Error creating IO Service."
 #define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)"
 #define LOAD_ERROR_NOSCHEME "Failed to get URI scheme.  This is bad."
 #define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI."
@@ -245,214 +237,16 @@ static bool EvalScript(JSContext* cx, Ha
       JSAutoRealm ar(cx, script);
       WriteCachedScript(StartupCache::GetSingleton(), cachePath, cx, script);
     }
   }
 
   return true;
 }
 
-class AsyncScriptLoader : public nsIIncrementalStreamLoaderObserver {
- public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
-
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AsyncScriptLoader)
-
-  AsyncScriptLoader(nsIChannel* aChannel, bool aWantReturnValue,
-                    JSObject* aTargetObj, JSObject* aLoadScope, bool aCache,
-                    Promise* aPromise)
-      : mChannel(aChannel),
-        mTargetObj(aTargetObj),
-        mLoadScope(aLoadScope),
-        mPromise(aPromise),
-        mWantReturnValue(aWantReturnValue),
-        mCache(aCache) {
-    // Needed for the cycle collector to manage mTargetObj.
-    mozilla::HoldJSObjects(this);
-  }
-
- private:
-  virtual ~AsyncScriptLoader() { mozilla::DropJSObjects(this); }
-
-  RefPtr<nsIChannel> mChannel;
-  Heap<JSObject*> mTargetObj;
-  Heap<JSObject*> mLoadScope;
-  RefPtr<Promise> mPromise;
-  bool mWantReturnValue;
-  bool mCache;
-};
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(AsyncScriptLoader)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AsyncScriptLoader)
-  NS_INTERFACE_MAP_ENTRY(nsIIncrementalStreamLoaderObserver)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AsyncScriptLoader)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
-  tmp->mTargetObj = nullptr;
-  tmp->mLoadScope = nullptr;
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AsyncScriptLoader)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(AsyncScriptLoader)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mTargetObj)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mLoadScope)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(AsyncScriptLoader)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(AsyncScriptLoader)
-
-class MOZ_STACK_CLASS AutoRejectPromise {
- public:
-  AutoRejectPromise(AutoEntryScript& aAutoEntryScript, Promise* aPromise,
-                    nsIGlobalObject* aGlobalObject)
-      : mAutoEntryScript(aAutoEntryScript),
-        mPromise(aPromise),
-        mGlobalObject(aGlobalObject) {}
-
-  ~AutoRejectPromise() {
-    if (mPromise) {
-      JSContext* cx = mAutoEntryScript.cx();
-      RootedValue rejectionValue(cx, JS::UndefinedValue());
-      if (mAutoEntryScript.HasException()) {
-        Unused << mAutoEntryScript.PeekException(&rejectionValue);
-      }
-      mPromise->MaybeReject(cx, rejectionValue);
-    }
-  }
-
-  void ResolvePromise(HandleValue aResolveValue) {
-    mPromise->MaybeResolve(aResolveValue);
-    mPromise = nullptr;
-  }
-
- private:
-  AutoEntryScript& mAutoEntryScript;
-  RefPtr<Promise> mPromise;
-  nsCOMPtr<nsIGlobalObject> mGlobalObject;
-};
-
-NS_IMETHODIMP
-AsyncScriptLoader::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
-                                     nsISupports* aContext,
-                                     uint32_t aDataLength, const uint8_t* aData,
-                                     uint32_t* aConsumedData) {
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
-                                    nsISupports* aContext, nsresult aStatus,
-                                    uint32_t aLength, const uint8_t* aBuf) {
-  nsCOMPtr<nsIURI> uri;
-  mChannel->GetURI(getter_AddRefs(uri));
-
-  nsCOMPtr<nsIGlobalObject> globalObject = xpc::NativeGlobal(mTargetObj);
-  AutoEntryScript aes(globalObject, "async loadSubScript");
-  AutoRejectPromise autoPromise(aes, mPromise, globalObject);
-  JSContext* cx = aes.cx();
-
-  if (NS_FAILED(aStatus)) {
-    ReportError(cx, "Unable to load script.", uri);
-  }
-  // Just notify that we are done with this load.
-  NS_ENSURE_SUCCESS(aStatus, NS_OK);
-
-  if (aLength == 0) {
-    ReportError(cx, LOAD_ERROR_NOCONTENT, uri);
-    return NS_OK;
-  }
-
-  if (aLength > INT32_MAX) {
-    ReportError(cx, LOAD_ERROR_CONTENTTOOBIG, uri);
-    return NS_OK;
-  }
-
-  RootedScript script(cx);
-  nsAutoCString spec;
-  nsresult rv = uri->GetSpec(spec);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  RootedObject targetObj(cx, mTargetObj);
-  RootedObject loadScope(cx, mLoadScope);
-
-  script = PrepareScript(uri, cx, JS_IsGlobalObject(targetObj), spec.get(),
-                         reinterpret_cast<const char*>(aBuf), aLength,
-                         mWantReturnValue);
-  if (!script) {
-    return NS_OK;
-  }
-
-  JS::Rooted<JS::Value> retval(cx);
-  if (EvalScript(cx, targetObj, loadScope, &retval, uri, mCache,
-                 mCache && !mWantReturnValue, &script)) {
-    autoPromise.ResolvePromise(retval);
-  }
-
-  return NS_OK;
-}
-
-nsresult mozJSSubScriptLoader::ReadScriptAsync(nsIURI* uri,
-                                               HandleObject targetObj,
-                                               HandleObject loadScope,
-                                               nsIIOService* serv,
-                                               bool wantReturnValue, bool cache,
-                                               MutableHandleValue retval) {
-  nsCOMPtr<nsIGlobalObject> globalObject = xpc::NativeGlobal(targetObj);
-  ErrorResult result;
-
-  AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(globalObject))) {
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  RefPtr<Promise> promise = Promise::Create(globalObject, result);
-  if (result.Failed()) {
-    return result.StealNSResult();
-  }
-
-  DebugOnly<bool> asJS = ToJSValue(jsapi.cx(), promise, retval);
-  MOZ_ASSERT(asJS, "Should not fail to convert the promise to a JS value");
-
-  // We create a channel and call SetContentType, to avoid expensive MIME type
-  // lookups (bug 632490).
-  nsCOMPtr<nsIChannel> channel;
-  nsresult rv;
-  rv = NS_NewChannel(getter_AddRefs(channel), uri,
-                     nsContentUtils::GetSystemPrincipal(),
-                     nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
-                     nsIContentPolicy::TYPE_OTHER,
-                     nullptr,  // nsICookieSettings
-                     nullptr,  // aPerformanceStorage
-                     nullptr,  // aLoadGroup
-                     nullptr,  // aCallbacks
-                     nsIRequest::LOAD_NORMAL, serv);
-
-  if (!NS_SUCCEEDED(rv)) {
-    return rv;
-  }
-
-  channel->SetContentType(NS_LITERAL_CSTRING("application/javascript"));
-
-  RefPtr<AsyncScriptLoader> loadObserver = new AsyncScriptLoader(
-      channel, wantReturnValue, targetObj, loadScope, cache, promise);
-
-  nsCOMPtr<nsIIncrementalStreamLoader> loader;
-  rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), loadObserver);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIStreamListener> listener = loader.get();
-  return channel->AsyncOpen(listener);
-}
-
 JSScript* mozJSSubScriptLoader::ReadScript(
     nsIURI* uri, JSContext* cx, HandleObject targetObj, const char* uriStr,
     nsIIOService* serv, bool wantReturnValue, bool useCompilationScope) {
   // We create a channel and call SetContentType, to avoid expensive MIME type
   // lookups (bug 632490).
   nsCOMPtr<nsIChannel> chan;
   nsCOMPtr<nsIInputStream> instream;
   nsresult rv;
@@ -511,17 +305,18 @@ JSScript* mozJSSubScriptLoader::ReadScri
                        len, wantReturnValue);
 }
 
 NS_IMETHODIMP
 mozJSSubScriptLoader::LoadSubScript(const nsAString& url, HandleValue target,
                                     JSContext* cx, MutableHandleValue retval) {
   /*
    * Loads a local url, referring to UTF-8-encoded data, and evals it into the
-   * current cx.  Synchronous (an async version would be cool too.)
+   * current cx.  Synchronous. ChromeUtils.compileScript() should be used for
+   * async loads.
    *   url: The url to load.  Must be local so that it can be loaded
    *        synchronously.
    *   targetObj: Optional object to eval the script onto (defaults to context
    *              global)
    *   returns: Whatever jsval the script pointed to by the url returns.
    * Should ONLY (O N L Y !) be called from JavaScript code.
    */
   LoadSubScriptOptions options(cx);
@@ -660,22 +455,16 @@ nsresult mozJSSubScriptLoader::DoLoadSub
       rv = ReadCachedScript(cache, cachePath, cx, &script);
     }
     if (NS_FAILED(rv) || !script) {
       // ReadCachedScript may have set a pending exception.
       JS_ClearPendingException(cx);
     }
   }
 
-  // If we are doing an async load, trigger it and bail out.
-  if (!script && options.async) {
-    return ReadScriptAsync(uri, targetObj, loadScope, serv,
-                           options.wantReturnValue, !!cache, retval);
-  }
-
   if (script) {
     // |script| came from the cache, so don't bother writing it
     // |back there.
     cache = nullptr;
   } else {
     script =
         ReadScript(uri, cx, targetObj, static_cast<const char*>(uriStr.get()),
                    serv, options.wantReturnValue, useCompilationScope);
deleted file mode 100644
--- a/js/xpconnect/tests/unit/subScriptWithEarlyError.js
+++ /dev/null
@@ -1,1 +0,0 @@
-var ;
deleted file mode 100644
--- a/js/xpconnect/tests/unit/test_asyncLoadSubScriptError.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var srvScope = {};
-
-function success(result) {
-  ok(false, "script should not have loaded successfully");
-  do_test_finished();
-}
-
-function error(err) {
-  ok(err instanceof SyntaxError, "loading script with early error asynchronously resulted in error");
-  do_test_finished();
-}
-
-function run_test() {
-  do_test_pending();
-
-  var file = do_get_file("subScriptWithEarlyError.js");
-  var ios = Cc["@mozilla.org/network/io-service;1"]
-              .getService(Ci.nsIIOService);
-  var uri = ios.newFileURI(file);
-  var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
-                       .getService(Ci.mozIJSSubScriptLoader);
-  var p = scriptLoader.loadSubScriptWithOptions(uri.spec,
-                                                { target: srvScope,
-                                                  async: true });
-  p.then(success, error);
-}
deleted file mode 100644
--- a/js/xpconnect/tests/unit/test_bug1150106.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-var srvScope = {};
-
-function success(result) {
-  equal(result, 42, "Result of script is correct");
-  ok('makeTags' in srvScope && srvScope.makeTags instanceof Function,
-     "makeTags is a function.");
-  do_test_finished();
-}
-
-function error() {
-  ok(false, "error loading the script asynchronously.");
-  do_test_finished();
-}
-
-function run_test() {
-  do_test_pending();
-
-  var file = do_get_file("bug451678_subscript.js");
-  var ios = Cc["@mozilla.org/network/io-service;1"]
-              .getService(Ci.nsIIOService);
-  var uri = ios.newFileURI(file);
-  var scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
-                       .getService(Ci.mozIJSSubScriptLoader);
-  var p = scriptLoader.loadSubScriptWithOptions(uri.spec,
-                                                { target: srvScope,
-                                                  async: true,
-                                                  wantReturnValue: true });
-  p.then(success, error);
-}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -13,17 +13,16 @@ support-files =
   component_import.manifest
   environment_script.js
   environment_loadscript.jsm
   environment_checkscript.jsm
   file_simple_script.js
   importer.jsm
   recursive_importA.jsm
   recursive_importB.jsm
-  subScriptWithEarlyError.js
   syntax_error.jsm
 
 [test_allowWaivers.js]
 [test_bogus_files.js]
 [test_bug408412.js]
 [test_bug451678.js]
 [test_bug604362.js]
 [test_bug677864.js]
@@ -52,17 +51,16 @@ support-files =
 [test_bug1033253.js]
 [test_bug1033920.js]
 [test_bug1033927.js]
 [test_bug1034262.js]
 [test_bug1082450.js]
 [test_bug1081990.js]
 [test_bug1110546.js]
 [test_bug1131707.js]
-[test_bug1150106.js]
 [test_bug1150771.js]
 [test_bug1151385.js]
 [test_bug1170311.js]
 [test_bug1244222.js]
 [test_bug_442086.js]
 [test_callFunctionWithAsyncStack.js]
 [test_cenums.js]
 [test_compileScript.js]
@@ -141,16 +139,15 @@ head = head_watchdog.js
 [test_xrayed_arguments.js]
 [test_xrayed_iterator.js]
 [test_xray_instanceof.js]
 [test_xray_named_element_access.js]
 [test_xray_SavedFrame.js]
 [test_xray_SavedFrame-02.js]
 [test_xray_regexp.js]
 [test_resolve_dead_promise.js]
-[test_asyncLoadSubScriptError.js]
 [test_function_names.js]
 [test_FrameScriptEnvironment.js]
 [test_SubscriptLoaderEnvironment.js]
 [test_SubscriptLoaderSandboxEnvironment.js]
 [test_SubscriptLoaderJSMEnvironment.js]
 [test_ComponentEnvironment.js]
 [test_wrapped_js_enumerator.js]
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -96,30 +96,16 @@ static gfxRect AppUnitsToFloatCSSPixels(
                                         const nsPresContext* aContext) {
   return gfxRect(nsPresContext::AppUnitsToFloatCSSPixels(aRect.x),
                  nsPresContext::AppUnitsToFloatCSSPixels(aRect.y),
                  nsPresContext::AppUnitsToFloatCSSPixels(aRect.width),
                  nsPresContext::AppUnitsToFloatCSSPixels(aRect.height));
 }
 
 /**
- * Scales a gfxRect around a given point.
- *
- * @param aRect The rectangle to scale.
- * @param aPoint The point around which to scale.
- * @param aScale The scale amount.
- */
-static void ScaleAround(gfxRect& aRect, const gfxPoint& aPoint, double aScale) {
-  aRect.x = aPoint.x - aScale * (aPoint.x - aRect.x);
-  aRect.y = aPoint.y - aScale * (aPoint.y - aRect.y);
-  aRect.width *= aScale;
-  aRect.height *= aScale;
-}
-
-/**
  * Returns whether a gfxPoint lies within a gfxRect.
  */
 static bool Inside(const gfxRect& aRect, const gfxPoint& aPoint) {
   return aPoint.x >= aRect.x && aPoint.x < aRect.XMost() &&
          aPoint.y >= aRect.y && aPoint.y < aRect.YMost();
 }
 
 /**
@@ -900,24 +886,18 @@ SVGBBox TextRenderedRun::GetRunUserSpace
   }
 
   // Convert the app units rectangle to user units.
   gfxRect fill = AppUnitsToFloatCSSPixels(
       gfxRect(fillInAppUnits.x, fillInAppUnits.y, fillInAppUnits.width,
               fillInAppUnits.height),
       aContext);
 
-  // Scale the rectangle up due to any mFontSizeScaleFactor.  We scale
-  // it around the text's origin.
-  ScaleAround(
-      fill,
-      textRun->IsVertical()
-          ? gfxPoint(nsPresContext::AppUnitsToFloatCSSPixels(baseline), 0.0)
-          : gfxPoint(0.0, nsPresContext::AppUnitsToFloatCSSPixels(baseline)),
-      1.0 / mFontSizeScaleFactor);
+  // Scale the rectangle up due to any mFontSizeScaleFactor.
+  fill.Scale(1.0 / mFontSizeScaleFactor);
 
   // Include the fill if requested.
   if (aFlags & eIncludeFill) {
     r = fill;
   }
 
   // Include the stroke if requested.
   if ((aFlags & eIncludeStroke) && !fill.IsEmpty() &&
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/svg/coordinate-systems/support/viewBox-scaling-text-001-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<head>
+  <meta charset="utf-8">
+  <title>Reference case for text scaled via SVG viewBox</title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <style>
+    body { margin: 0; }
+    svg {
+      width: 100px;
+      height: 100px;
+      background: red;
+    }
+    rect {
+      fill: lime;
+    }
+  </style>
+</head>
+<body>
+  <svg>
+    <rect height="100%" width="100%"></rect>
+  </svg>
+</body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/svg/coordinate-systems/viewBox-scaling-text-001.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<head>
+  <meta charset="utf-8">
+  <title>Testcase for text scaled via SVG viewBox</title>
+  <link rel="author" title="Daniel Holbert" href="mailto:dholbert@mozilla.com">
+  <link rel="help" href="https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute">
+  <link rel="match" href="support/viewBox-scaling-text-001-ref.html">
+  <style>
+    body { margin: 0; }
+    svg {
+      width: 100px;
+      height: 100px;
+      background: red;
+    }
+    text {
+      fill: lime;
+      font: 1px/1 Ahem;
+    }
+  </style>
+</head>
+<body>
+  <!-- We position the <text> at y=0.8px, which is the alphabetic baseline for
+       the Ahem font. This puts the bottom of the rendered square glyph at
+       y=1px, i.e. the bottom of the SVG viewport. With that, the 1px-tall Ahem
+       square 'X' character should fully fill the SVG viewport (which is then
+       scaled up from 1x1 to 100x100). -->
+  <svg viewBox="0 0 1 1">
+    <text x="0" y="0.8">X̂̂̂̂̂̂</text>
+  </svg>
+</body>