Merge mozilla-central to autoland. a=merge CLOSED TREE
authorCiure Andrei <aciure@mozilla.com>
Sat, 26 Jan 2019 11:38:54 +0200
changeset 515552 aee9ebe9b9b2432993e8a3cc1f1cf33ab4e2a240
parent 515540 8f22c3daa581e0f5c89f7ee6a8e74f6a00e3d7fd (current diff)
parent 515551 341040a5fb8064aef7dc5c520709019716ec222b (diff)
child 515558 a711808372f9d2c51f9b5b046ea62aa7a8d24c26
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
--- a/browser/base/content/test/trackingUI/browser_trackingUI_animation.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_animation.js
@@ -2,39 +2,44 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TP_PREF = "privacy.trackingprotection.enabled";
 const ANIMATIONS_PREF = "toolkit.cosmeticAnimations.enabled";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 
 // Test that the shield icon animation can be controlled by the cosmetic
 // animations pref and that one of the icons is visible in each case.
 add_task(async function testShieldAnimation() {
   await UrlClassifierTestUtils.addTestTrackers();
   Services.prefs.setBoolPref(TP_PREF, true);
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
 
   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
 
   let animationIcon = document.getElementById("tracking-protection-icon-animatable-image");
   let noAnimationIcon = document.getElementById("tracking-protection-icon");
 
   Services.prefs.setBoolPref(ANIMATIONS_PREF, true);
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.linkedBrowser.ownerGlobal)]);
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden when animations are enabled");
   ok(BrowserTestUtils.is_visible(animationIcon), "the animated icon is shown when animations are enabled");
 
   await promiseTabLoadEvent(tab, BENIGN_PAGE);
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
 
   Services.prefs.setBoolPref(ANIMATIONS_PREF, false);
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.linkedBrowser.ownerGlobal)]);
   ok(BrowserTestUtils.is_visible(noAnimationIcon), "the default icon is shown when animations are disabled");
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden when animations are disabled");
 
   gBrowser.removeCurrentTab();
   Services.prefs.clearUserPref(ANIMATIONS_PREF);
   Services.prefs.clearUserPref(TP_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
   UrlClassifierTestUtils.cleanupTestTrackers();
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_animation_2.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_animation_2.js
@@ -6,28 +6,32 @@
  */
 
 const TP_PREF = "privacy.trackingprotection.enabled";
 const TP_PB_PREF = "privacy.trackingprotection.enabled";
 const NCB_PREF = "network.cookie.cookieBehavior";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const COOKIE_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/cookiePage.html";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 
 requestLongerTimeout(2);
 
 registerCleanupFunction(function() {
   UrlClassifierTestUtils.cleanupTestTrackers();
   Services.prefs.clearUserPref(TP_PREF);
   Services.prefs.clearUserPref(TP_PB_PREF);
   Services.prefs.clearUserPref(NCB_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
   Services.prefs.clearUserPref(ContentBlocking.prefIntroCount);
 });
 
 async function testTrackingProtectionAnimation(tabbrowser) {
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
+
   info("Load a test page not containing tracking elements");
   let benignTab = await BrowserTestUtils.openNewForegroundTab(tabbrowser, BENIGN_PAGE);
   let ContentBlocking = tabbrowser.ownerGlobal.ContentBlocking;
 
   ok(!ContentBlocking.iconBox.hasAttribute("active"), "iconBox not active");
   ok(!ContentBlocking.iconBox.hasAttribute("animate"), "iconBox not animating");
 
   info("Load a test page containing tracking elements");
--- a/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js
@@ -1,22 +1,24 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test that sites added to the Tracking Protection whitelist in private
 // browsing mode don't persist once the private browsing window closes.
 
 const TP_PB_PREF = "privacy.trackingprotection.enabled";
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 var TrackingProtection = null;
 var ContentBlocking = null;
 var browser = null;
 
 registerCleanupFunction(function() {
   Services.prefs.clearUserPref(TP_PB_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
   ContentBlocking = TrackingProtection = browser = null;
   UrlClassifierTestUtils.cleanupTestTrackers();
 });
 
 function hidden(sel) {
   let win = browser.ownerGlobal;
   let el = win.document.querySelector(sel);
   let display = win.getComputedStyle(el).getPropertyValue("display", null);
@@ -74,30 +76,32 @@ function testTrackingPageUnblocked() {
   ok(hidden("#tracking-action-unblock"), "unblockButton is hidden");
 
   ok(hidden("#identity-popup-content-blocking-not-detected"), "blocking not detected label is hidden");
   ok(!hidden("#identity-popup-content-blocking-detected"), "blocking detected label is visible");
 }
 
 add_task(async function testExceptionAddition() {
   await UrlClassifierTestUtils.addTestTrackers();
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
   let privateWin = await BrowserTestUtils.openNewBrowserWindow({private: true});
   browser = privateWin.gBrowser;
   let tab = await BrowserTestUtils.openNewForegroundTab({ gBrowser: browser, waitForLoad: true, waitForStateStop: true });
 
   ContentBlocking = browser.ownerGlobal.ContentBlocking;
   ok(ContentBlocking, "CB is attached to the private window");
   TrackingProtection = browser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the private window");
 
   Services.prefs.setBoolPref(TP_PB_PREF, true);
   ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
 
   info("Load a test page containing tracking elements");
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
 
   testTrackingPage(tab.ownerGlobal);
 
   info("Disable TP for the page (which reloads the page)");
   let tabReloadPromise = promiseTabLoadEvent(tab);
   clickButton("#tracking-action-unblock");
   is(identityPopupState(), "closed", "Identity popup is closed");
 
@@ -123,22 +127,24 @@ add_task(async function testExceptionPer
   ContentBlocking = browser.ownerGlobal.ContentBlocking;
   ok(ContentBlocking, "CB is attached to the private window");
   TrackingProtection = browser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the private window");
 
   ok(TrackingProtection.enabled, "TP is still enabled");
 
   info("Load a test page containing tracking elements");
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
 
   testTrackingPage(tab.ownerGlobal);
 
   info("Disable TP for the page (which reloads the page)");
   let tabReloadPromise = promiseTabLoadEvent(tab);
   clickButton("#tracking-action-unblock");
   is(identityPopupState(), "closed", "Identity popup is closed");
 
-  await tabReloadPromise;
+  await Promise.all([tabReloadPromise,
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
   testTrackingPageUnblocked();
 
   privateWin.close();
 });
--- a/browser/base/content/test/trackingUI/browser_trackingUI_state.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_state.js
@@ -12,32 +12,34 @@
  *     2) A page with tracking elements is loaded.
  *
  * See also Bugs 1175327, 1043801, 1178985
  */
 
 const TP_PREF = "privacy.trackingprotection.enabled";
 const TP_PB_PREF = "privacy.trackingprotection.pbmode.enabled";
 const TPC_PREF = "network.cookie.cookieBehavior";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const COOKIE_PAGE = "http://not-tracking.example.com/browser/browser/base/content/test/trackingUI/cookiePage.html";
 var ContentBlocking = null;
 var TrackingProtection = null;
 var ThirdPartyCookies = null;
 var tabbrowser = null;
 var gTrackingPageURL = TRACKING_PAGE;
 
 registerCleanupFunction(function() {
   TrackingProtection = ContentBlocking =
     ThirdPartyCookies = tabbrowser = null;
   UrlClassifierTestUtils.cleanupTestTrackers();
   Services.prefs.clearUserPref(TP_PREF);
   Services.prefs.clearUserPref(TP_PB_PREF);
   Services.prefs.clearUserPref(TPC_PREF);
+  Services.prefs.clearUserPref(DTSCBN_PREF);
 });
 
 // This is a special version of "hidden" that doesn't check for item
 // visibility and just asserts the display and opacity attributes.
 // That way we can test elements even when their panel is hidden...
 function hidden(sel) {
   let win = tabbrowser.ownerGlobal;
   let el = win.document.querySelector(sel);
@@ -101,30 +103,29 @@ function areTrackersBlocked(isPrivateBro
   return blockedByTP || blockedByTPC;
 }
 
 function testTrackingPage(window) {
   info("Tracking content must be blocked");
   ok(ContentBlocking.content.hasAttribute("detected"), "trackers are detected");
   ok(!ContentBlocking.content.hasAttribute("hasException"), "content shows no exception");
 
-  let isPrivateBrowsing = PrivateBrowsingUtils.isWindowPrivate(window);
-  let blockedByTP = areTrackersBlocked(isPrivateBrowsing);
+  let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
+  let blockedByTP = areTrackersBlocked(isWindowPrivate);
   is(BrowserTestUtils.is_visible(ContentBlocking.iconBox), blockedByTP,
      "icon box is" + (blockedByTP ? "" : " not") + " visible");
   is(ContentBlocking.iconBox.hasAttribute("active"), blockedByTP,
       "shield is" + (blockedByTP ? "" : " not") + " active");
   ok(!ContentBlocking.iconBox.hasAttribute("hasException"), "icon box shows no exception");
   is(ContentBlocking.iconBox.getAttribute("tooltiptext"),
      blockedByTP ? gNavigatorBundle.getString("trackingProtection.icon.activeTooltip") : "",
      "correct tooltip");
 
   ok(hidden("#tracking-action-block"), "blockButton is hidden");
 
-  let isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
   if (isWindowPrivate) {
     ok(hidden("#tracking-action-unblock"), "unblockButton is hidden");
     is(!hidden("#tracking-action-unblock-private"), blockedByTP,
        "unblockButtonPrivate is" + (blockedByTP ? "" : " not") + " visible");
   } else {
     ok(hidden("#tracking-action-unblock-private"), "unblockButtonPrivate is hidden");
     is(!hidden("#tracking-action-unblock"), blockedByTP,
        "unblockButton is" + (blockedByTP ? "" : " not") + " visible");
@@ -213,16 +214,18 @@ async function testContentBlocking(tab) 
   clickButton("#tracking-action-block");
   await tabReloadPromise;
   testTrackingPage(tab.ownerGlobal);
 }
 
 add_task(async function testNormalBrowsing() {
   await UrlClassifierTestUtils.addTestTrackers();
 
+  Services.prefs.setBoolPref(DTSCBN_PREF, true);
+
   tabbrowser = gBrowser;
   let tab = tabbrowser.selectedTab = BrowserTestUtils.addTab(tabbrowser);
 
   ContentBlocking = gBrowser.ownerGlobal.ContentBlocking;
   ok(ContentBlocking, "CB is attached to the browser window");
   TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the browser window");
   is(TrackingProtection.enabled, Services.prefs.getBoolPref(TP_PREF),
--- a/browser/base/content/test/trackingUI/browser_trackingUI_state_all_disabled.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_state_all_disabled.js
@@ -3,50 +3,54 @@
 
 "use strict";
 
 const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
 const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html";
 const TP_PREF = "privacy.trackingprotection.enabled";
 const COOKIE_PREF = "network.cookie.cookieBehavior";
 const ANIMATIONS_PREF = "toolkit.cosmeticAnimations.enabled";
+const DTSCBN_PREF = "dom.testing.sync-content-blocking-notifications";
 
 // Check that the shield icon is always hidden when all content blocking
 // categories are turned off, even when content blocking is on.
 add_task(async function testContentBlockingAllDisabled() {
   await SpecialPowers.pushPrefEnv({set: [
     [TP_PREF, false],
     [COOKIE_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT],
+    [DTSCBN_PREF, true],
   ]});
   await UrlClassifierTestUtils.addTestTrackers();
 
   let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   Services.prefs.setBoolPref(ANIMATIONS_PREF, true);
 
   registerCleanupFunction(function() {
     gBrowser.removeCurrentTab();
     Services.prefs.clearUserPref(ANIMATIONS_PREF);
     UrlClassifierTestUtils.cleanupTestTrackers();
   });
 
   let animationIcon = document.getElementById("tracking-protection-icon-animatable-image");
   let noAnimationIcon = document.getElementById("tracking-protection-icon");
 
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
 
   await promiseTabLoadEvent(tab, BENIGN_PAGE);
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
 
   Services.prefs.setBoolPref(ANIMATIONS_PREF, false);
   await promiseTabLoadEvent(tab, TRACKING_PAGE);
   ok(BrowserTestUtils.is_hidden(animationIcon), "the animated icon is hidden");
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden");
 
   // Sanitity check that the shield is showing when at least one blocker is enabled.
   await SpecialPowers.pushPrefEnv({set: [
     [TP_PREF, true],
   ]});
-  await promiseTabLoadEvent(tab, TRACKING_PAGE);
+  await Promise.all([promiseTabLoadEvent(tab, TRACKING_PAGE),
+                     waitForContentBlockingEvent(2, tab.ownerGlobal)]);
   ok(BrowserTestUtils.is_visible(noAnimationIcon), "the default icon is shown");
 });
--- a/devtools/client/debugger/new/src/client/firefox/create.js
+++ b/devtools/client/debugger/new/src/client/firefox/create.js
@@ -21,18 +21,20 @@ export function createFrame(frame: Frame
   }
   let title;
   if (frame.type == "call") {
     const c = frame.callee;
     title = c.name || c.userDisplayName || c.displayName;
   } else {
     title = `(${frame.type})`;
   }
+
+  // NOTE: Firefox 66 switched from where.source to where.actor
   const location = {
-    sourceId: frame.where.source.actor,
+    sourceId: frame.where.source ? frame.where.source.actor : frame.where.actor,
     line: frame.where.line,
     column: frame.where.column
   };
 
   return {
     id: frame.actor,
     displayName: title,
     location,
--- a/devtools/server/actors/frame.js
+++ b/devtools/server/actors/frame.js
@@ -94,17 +94,17 @@ const FrameActor = ActorClassWithSpec(fr
       form.this = createValueGrip(this.frame.this, threadActor._pausePool,
         threadActor.objectGrip);
     }
 
     form.arguments = this._args();
     if (this.frame.script) {
       const generatedLocation = this.threadActor.sources.getFrameLocation(this.frame);
       form.where = {
-        source: generatedLocation.generatedSourceActor.form(),
+        actor: generatedLocation.generatedSourceActor.actorID,
         line: generatedLocation.generatedLine,
         column: generatedLocation.generatedColumn,
       };
     }
 
     if (!this.frame.older) {
       form.oldest = true;
     }
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -478,17 +478,17 @@ const ThreadActor = ActorClassWithSpec(t
 
       if (!generatedSourceActor) {
         // If the frame location is in a source that not pass the 'allowSource'
         // check and thus has no actor, we do not bother pausing.
         return undefined;
       }
 
       packet.frame.where = {
-        source: generatedSourceActor.form(),
+        actor: generatedSourceActor.actorID,
         line: generatedLine,
         column: generatedColumn,
       };
       const pkt = onPacket(packet);
 
       this.conn.send(pkt);
     } catch (error) {
       reportError(error);
@@ -1186,29 +1186,27 @@ const ThreadActor = ActorClassWithSpec(t
     for (; frame && (!count || i < (start + count)); i++, frame = frame.older) {
       const form = this._createFrameActor(frame).form();
       form.depth = i;
 
       let frameItem = null;
 
       const frameSourceActor = this.sources.createSourceActor(frame.script.source);
       if (frameSourceActor) {
-        const sourceForm = frameSourceActor.form();
         form.where = {
-          source: sourceForm,
+          actor: frameSourceActor.actorID,
           line: form.where.line,
           column: form.where.column,
         };
-        form.source = sourceForm;
         frameItem = form;
       }
       frames.push(frameItem);
     }
 
-    // Filter null values because sourcemapping may have failed.
+    // Filter null values because createSourceActor can be falsey
     return { frames: frames.filter(x => !!x) };
   },
 
   onReleaseMany: function(request) {
     if (!request.actors) {
       return { error: "missingParameter",
                message: "no actors were specified" };
     }
--- a/devtools/server/tests/unit/head_dbg.js
+++ b/devtools/server/tests/unit/head_dbg.js
@@ -799,29 +799,36 @@ function getSourceContent(sourceClient) 
 
 /**
  * Get a source at the specified url.
  *
  * @param ThreadClient threadClient
  * @param string url
  * @returns Promise<SourceClient>
  */
-function getSource(threadClient, url) {
-  const deferred = defer();
-  threadClient.getSources((res) => {
-    const source = res.sources.filter(function(s) {
-      return s.url === url;
-    });
-    if (source.length) {
-      deferred.resolve(threadClient.source(source[0]));
-    } else {
-      deferred.reject(new Error("source not found"));
-    }
-  });
-  return deferred.promise;
+async function getSource(threadClient, url) {
+  const {sources} = await threadClient.getSources();
+  const source = sources.find((s) => s.url === url);
+
+  if (source) {
+    return threadClient.source(source);
+  }
+
+  throw new Error("source not found");
+}
+
+async function getSourceById(threadClient, id) {
+  const { sources } = await threadClient.getSources();
+  const form = sources.find(source => source.actor == id);
+  return threadClient.source(form);
+}
+
+async function getSourceFormById(threadClient, id) {
+  const { sources } = await threadClient.getSources();
+  return sources.find(source => source.actor == id);
 }
 
 /**
  * Do a reload which clears the thread debugger
  *
  * @param TabFront tabFront
  * @returns Promise<response>
  */
--- a/devtools/server/tests/unit/test_blackboxing-01.js
+++ b/devtools/server/tests/unit/test_blackboxing-01.js
@@ -25,74 +25,82 @@ function run_test() {
   do_test_pending();
 }
 
 const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
 const SOURCE_URL = "http://example.com/source.js";
 
 const testBlackBox = async function() {
   const packet = await executeOnNextTickAndWaitForPause(evalCode, gClient);
-  const source = gThreadClient.source(packet.frame.where.source);
+  const bpSource = await getSourceById(
+    gThreadClient,
+    packet.frame.where.actor
+  );
 
-  await setBreakpoint(source, {
-    line: 2,
-  });
+  await setBreakpoint(bpSource, { line: 2 });
   await resume(gThreadClient);
 
-  const { sources } = await getSources(gThreadClient);
-  const sourceClient = gThreadClient.source(
-    sources.filter(s => s.url == BLACK_BOXED_URL)[0]
-  );
+  const sourceClient = await getSource(gThreadClient, BLACK_BOXED_URL);
 
   Assert.ok(!sourceClient.isBlackBoxed,
             "By default the source is not black boxed.");
 
   // Test that we can step into `doStuff` when we are not black boxed.
   await runTest(
-    function onSteppedLocation(location) {
-      Assert.equal(location.source.url, BLACK_BOXED_URL);
+    async function onSteppedLocation(location) {
+      const source = await getSourceFormById(gThreadClient, location.actor);
+      Assert.equal(source.url, BLACK_BOXED_URL);
       Assert.equal(location.line, 2);
     },
-    function onDebuggerStatementFrames(frames) {
-      Assert.ok(!frames.some(f => f.where.source.isBlackBoxed));
+    async function onDebuggerStatementFrames(frames) {
+      for (const frame of frames) {
+        const source = await getSourceFormById(gThreadClient, frame.where.actor);
+        Assert.ok(!source.isBlackBoxed);
+      }
     }
   );
 
   await blackBox(sourceClient);
   Assert.ok(sourceClient.isBlackBoxed);
 
   // Test that we step through `doStuff` when we are black boxed and its frame
   // doesn't show up.
   await runTest(
-    function onSteppedLocation(location) {
-      Assert.equal(location.source.url, SOURCE_URL);
+    async function onSteppedLocation(location) {
+      const source = await getSourceFormById(gThreadClient, location.actor);
+      Assert.equal(source.url, SOURCE_URL);
       Assert.equal(location.line, 4);
     },
-    function onDebuggerStatementFrames(frames) {
-      for (const f of frames) {
-        if (f.where.source.url == BLACK_BOXED_URL) {
-          Assert.ok(f.where.source.isBlackBoxed);
+    async function onDebuggerStatementFrames(frames) {
+      for (const frame of frames) {
+        const source = await getSourceFormById(gThreadClient, frame.where.actor);
+        if (source.url == BLACK_BOXED_URL) {
+          Assert.ok(source.isBlackBoxed);
         } else {
-          Assert.ok(!f.where.source.isBlackBoxed);
+          Assert.ok(!source.isBlackBoxed);
         }
       }
     }
   );
 
   await unBlackBox(sourceClient);
   Assert.ok(!sourceClient.isBlackBoxed);
 
   // Test that we can step into `doStuff` again.
   await runTest(
-    function onSteppedLocation(location) {
-      Assert.equal(location.source.url, BLACK_BOXED_URL);
+    async function onSteppedLocation(location) {
+      const source = await getSourceFormById(gThreadClient, location.actor);
+      Assert.equal(source.url, BLACK_BOXED_URL);
       Assert.equal(location.line, 2);
     },
-    function onDebuggerStatementFrames(frames) {
-      Assert.ok(!frames.some(f => f.where.source.isBlackBoxed));
+    async function onDebuggerStatementFrames(frames) {
+      for (const frame of frames) {
+        const source = await getSourceFormById(gThreadClient, frame.where.actor);
+        Assert.ok(!source.isBlackBoxed);
+      }
     }
   );
 
   finishClient(gClient);
 };
 
 function evalCode() {
   /* eslint-disable */
@@ -127,23 +135,23 @@ function evalCode() {
 const runTest = async function(onSteppedLocation, onDebuggerStatementFrames) {
   let packet = await executeOnNextTickAndWaitForPause(gDebuggee.runTest,
                                                       gClient);
   Assert.equal(packet.why.type, "breakpoint");
 
   await stepIn(gClient, gThreadClient);
 
   const location = await getCurrentLocation();
-  onSteppedLocation(location);
+  await onSteppedLocation(location);
 
   packet = await resumeAndWaitForPause(gClient, gThreadClient);
   Assert.equal(packet.why.type, "debuggerStatement");
 
   const { frames } = await getFrames(gThreadClient, 0, 100);
-  onDebuggerStatementFrames(frames);
+  await onDebuggerStatementFrames(frames);
 
   return resume(gThreadClient);
 };
 
 const getCurrentLocation = async function() {
   const response = await getFrames(gThreadClient, 0, 1);
   return response.frames[0].where;
 };
--- a/devtools/server/tests/unit/test_blackboxing-03.js
+++ b/devtools/server/tests/unit/test_blackboxing-03.js
@@ -26,24 +26,22 @@ function run_test() {
   });
   do_test_pending();
 }
 
 const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
 const SOURCE_URL = "http://example.com/source.js";
 
 function test_black_box() {
-  gClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
-    source.setBreakpoint({
-      line: 4,
-    }).then(function([response, bpClient]) {
-      gBpClient = bpClient;
-      gThreadClient.resume(test_black_box_dbg_statement);
-    });
+  gClient.addOneTimeListener("paused", async function(event, packet) {
+    const source = await getSourceById(gThreadClient, packet.frame.where.actor);
+    const [, bpClient] = await source.setBreakpoint({ line: 4 });
+    gBpClient = bpClient;
+    await gThreadClient.resume();
+    test_black_box_dbg_statement();
   });
 
   /* eslint-disable no-multi-spaces, no-undef */
   Cu.evalInSandbox(
     "" + function doStuff(k) { // line 1
       debugger;                // line 2 - Break here
       k(100);                  // line 3
     },                         // line 4
@@ -68,29 +66,27 @@ function test_black_box() {
     1
   );
   /* eslint-enable no-multi-spaces, no-undef */
 }
 
 function test_black_box_dbg_statement() {
   gThreadClient.getSources(async function({error, sources}) {
     Assert.ok(!error, "Should not get an error: " + error);
-    const sourceClient = gThreadClient.source(
-      sources.filter(s => s.url == BLACK_BOXED_URL)[0]
-    );
+    const sourceClient = await getSource(gThreadClient, BLACK_BOXED_URL);
 
     await blackBox(sourceClient);
 
-    gClient.addOneTimeListener("paused", function(event, packet) {
+    gThreadClient.addOneTimeListener("paused", async function(event, packet) {
       Assert.equal(packet.why.type, "breakpoint",
                    "We should pass over the debugger statement.");
-      gBpClient.remove(function({error}) {
-        Assert.ok(!error, "Should not get an error: " + error);
-        gThreadClient.resume(test_unblack_box_dbg_statement.bind(null, sourceClient));
-      });
+
+      await gBpClient.remove();
+      await gThreadClient.resume();
+      await test_unblack_box_dbg_statement(sourceClient);
     });
     gDebuggee.runTest();
   });
 }
 
 async function test_unblack_box_dbg_statement(sourceClient) {
   await unBlackBox(sourceClient);
 
--- a/devtools/server/tests/unit/test_blackboxing-05.js
+++ b/devtools/server/tests/unit/test_blackboxing-05.js
@@ -66,24 +66,23 @@ function test_black_box() {
     1
   );
   /* eslint-enable no-multi-spaces, no-unreachable, no-undef */
 }
 
 function test_black_box_exception() {
   gThreadClient.getSources(async function({error, sources}) {
     Assert.ok(!error, "Should not get an error: " + error);
-    const sourceClient = gThreadClient.source(
-      sources.filter(s => s.url == BLACK_BOXED_URL)[0]
-    );
-
+    const sourceClient = await getSource(gThreadClient, BLACK_BOXED_URL);
     await blackBox(sourceClient);
     gThreadClient.pauseOnExceptions(true);
 
-    gClient.addOneTimeListener("paused", function(event, packet) {
-      Assert.equal(packet.frame.where.source.url, SOURCE_URL,
+    gClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(gThreadClient, packet.frame.where.actor);
+
+      Assert.equal(source.url, SOURCE_URL,
                    "We shouldn't pause while in the black boxed source.");
       finishClient(gClient);
     });
 
     gThreadClient.resume();
   });
 }
--- a/devtools/server/tests/unit/test_breakpoint-01.js
+++ b/devtools/server/tests/unit/test_breakpoint-01.js
@@ -3,50 +3,49 @@
 /* eslint-disable no-shadow, max-nested-callbacks */
 
 "use strict";
 
 /**
  * Check basic breakpoint functionality.
  */
 
-add_task(threadClientTest(({ threadClient, debuggee }) => {
-  return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
-      const location = {
-        line: debuggee.line0 + 3,
-      };
+add_task(threadClientTest(async ({ threadClient, debuggee }) => {
+  (async () => {
+    info("Wait for the debugger statement to be hit");
+    let packet = await waitForPause(threadClient);
+    const source = await getSourceById(
+      threadClient,
+      packet.frame.where.actor
+    );
 
-      source.setBreakpoint(location).then(function([response, bpClient]) {
-        threadClient.addOneTimeListener("paused", function(event, packet) {
-          // Check the return value.
-          Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
-          Assert.equal(packet.frame.where.line, location.line);
-          Assert.equal(packet.why.type, "breakpoint");
-          Assert.equal(packet.why.actors[0], bpClient.actor);
-          // Check that the breakpoint worked.
-          Assert.equal(debuggee.a, 1);
-          Assert.equal(debuggee.b, undefined);
+    const location = { line: debuggee.line0 + 3 };
+
+    const [, bpClient] = await source.setBreakpoint(location);
+
+    await threadClient.resume();
+    packet = await waitForPause(threadClient);
 
-          // Remove the breakpoint.
-          bpClient.remove(function(response) {
-            threadClient.resume(resolve);
-          });
-        });
+    info("Paused at the breakpoint");
+    Assert.equal(packet.type, "paused");
+    Assert.equal(packet.frame.where.actor, source.actor);
+    Assert.equal(packet.frame.where.line, location.line);
+    Assert.equal(packet.why.type, "breakpoint");
+    Assert.equal(packet.why.actors[0], bpClient.actor);
 
-        // Continue until the breakpoint is hit.
-        threadClient.resume();
-      });
-    });
+    info("Check that the breakpoint worked.");
+    Assert.equal(debuggee.a, 1);
+    Assert.equal(debuggee.b, undefined);
 
-    /* eslint-disable */
-    Cu.evalInSandbox(
-      "var line0 = Error().lineNumber;\n" +
-      "debugger;\n" +   // line0 + 1
-      "var a = 1;\n" +  // line0 + 2
-      "var b = 2;\n",   // line0 + 3
-      debuggee
-    );
-    /* eslint-enable */
-  });
+    await bpClient.remove();
+    await threadClient.resume();
+  })();
+
+  /* eslint-disable */
+  Cu.evalInSandbox(
+    "var line0 = Error().lineNumber;\n" +
+    "debugger;\n" +   // line0 + 1
+    "var a = 1;\n" +  // line0 + 2
+    "var b = 2;\n",   // line0 + 3
+     debuggee
+  );
+  /* eslint-enable */
 }));
--- a/devtools/server/tests/unit/test_breakpoint-02.js
+++ b/devtools/server/tests/unit/test_breakpoint-02.js
@@ -4,29 +4,32 @@
 
 "use strict";
 
 /**
  * Check that setting breakpoints when the debuggee is running works.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
-  return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
+  return new Promise((resolve) => {
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
       const location = { line: debuggee.line0 + 3 };
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
 
       threadClient.resume();
 
       // Setting the breakpoint later should interrupt the debuggee.
       threadClient.addOneTimeListener("paused", function(event, packet) {
         Assert.equal(packet.type, "paused");
         Assert.equal(packet.why.type, "interrupted");
       });
 
-      const source = threadClient.source(packet.frame.where.source);
       source.setBreakpoint(location).then(function() {
         executeSoon(resolve);
       }, function(response) {
         // Eval scripts don't stick around long enough for the breakpoint to be set,
         // so just make sure we got the expected response from the actor.
         Assert.notEqual(response.error, "noScript");
 
         executeSoon(resolve);
--- a/devtools/server/tests/unit/test_breakpoint-03.js
+++ b/devtools/server/tests/unit/test_breakpoint-03.js
@@ -19,32 +19,34 @@ var test_no_skip_breakpoint = async func
   Assert.equal(bpClient.location.line, debuggee.line0 + 3);
   await bpClient.remove();
 };
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
     threadClient.addOneTimeListener("paused", async function(event, packet) {
       const location = { line: debuggee.line0 + 3 };
-      const source = threadClient.source(packet.frame.where.source);
-
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       // First, make sure that we can disable sliding with the
       // `noSliding` option.
       await test_no_skip_breakpoint(source, location, debuggee);
 
       // Now make sure that the breakpoint properly slides forward one line.
       const [response, bpClient] = await source.setBreakpoint(location);
       Assert.ok(!!response.actualLocation);
       Assert.equal(response.actualLocation.source.actor, source.actor);
       Assert.equal(response.actualLocation.line, location.line + 1);
 
       threadClient.addOneTimeListener("paused", function(event, packet) {
         // Check the return value.
         Assert.equal(packet.type, "paused");
-        Assert.equal(packet.frame.where.source.actor, source.actor);
+        Assert.equal(packet.frame.where.actor, source.actor);
         Assert.equal(packet.frame.where.line, location.line + 1);
         Assert.equal(packet.why.type, "breakpoint");
         Assert.equal(packet.why.actors[0], bpClient.actor);
         // Check that the breakpoint worked.
         Assert.equal(debuggee.a, 1);
         Assert.equal(debuggee.b, undefined);
 
         // Remove the breakpoint.
--- a/devtools/server/tests/unit/test_breakpoint-04.js
+++ b/devtools/server/tests/unit/test_breakpoint-04.js
@@ -5,28 +5,31 @@
 "use strict";
 
 /**
  * Check that setting a breakpoint in a line in a child script works.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 3 };
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         // actualLocation is not returned when breakpoints don't skip forward.
         Assert.equal(response.actualLocation, undefined);
 
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.actor, source.actor);
           Assert.equal(packet.frame.where.line, location.line);
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
           Assert.equal(debuggee.a, 1);
           Assert.equal(debuggee.b, undefined);
 
           // Remove the breakpoint.
--- a/devtools/server/tests/unit/test_breakpoint-05.js
+++ b/devtools/server/tests/unit/test_breakpoint-05.js
@@ -6,29 +6,32 @@
 
 /**
  * Check that setting a breakpoint in a line without code in a child script
  * will skip forward.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 3 };
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         // Check that the breakpoint has properly skipped forward one line.
         Assert.equal(response.actualLocation.source.actor, source.actor);
         Assert.equal(response.actualLocation.line, location.line + 1);
 
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.actor, source.actor);
           Assert.equal(packet.frame.where.line, location.line + 1);
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
           Assert.equal(debuggee.a, 1);
           Assert.equal(debuggee.b, undefined);
 
           // Remove the breakpoint.
--- a/devtools/server/tests/unit/test_breakpoint-06.js
+++ b/devtools/server/tests/unit/test_breakpoint-06.js
@@ -6,29 +6,32 @@
 
 /**
  * Check that setting a breakpoint in a line without code in a deeply-nested
  * child script will skip forward.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 5 };
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         // Check that the breakpoint has properly skipped forward one line.
         Assert.equal(response.actualLocation.source.actor, source.actor);
         Assert.equal(response.actualLocation.line, location.line + 1);
 
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.actor, source.actor);
           Assert.equal(packet.frame.where.line, location.line + 1);
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
           Assert.equal(debuggee.a, 1);
           Assert.equal(debuggee.b, undefined);
 
           // Remove the breakpoint.
--- a/devtools/server/tests/unit/test_breakpoint-07.js
+++ b/devtools/server/tests/unit/test_breakpoint-07.js
@@ -6,29 +6,32 @@
 
 /**
  * Check that setting a breakpoint in a line without code in the second child
  * script will skip forward.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 6 };
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         // Check that the breakpoint has properly skipped forward one line.
         Assert.equal(response.actualLocation.source.actor, source.actor);
         Assert.equal(response.actualLocation.line, location.line + 1);
 
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.actor, source.actor);
           Assert.equal(packet.frame.where.line, location.line + 1);
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
           Assert.equal(debuggee.a, 1);
           Assert.equal(debuggee.b, undefined);
 
           // Remove the breakpoint.
--- a/devtools/server/tests/unit/test_breakpoint-08.js
+++ b/devtools/server/tests/unit/test_breakpoint-08.js
@@ -8,52 +8,53 @@
  * Check that setting a breakpoint in a line without code in a child script
  * will skip forward, in a file with two scripts.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
     threadClient.addOneTimeListener("paused", function(event, packet) {
       threadClient.eval(packet.frame.actor, "foo", function(response) {
-        threadClient.addOneTimeListener("paused", function(event, packet) {
+        threadClient.addOneTimeListener("paused", async function(event, packet) {
           const obj = threadClient.pauseGrip(packet.why.frameFinished.return);
-          obj.getDefinitionSite(runWithBreakpoint);
+          const site = await obj.getDefinitionSite();
+
+          const location = { line: debuggee.line0 + 3 };
+          const source = await getSourceById(
+            threadClient,
+            site.source.actor
+          );
+
+          source.setBreakpoint(location).then(function([response, bpClient]) {
+            // Check that the breakpoint has properly skipped forward one line.
+            Assert.equal(response.actualLocation.source.actor, source.actor);
+            Assert.equal(response.actualLocation.line, location.line + 1);
+
+            threadClient.addOneTimeListener("paused", function(event, packet) {
+              // Check the return value.
+              Assert.equal(packet.type, "paused");
+              Assert.equal(packet.frame.where.actor, source.actor);
+              Assert.equal(packet.frame.where.line, location.line + 1);
+              Assert.equal(packet.why.type, "breakpoint");
+              Assert.equal(packet.why.actors[0], bpClient.actor);
+              // Check that the breakpoint worked.
+              Assert.equal(debuggee.a, 1);
+              Assert.equal(debuggee.b, undefined);
+
+              // Remove the breakpoint.
+              bpClient.remove(function(response) {
+                threadClient.resume(resolve);
+              });
+            });
+
+            // Continue until the breakpoint is hit.
+            threadClient.resume();
+          });
         });
       });
-
-      function runWithBreakpoint(packet) {
-        const source = threadClient.source(packet.source);
-        const location = { line: debuggee.line0 + 3 };
-
-        source.setBreakpoint(location).then(function([response, bpClient]) {
-          // Check that the breakpoint has properly skipped forward one line.
-          Assert.equal(response.actualLocation.source.actor, source.actor);
-          Assert.equal(response.actualLocation.line, location.line + 1);
-
-          threadClient.addOneTimeListener("paused", function(event, packet) {
-            // Check the return value.
-            Assert.equal(packet.type, "paused");
-            Assert.equal(packet.frame.where.source.actor, source.actor);
-            Assert.equal(packet.frame.where.line, location.line + 1);
-            Assert.equal(packet.why.type, "breakpoint");
-            Assert.equal(packet.why.actors[0], bpClient.actor);
-            // Check that the breakpoint worked.
-            Assert.equal(debuggee.a, 1);
-            Assert.equal(debuggee.b, undefined);
-
-            // Remove the breakpoint.
-            bpClient.remove(function(response) {
-              threadClient.resume(resolve);
-            });
-          });
-
-          // Continue until the breakpoint is hit.
-          threadClient.resume();
-        });
-      }
     });
 
     /* eslint-disable */
     Cu.evalInSandbox("var line0 = Error().lineNumber;\n" +
                      "function foo() {\n" + // line0 + 1
                      "  this.a = 1;\n" +    // line0 + 2
                      "  // A comment.\n" +  // line0 + 3
                      "  this.b = 2;\n" +    // line0 + 4
--- a/devtools/server/tests/unit/test_breakpoint-09.js
+++ b/devtools/server/tests/unit/test_breakpoint-09.js
@@ -6,25 +6,28 @@
 
 /**
  * Check that removing a breakpoint works.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
     let done = false;
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 2 };
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.actor, source.actor);
           Assert.equal(packet.frame.where.line, location.line);
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
           Assert.equal(debuggee.a, undefined);
 
           // Remove the breakpoint.
           bpClient.remove(function(response) {
--- a/devtools/server/tests/unit/test_breakpoint-10.js
+++ b/devtools/server/tests/unit/test_breakpoint-10.js
@@ -6,18 +6,21 @@
 
 /**
  * Check that setting a breakpoint in a line with multiple entry points
  * triggers no matter which entry point we reach.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 3 };
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         // actualLocation is not returned when breakpoints don't skip forward.
         Assert.equal(response.actualLocation, undefined);
 
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
--- a/devtools/server/tests/unit/test_breakpoint-11.js
+++ b/devtools/server/tests/unit/test_breakpoint-11.js
@@ -6,18 +6,21 @@
 
 /**
  * Make sure that setting a breakpoint in a line with bytecodes in multiple
  * scripts, sets the breakpoint in all of them (bug 793214).
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 2 };
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         // actualLocation is not returned when breakpoints don't skip forward.
         Assert.equal(response.actualLocation, undefined);
 
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
--- a/devtools/server/tests/unit/test_breakpoint-12.js
+++ b/devtools/server/tests/unit/test_breakpoint-12.js
@@ -10,18 +10,21 @@
  */
 
 const NUM_BREAKPOINTS = 10;
 var gBpActor;
 var gCount;
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 3};
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         // Check that the breakpoint has properly skipped forward one line.
         Assert.equal(response.actualLocation.source.actor, source.actor);
         Assert.equal(response.actualLocation.line, location.line + 1);
         gBpActor = response.actor;
 
@@ -57,17 +60,17 @@ add_task(threadClientTest(({ threadClien
           return;
         }
 
         // After setting all the breakpoints, check that only one has effectively
         // remained.
         threadClient.addOneTimeListener("paused", function(event, packet) {
           // Check the return value.
           Assert.equal(packet.type, "paused");
-          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.actor, source.actor);
           Assert.equal(packet.frame.where.line, location.line + 1);
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
           // Check that the breakpoint worked.
           Assert.equal(debuggee.a, 1);
           Assert.equal(debuggee.b, undefined);
 
           threadClient.addOneTimeListener("paused", function(event, packet) {
--- a/devtools/server/tests/unit/test_breakpoint-13.js
+++ b/devtools/server/tests/unit/test_breakpoint-13.js
@@ -6,18 +6,21 @@
 
 /**
  * Check that execution doesn't pause twice while stepping, when encountering
  * either a breakpoint or a debugger statement.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 2 };
 
       source.setBreakpoint(location).then(async function([response, bpClient]) {
         const testCallbacks = [
           function(packet) {
             // Check that the stepping worked.
             Assert.equal(packet.frame.where.line, debuggee.line0 + 5);
             Assert.equal(packet.why.type, "resumeLimit");
--- a/devtools/server/tests/unit/test_breakpoint-14.js
+++ b/devtools/server/tests/unit/test_breakpoint-14.js
@@ -6,18 +6,21 @@
 
 /**
  * Check that a breakpoint or a debugger statement cause execution to pause even
  * in a stepped-over function.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee }) => {
   return new Promise(resolve => {
-    threadClient.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    threadClient.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = { line: debuggee.line0 + 2 };
 
       source.setBreakpoint(location).then(async function([response, bpClient]) {
         const testCallbacks = [
           function(packet) {
             // Check that the stepping worked.
             Assert.equal(packet.frame.where.line, debuggee.line0 + 5);
             Assert.equal(packet.why.type, "resumeLimit");
--- a/devtools/server/tests/unit/test_breakpoint-15.js
+++ b/devtools/server/tests/unit/test_breakpoint-15.js
@@ -24,17 +24,20 @@ function run_test() {
   });
   do_test_pending();
 }
 
 const SOURCE_URL = "http://example.com/source.js";
 
 const testSameBreakpoint = async function() {
   const packet = await executeOnNextTickAndWaitForPause(evalCode, gClient);
-  const source = gThreadClient.source(packet.frame.where.source);
+  const source = await getSourceById(
+    gThreadClient,
+    packet.frame.where.actor
+  );
 
   // Whole line
   const wholeLineLocation = {
     line: 2,
   };
 
   let [, firstBpClient] = await setBreakpoint(source, wholeLineLocation);
   let [, secondBpClient] = await setBreakpoint(source, wholeLineLocation);
--- a/devtools/server/tests/unit/test_breakpoint-16.js
+++ b/devtools/server/tests/unit/test_breakpoint-16.js
@@ -6,30 +6,33 @@
 
 /**
  * Check that we can set breakpoints in columns, not just lines.
  */
 
 add_task(threadClientTest(({ threadClient, debuggee, client }) => {
   return new Promise(resolve => {
     // Debugger statement
-    client.addOneTimeListener("paused", function(event, packet) {
-      const source = threadClient.source(packet.frame.where.source);
+    client.addOneTimeListener("paused", async function(event, packet) {
+      const source = await getSourceById(
+        threadClient,
+        packet.frame.where.actor
+      );
       const location = {
         line: debuggee.line0 + 1,
         column: 55,
       };
       let timesBreakpointHit = 0;
 
       source.setBreakpoint(location).then(function([response, bpClient]) {
         threadClient.addListener("paused", function onPaused(event, packet) {
           Assert.equal(packet.type, "paused");
           Assert.equal(packet.why.type, "breakpoint");
           Assert.equal(packet.why.actors[0], bpClient.actor);
-          Assert.equal(packet.frame.where.source.actor, source.actor);
+          Assert.equal(packet.frame.where.actor, source.actor);
           Assert.equal(packet.frame.where.line, location.line);
           Assert.equal(packet.frame.where.column, location.column);
 
           Assert.equal(debuggee.acc, timesBreakpointHit);
           Assert.equal(packet.frame.environment.bindings.variables.i.value,
                        timesBreakpointHit);
 
           if (++timesBreakpointHit === 3) {
--- a/devtools/server/tests/unit/test_breakpoint-17.js
+++ b/devtools/server/tests/unit/test_breakpoint-17.js
@@ -37,19 +37,22 @@ add_task(threadClientTest(({ threadClien
       resolve();
     });
 
     Cu.evalInSandbox(code, debuggee, "1.8", "http://example.com/", 1);
   });
 }));
 
 function set_breakpoints(packet, threadClient) {
-  return new Promise(resolve => {
+  return new Promise(async resolve => {
     let first, second;
-    const source = threadClient.source(packet.frame.where.source);
+    const source = await getSourceById(
+      threadClient,
+      packet.frame.where.actor
+    );
 
     source.setBreakpoint(firstLocation).then(function([{ actualLocation },
                                                        breakpointClient]) {
       Assert.ok(!actualLocation, "Should not get an actualLocation");
       first = breakpointClient;
 
       source.setBreakpoint(secondLocation).then(function([{ actualLocation },
                                                           breakpointClient]) {
--- a/devtools/server/tests/unit/test_breakpoint-18.js
+++ b/devtools/server/tests/unit/test_breakpoint-18.js
@@ -39,18 +39,21 @@ add_task(threadClientTest(({ threadClien
       "1.8",
       "http://example.com/",
       1
     );
   });
 }));
 
 function setBreakpoint(packet, threadClient, client) {
-  return new Promise(resolve => {
-    const source = threadClient.source(packet.frame.where.source);
+  return new Promise(async resolve => {
+    const source = await getSourceById(
+      threadClient,
+      packet.frame.where.actor
+    );
     client.addOneTimeListener("resumed", resolve);
 
     source.setBreakpoint({ line: 2 }).then(() => {
       threadClient.resume();
     });
   });
 }
 
--- a/devtools/server/tests/unit/test_breakpoint-21.js
+++ b/devtools/server/tests/unit/test_breakpoint-21.js
@@ -12,30 +12,33 @@
 add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   // Populate the `ScriptStore` so that we only test that the script
   // is added through `onNewScript`
   await getSources(threadClient);
 
   let packet = await executeOnNextTickAndWaitForPause(() => {
     evalCode(debuggee);
   }, client);
-  const source = threadClient.source(packet.frame.where.source);
+  const source = await getSourceById(
+      threadClient,
+      packet.frame.where.actor
+    );
   const location = {
     line: debuggee.line0 + 8,
   };
 
   const [res, bpClient] = await setBreakpoint(source, location);
   ok(!res.error);
 
   await resume(threadClient);
   packet = await waitForPause(client);
   Assert.equal(packet.type, "paused");
   Assert.equal(packet.why.type, "breakpoint");
   Assert.equal(packet.why.actors[0], bpClient.actor);
-  Assert.equal(packet.frame.where.source.actor, source.actor);
+  Assert.equal(packet.frame.where.actor, source.actor);
   Assert.equal(packet.frame.where.line, location.line);
 
   await resume(threadClient);
 }));
 
 /* eslint-disable */
 function evalCode(debuggee) {
   // Start a new script
--- a/devtools/server/tests/unit/test_breakpoint-22.js
+++ b/devtools/server/tests/unit/test_breakpoint-22.js
@@ -11,17 +11,21 @@
 add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   // Populate the `ScriptStore` so that we only test that the script
   // is added through `onNewScript`
   await getSources(threadClient);
 
   const packet = await executeOnNextTickAndWaitForPause(() => {
     evalCode(debuggee);
   }, client);
-  const source = threadClient.source(packet.frame.where.source);
+  const source = await getSourceById(
+    threadClient,
+    packet.frame.where.actor
+  );
+
   const location = {
     line: debuggee.line0 + 2,
   };
 
   const [res ] = await setBreakpoint(source, location);
   ok(!res.error);
 
   const location2 = {
--- a/devtools/server/tests/unit/test_conditional_breakpoint-01.js
+++ b/devtools/server/tests/unit/test_conditional_breakpoint-01.js
@@ -22,18 +22,21 @@ function run_test() {
                              gThreadClient = threadClient;
                              test_simple_breakpoint();
                            });
   });
   do_test_pending();
 }
 
 function test_simple_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
+  gThreadClient.addOneTimeListener("paused", async function(event, packet) {
+    const source = await getSourceById(
+      gThreadClient,
+      packet.frame.where.actor
+    );
     source.setBreakpoint({
       line: 3,
       condition: "a === 1",
     }).then(function([response, bpClient]) {
       gThreadClient.addOneTimeListener("paused", function(event, packet) {
         // Check the return value.
         Assert.equal(packet.why.type, "breakpoint");
         Assert.equal(packet.frame.where.line, 3);
--- a/devtools/server/tests/unit/test_conditional_breakpoint-02.js
+++ b/devtools/server/tests/unit/test_conditional_breakpoint-02.js
@@ -22,18 +22,21 @@ function run_test() {
                              gThreadClient = threadClient;
                              test_simple_breakpoint();
                            });
   });
   do_test_pending();
 }
 
 function test_simple_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
+  gThreadClient.addOneTimeListener("paused", async function(event, packet) {
+    const source = await getSourceById(
+      gThreadClient,
+      packet.frame.where.actor
+    );
     source.setBreakpoint({
       line: 3,
       condition: "a === 2",
     }).then(function([response, bpClient]) {
       gThreadClient.addOneTimeListener("paused", function(event, packet) {
         // Check the return value.
         Assert.equal(packet.why.type, "debuggerStatement");
         Assert.equal(packet.frame.where.line, 4);
--- a/devtools/server/tests/unit/test_conditional_breakpoint-03.js
+++ b/devtools/server/tests/unit/test_conditional_breakpoint-03.js
@@ -22,18 +22,21 @@ function run_test() {
                              gThreadClient = threadClient;
                              test_simple_breakpoint();
                            });
   });
   do_test_pending();
 }
 
 function test_simple_breakpoint() {
-  gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    const source = gThreadClient.source(packet.frame.where.source);
+  gThreadClient.addOneTimeListener("paused", async function(event, packet) {
+    const source = await getSourceById(
+      gThreadClient,
+      packet.frame.where.actor
+    );
     source.setBreakpoint({
       line: 3,
       condition: "throw new Error()",
     }).then(function([response, bpClient]) {
       gThreadClient.addOneTimeListener("paused", function(event, packet) {
         // Check the return value.
         Assert.equal(packet.why.type, "breakpointConditionThrown");
         Assert.equal(packet.frame.where.line, 3);
--- a/devtools/server/tests/unit/test_frameactor_wasm-01.js
+++ b/devtools/server/tests/unit/test_frameactor_wasm-01.js
@@ -39,27 +39,28 @@ function run_test() {
         });
       });
   });
   do_test_pending();
 }
 
 function test_pause_frame() {
   gThreadClient.addOneTimeListener("paused", function(event, packet) {
-    gThreadClient.getFrames(0, null, function(frameResponse) {
+    gThreadClient.getFrames(0, null, async function(frameResponse) {
       Assert.equal(frameResponse.frames.length, 4);
 
       const wasmFrame = frameResponse.frames[1];
       Assert.equal(wasmFrame.type, "wasmcall");
       Assert.equal(wasmFrame.this, undefined);
 
       const location = wasmFrame.where;
+      const source = await getSourceById(gThreadClient, location.actor);
       Assert.equal(location.line > 0, true);
       Assert.equal(location.column > 0, true);
-      Assert.equal(/^wasm:(?:[^:]*:)*?[0-9a-f]{16}$/.test(location.source.url), true);
+      Assert.equal(/^wasm:(?:[^:]*:)*?[0-9a-f]{16}$/.test(source.url), true);
 
       finishClient(gClient);
     });
   });
 
   /* eslint-disable comma-spacing, max-len */
   gDebuggee.eval("(" + function() {
     // WebAssembly bytecode was generated by running:
--- a/devtools/server/tests/unit/test_setBreakpoint-at-the-beginning-of-a-line.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-at-the-beginning-of-a-line.js
@@ -23,20 +23,19 @@ add_task(threadClientTest(async ({ threa
 
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
 
   const frame = packet.frame;
-  const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
-  Assert.equal(where.line, location.line);
-  Assert.equal(where.column, 6);
+  Assert.equal(frame.where.actor, source.actor);
+  Assert.equal(frame.where.line, location.line);
+  Assert.equal(frame.where.column, 6);
 
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value.type, "undefined");
   Assert.equal(variables.b.value.type, "undefined");
   Assert.equal(variables.c.value.type, "undefined");
 
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_setBreakpoint-at-the-beginning-of-a-minified-fn.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-at-the-beginning-of-a-minified-fn.js
@@ -26,17 +26,17 @@ add_task(threadClientTest(async ({ threa
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
 
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   Assert.equal(where.column, 52);
 
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value.type, "undefined");
   Assert.equal(variables.b.value.type, "undefined");
   Assert.equal(variables.c.value.type, "undefined");
 
--- a/devtools/server/tests/unit/test_setBreakpoint-at-the-end-of-a-line.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-at-the-end-of-a-line.js
@@ -24,17 +24,17 @@ add_task(threadClientTest(async ({ threa
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
 
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   Assert.equal(where.column, 28);
 
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.b.value, 2);
   Assert.equal(variables.c.value.type, "undefined");
 
--- a/devtools/server/tests/unit/test_setBreakpoint-at-the-end-of-a-minified-fn.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-at-the-end-of-a-minified-fn.js
@@ -26,17 +26,17 @@ add_task(threadClientTest(async ({ threa
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
 
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   Assert.equal(where.column, 81);
 
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.b.value, 2);
   Assert.equal(variables.c.value, 3);
 
--- a/devtools/server/tests/unit/test_setBreakpoint-on-column-in-gcd-script.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-column-in-gcd-script.js
@@ -22,17 +22,17 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   Assert.equal(where.column, location.column);
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.b.value.type, "undefined");
   Assert.equal(variables.c.value.type, "undefined");
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_setBreakpoint-on-column.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-column.js
@@ -18,17 +18,17 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   Assert.equal(where.column, location.column);
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.b.value.type, "undefined");
   Assert.equal(variables.c.value.type, "undefined");
 
   await resume(threadClient);
--- a/devtools/server/tests/unit/test_setBreakpoint-on-line-in-gcd-script.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-line-in-gcd-script.js
@@ -22,16 +22,16 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.b.value.type, "undefined");
   Assert.equal(variables.c.value.type, "undefined");
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_setBreakpoint-on-line-with-multiple-offsets.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-line-with-multiple-offsets.js
@@ -18,30 +18,31 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   let why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   let frame = packet.frame;
   let where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   let variables = frame.environment.bindings.variables;
   Assert.equal(variables.i.value.type, "undefined");
 
-  packet = await executeOnNextTickAndWaitForPause(function() {
-    resume(threadClient);
-  }, client);
+  packet = await executeOnNextTickAndWaitForPause(
+    () => resume(threadClient),
+    client
+  );
   Assert.equal(packet.type, "paused");
   why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   frame = packet.frame;
   where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   variables = frame.environment.bindings.variables;
   Assert.equal(variables.i.value, 0);
 
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_setBreakpoint-on-line-with-multiple-statements.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-line-with-multiple-statements.js
@@ -18,17 +18,17 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value.type, "undefined");
   Assert.equal(variables.b.value.type, "undefined");
   Assert.equal(variables.c.value.type, "undefined");
 
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_setBreakpoint-on-line-with-no-offsets-in-gcd-script.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-line-with-no-offsets-in-gcd-script.js
@@ -22,16 +22,16 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, 8);
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.c.value.type, "undefined");
 
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_setBreakpoint-on-line-with-no-offsets.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-line-with-no-offsets.js
@@ -20,16 +20,16 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, actualLocation.line);
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.c.value.type, "undefined");
 
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_setBreakpoint-on-line.js
+++ b/devtools/server/tests/unit/test_setBreakpoint-on-line.js
@@ -18,17 +18,17 @@ add_task(threadClientTest(async ({ threa
   }, client);
   Assert.equal(packet.type, "paused");
   const why = packet.why;
   Assert.equal(why.type, "breakpoint");
   Assert.equal(why.actors.length, 1);
   Assert.equal(why.actors[0], breakpointClient.actor);
   const frame = packet.frame;
   const where = frame.where;
-  Assert.equal(where.source.actor, source.actor);
+  Assert.equal(where.actor, source.actor);
   Assert.equal(where.line, location.line);
   const variables = frame.environment.bindings.variables;
   Assert.equal(variables.a.value, 1);
   Assert.equal(variables.b.value.type, "undefined");
   Assert.equal(variables.c.value.type, "undefined");
 
   await resume(threadClient);
 }, { doNotRunWorker: true }));
--- a/devtools/server/tests/unit/test_stepping-08.js
+++ b/devtools/server/tests/unit/test_stepping-08.js
@@ -9,17 +9,20 @@
 
 add_task(threadClientTest(async ({ threadClient, debuggee, client }) => {
   dumpn("Evaluating test code and waiting for first debugger statement");
   const dbgStmt = await executeOnNextTickAndWaitForPause(
     () => evaluateTestCode(debuggee), client);
   equal(dbgStmt.frame.where.line, 3, "Should be at debugger statement on line 3");
 
   dumpn("Setting breakpoint in innerFunction");
-  const source = threadClient.source(dbgStmt.frame.where.source);
+  const source = await getSourceById(
+    threadClient,
+    dbgStmt.frame.where.actor
+  );
   await source.setBreakpoint({ line: 7 });
 
   dumpn("Step in to innerFunction");
   const step1 = await stepIn(client, threadClient);
   equal(step1.frame.where.line, 7);
 
   dumpn("Step out of innerFunction");
   const step2 = await stepOut(client, threadClient);
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -314,16 +314,18 @@ using mozilla::TimeStamp;
   }                                                     \
   return GetCurrentInnerWindowInternal()->method args;  \
   PR_END_MACRO
 
 static LazyLogModule gDOMLeakPRLogOuter("DOMLeakOuter");
 
 static int32_t gOpenPopupSpamCount = 0;
 
+static bool gSyncContentBlockingNotifications = false;
+
 nsGlobalWindowOuter::OuterWindowByIdTable*
     nsGlobalWindowOuter::sOuterWindowsById = nullptr;
 
 /* static */
 nsPIDOMWindowOuter* nsPIDOMWindowOuter::GetFromCurrentInner(
     nsPIDOMWindowInner* aInner) {
   if (!aInner) {
     return nullptr;
@@ -5400,110 +5402,140 @@ void nsGlobalWindowOuter::NotifyContentB
 
   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   if (!docShell) {
     return;
   }
   nsCOMPtr<Document> doc = docShell->GetDocument();
   NS_ENSURE_TRUE_VOID(doc);
 
-  // This event might come after the user has navigated to another page.
-  // To prevent showing the TrackingProtection UI on the wrong page, we need to
-  // check that the loading URI for the channel is the same as the URI currently
-  // loaded in the document.
-  if (!SameLoadingURI(doc, aChannel) &&
-      aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
-    return;
-  }
-
-  // Notify nsIWebProgressListeners of this content blocking event.
-  // Can be used to change the UI state.
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsISecurityEventSink> eventSink = do_QueryInterface(docShell, &rv);
-  NS_ENSURE_SUCCESS_VOID(rv);
-  uint32_t event = 0;
-  nsCOMPtr<nsISecureBrowserUI> securityUI;
-  docShell->GetSecurityUI(getter_AddRefs(securityUI));
-  if (!securityUI) {
+  nsCOMPtr<nsIURI> uri(aURIHint);
+  nsCOMPtr<nsIChannel> channel(aChannel);
+
+  static bool prefInitialized = false;
+  if (!prefInitialized) {
+    Preferences::AddBoolVarCache(
+        &gSyncContentBlockingNotifications,
+        "dom.testing.sync-content-blocking-notifications", false);
+    prefInitialized = true;
+  }
+
+  nsCOMPtr<nsIRunnable> func = NS_NewRunnableFunction(
+      "NotifyContentBlockingEventDelayed",
+      [doc, docShell, uri, channel, aEvent, aBlocked]() {
+        // This event might come after the user has navigated to another
+        // page. To prevent showing the TrackingProtection UI on the wrong
+        // page, we need to check that the loading URI for the channel is
+        // the same as the URI currently loaded in the document.
+        if (!SameLoadingURI(doc, channel) &&
+            aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
+          return;
+        }
+
+        // Notify nsIWebProgressListeners of this content blocking event.
+        // Can be used to change the UI state.
+        nsresult rv = NS_OK;
+        nsCOMPtr<nsISecurityEventSink> eventSink =
+            do_QueryInterface(docShell, &rv);
+        NS_ENSURE_SUCCESS_VOID(rv);
+        uint32_t event = 0;
+        nsCOMPtr<nsISecureBrowserUI> securityUI;
+        docShell->GetSecurityUI(getter_AddRefs(securityUI));
+        if (!securityUI) {
+          return;
+        }
+        securityUI->GetContentBlockingEvent(&event);
+        nsAutoCString origin;
+        nsContentUtils::GetASCIIOrigin(uri, origin);
+
+        bool blockedValue = aBlocked;
+        bool unblocked = false;
+        if (aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
+          doc->SetHasTrackingContentBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasTrackingContentBlocked();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
+          doc->SetHasTrackingContentLoaded(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasTrackingContentLoaded();
+          }
+        } else if (aEvent == nsIWebProgressListener::
+                                 STATE_COOKIES_BLOCKED_BY_PERMISSION) {
+          doc->SetHasCookiesBlockedByPermission(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasCookiesBlockedByPermission();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) {
+          doc->SetHasTrackingCookiesBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasTrackingCookiesBlocked();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) {
+          doc->SetHasAllCookiesBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasAllCookiesBlocked();
+          }
+        } else if (aEvent ==
+                   nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
+          doc->SetHasForeignCookiesBlocked(aBlocked, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasForeignCookiesBlocked();
+          }
+        } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_LOADED) {
+          MOZ_ASSERT(!aBlocked,
+                     "We don't expected to see blocked STATE_COOKIES_LOADED");
+          // Note that the logic in this branch is the logical negation of
+          // the logic in other branches, since the Document API we have is
+          // phrased in "loaded" terms as opposed to "blocked" terms.
+          blockedValue = !aBlocked;
+          doc->SetHasCookiesLoaded(blockedValue, origin);
+          if (!aBlocked) {
+            unblocked = !doc->GetHasCookiesLoaded();
+          }
+        } else {
+          // Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
+        }
+        const uint32_t oldEvent = event;
+        if (blockedValue) {
+          event |= aEvent;
+        } else if (unblocked) {
+          event &= ~aEvent;
+        }
+
+        if (event == oldEvent
+#ifdef ANDROID
+            // GeckoView always needs to notify about blocked trackers,
+            // since the GeckoView API always needs to report the URI and
+            // type of any blocked tracker. We use a platform-dependent code
+            // path here because reporting this notification on desktop
+            // platforms isn't necessary and doing so can have a big
+            // performance cost.
+            && aEvent != nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT
+#endif
+        ) {
+          // Avoid dispatching repeated notifications when nothing has
+          // changed
+          return;
+        }
+
+        eventSink->OnContentBlockingEvent(channel, event);
+      });
+  nsresult rv;
+  if (gSyncContentBlockingNotifications) {
+    rv = func->Run();
+  } else {
+    rv = NS_IdleDispatchToCurrentThread(func.forget(), 100);
+  }
+  if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
-  securityUI->GetContentBlockingEvent(&event);
-  nsAutoCString origin;
-  nsContentUtils::GetASCIIOrigin(aURIHint, origin);
-
-  bool blockedValue = aBlocked;
-  bool unblocked = false;
-  if (aEvent == nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT) {
-    doc->SetHasTrackingContentBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasTrackingContentBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
-    doc->SetHasTrackingContentLoaded(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasTrackingContentLoaded();
-    }
-  } else if (aEvent ==
-             nsIWebProgressListener::STATE_COOKIES_BLOCKED_BY_PERMISSION) {
-    doc->SetHasCookiesBlockedByPermission(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasCookiesBlockedByPermission();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_TRACKER) {
-    doc->SetHasTrackingCookiesBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasTrackingCookiesBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_ALL) {
-    doc->SetHasAllCookiesBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasAllCookiesBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
-    doc->SetHasForeignCookiesBlocked(aBlocked, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasForeignCookiesBlocked();
-    }
-  } else if (aEvent == nsIWebProgressListener::STATE_COOKIES_LOADED) {
-    MOZ_ASSERT(!aBlocked,
-               "We don't expected to see blocked STATE_COOKIES_LOADED");
-    // Note that the logic in this branch is the logical negation of the logic
-    // in other branches, since the Document API we have is phrased in
-    // "loaded" terms as opposed to "blocked" terms.
-    blockedValue = !aBlocked;
-    doc->SetHasCookiesLoaded(blockedValue, origin);
-    if (!aBlocked) {
-      unblocked = !doc->GetHasCookiesLoaded();
-    }
-  } else {
-    // Ignore nsIWebProgressListener::STATE_BLOCKED_UNSAFE_CONTENT;
-  }
-  const uint32_t oldEvent = event;
-  if (blockedValue) {
-    event |= aEvent;
-  } else if (unblocked) {
-    event &= ~aEvent;
-  }
-
-  if (event == oldEvent
-#ifdef ANDROID
-      // GeckoView always needs to notify about blocked trackers, since the
-      // GeckoView API always needs to report the URI and type of any blocked
-      // tracker.
-      // We use a platform-dependent code path here because reporting this
-      // notification on desktop platforms isn't necessary and doing so can have
-      // a big performance cost.
-      && aEvent != nsIWebProgressListener::STATE_BLOCKED_TRACKING_CONTENT
-#endif
-  ) {
-    // Avoid dispatching repeated notifications when nothing has changed
-    return;
-  }
-
-  eventSink->OnContentBlockingEvent(aChannel, event);
 }
 
 // static
 bool nsGlobalWindowOuter::SameLoadingURI(Document* aDoc, nsIChannel* aChannel) {
   nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
   nsCOMPtr<nsILoadInfo> channelLoadInfo = aChannel->GetLoadInfo();
   if (!channelLoadInfo || !docURI) {
     return false;
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -18,16 +18,17 @@
 
 #include "wasm/AsmJS.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Compression.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/ScopeExit.h"
+#include "mozilla/Sprintf.h"  // SprintfLiteral
 #include "mozilla/Unused.h"
 #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
 #include "mozilla/Variant.h"
 
 #include <new>
 
 #include "jsmath.h"
 #include "jsutil.h"
--- a/netwerk/base/nsIURIMutator.idl
+++ b/netwerk/base/nsIURIMutator.idl
@@ -329,17 +329,17 @@ NS_MutatorMethod(Method aMethod, Args ..
 {
   // Capture arguments by value, otherwise we crash.
   return [=](nsIURIMutator* aMutator) {
     typedef typename nsMethodTypeTraits<Method>::class_type Interface;
     nsresult rv;
     nsCOMPtr<Interface> target = do_QueryInterface(aMutator, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = (target->*aMethod)(aArgs...);
-    NS_ENSURE_SUCCESS(rv, rv);
+    if (NS_FAILED(rv)) return rv;
     return NS_OK;
   };
 }
 
 // This class provides a useful helper that allows chaining of setter operations
 class MOZ_STACK_CLASS NS_MutateURI
 {
 public:
@@ -488,17 +488,16 @@ public:
    * types, or the number of arguments, then there will be a compile error.
    */
   NS_MutateURI& Apply(const std::function<nsresult(nsIURIMutator*)>& aFunction)
   {
     if (NS_FAILED(mStatus)) {
       return *this;
     }
     mStatus = aFunction(mMutator);
-    NS_ENSURE_SUCCESS(mStatus, *this);
     return *this;
   }
 
   template <class C>
   MOZ_MUST_USE nsresult Finalize(nsCOMPtr<C>& aURI)
   {
     NS_ENSURE_SUCCESS(mStatus, mStatus);
 
@@ -538,17 +537,17 @@ public:
 
     result.forget(aURI);
     mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
     return NS_OK;
   }
 
   MOZ_MUST_USE nsresult Finalize(nsIURI** aURI)
   {
-    NS_ENSURE_SUCCESS(mStatus, mStatus);
+    if (NS_FAILED(mStatus)) return mStatus;
     mStatus = mMutator->Finalize(aURI);
     NS_ENSURE_SUCCESS(mStatus, mStatus);
 
     mStatus = NS_ERROR_NOT_AVAILABLE; // Second call to Finalize should fail.
     return NS_OK;
   }
 
   nsresult GetStatus() { return mStatus; }
new file mode 100644
--- /dev/null
+++ b/security/nss/.arcconfig
@@ -0,0 +1,5 @@
+{
+  "phabricator.uri" : "https://phabricator.services.mozilla.com/",
+  "repository.callsign": "NSS",
+  "history.immutable": false
+}
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_42_BETA1
+NSS_3_42_BETA2
--- a/security/nss/build.sh
+++ b/security/nss/build.sh
@@ -45,16 +45,17 @@ clean=0
 rebuild_gyp=0
 rebuild_nspr=0
 target=Debug
 verbose=0
 fuzz=0
 fuzz_tls=0
 fuzz_oss=0
 no_local_nspr=0
+sslkeylogfile=1
 
 gyp_params=(--depth="$cwd" --generator-output=".")
 ninja_params=()
 
 # Assume that the target architecture is the same as the host by default.
 host_arch=$(python "$cwd"/coreconf/detect_host_arch.py)
 target_arch=$host_arch
 
@@ -98,29 +99,32 @@ while [ $# -gt 0 ]; do
         --ct-verif) gyp_params+=(-Dct_verif=1) ;;
         --nspr) nspr_clean; rebuild_nspr=1 ;;
         --with-nspr=?*) set_nspr_path "${1#*=}"; no_local_nspr=1 ;;
         --system-nspr) set_nspr_path "/usr/include/nspr/:"; no_local_nspr=1 ;;
         --system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;;
         --enable-fips) gyp_params+=(-Ddisable_fips=0) ;;
         --enable-libpkix) gyp_params+=(-Ddisable_libpkix=0) ;;
         --mozpkix-only) gyp_params+=(-Dmozpkix_only=1 -Ddisable_tests=1 -Dsign_libs=0) ;;
+        --disable-keylog) sslkeylogfile=0 ;;
         *) show_help; exit 2 ;;
     esac
     shift
 done
 
 # Set the target architecture and build type.
 gyp_params+=(-Dtarget_arch="$target_arch")
 if [ "$opt_build" = 1 ]; then
     target=Release
 else
     target=Debug
 fi
 
+gyp_params+=(-Denable_sslkeylogfile="$sslkeylogfile")
+
 # Do special setup.
 if [ "$fuzz" = 1 ]; then
     source "$cwd"/coreconf/fuzz.sh
 fi
 nspr_set_flags $sanitizer_flags
 if [ ! -z "$sanitizer_flags" ]; then
     gyp_params+=(-Dsanitizer_flags="$sanitizer_flags")
 fi
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/security/nss/gtests/ssl_gtest/Makefile
+++ b/security/nss/gtests/ssl_gtest/Makefile
@@ -31,16 +31,22 @@ CFLAGS += -I$(CORE_DEPTH)/lib/ssl
 
 ifdef NSS_DISABLE_TLS_1_3
 NSS_DISABLE_TLS_1_3=1
 # Run parameterized tests only, for which we can easily exclude TLS 1.3
 CPPSRCS := $(filter-out $(shell grep -l '^TEST_F' $(CPPSRCS)), $(CPPSRCS))
 CFLAGS += -DNSS_DISABLE_TLS_1_3
 endif
 
+ifdef NSS_ALLOW_SSLKEYLOGFILE
+SSLKEYLOGFILE_FILES = ssl_keylog_unittest.cc
+else
+SSLKEYLOGFILE_FILES = $(NULL)
+endif
+
 #######################################################################
 # (5) Execute "global" rules. (OPTIONAL)                              #
 #######################################################################
 
 include $(CORE_DEPTH)/coreconf/rules.mk
 
 #######################################################################
 # (6) Execute "component" rules. (OPTIONAL)                           #
--- a/security/nss/gtests/ssl_gtest/manifest.mn
+++ b/security/nss/gtests/ssl_gtest/manifest.mn
@@ -15,28 +15,28 @@ CPPSRCS = \
       bloomfilter_unittest.cc \
       ssl_0rtt_unittest.cc \
       ssl_agent_unittest.cc \
       ssl_auth_unittest.cc \
       ssl_cert_ext_unittest.cc \
       ssl_ciphersuite_unittest.cc \
       ssl_custext_unittest.cc \
       ssl_damage_unittest.cc \
+      ssl_debug_env_unittest.cc \
       ssl_dhe_unittest.cc \
       ssl_drop_unittest.cc \
       ssl_ecdh_unittest.cc \
       ssl_ems_unittest.cc \
       ssl_exporter_unittest.cc \
       ssl_extension_unittest.cc \
       ssl_fragment_unittest.cc \
       ssl_fuzz_unittest.cc \
       ssl_gather_unittest.cc \
       ssl_gtest.cc \
       ssl_hrr_unittest.cc \
-      ssl_keylog_unittest.cc \
       ssl_keyupdate_unittest.cc \
       ssl_loopback_unittest.cc \
       ssl_misc_unittest.cc \
       ssl_record_unittest.cc \
       ssl_recordsize_unittest.cc \
       ssl_resumption_unittest.cc \
       ssl_renegotiation_unittest.cc \
       ssl_skip_unittest.cc \
@@ -48,16 +48,17 @@ CPPSRCS = \
       selfencrypt_unittest.cc \
       test_io.cc \
       tls_agent.cc \
       tls_connect.cc \
       tls_hkdf_unittest.cc \
       tls_filter.cc \
       tls_protect.cc \
       tls_esni_unittest.cc \
+      $(SSLKEYLOGFILE_FILES) \
       $(NULL)
 
 INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
             -I$(CORE_DEPTH)/gtests/common \
             -I$(CORE_DEPTH)/cpputil
 
 REQUIRES = nspr nss libdbm gtest cpputil
 
new file mode 100644
--- /dev/null
+++ b/security/nss/gtests/ssl_gtest/ssl_debug_env_unittest.cc
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include <cstdlib>
+#include <fstream>
+#include <sstream>
+
+#include "gtest_utils.h"
+#include "tls_connect.h"
+
+namespace nss_test {
+
+extern "C" {
+extern FILE* ssl_trace_iob;
+
+#ifdef NSS_ALLOW_SSLKEYLOGFILE
+extern FILE* ssl_keylog_iob;
+#endif
+}
+
+// These tests ensure that when the associated environment variables are unset
+// that the lazily-initialized defaults are what they are supposed to be.
+
+#ifdef DEBUG
+TEST_P(TlsConnectGeneric, DebugEnvTraceFileNotSet) {
+  char* ev = PR_GetEnvSecure("SSLDEBUGFILE");
+  if (ev && ev[0]) {
+    // note: should use GTEST_SKIP when GTest gets updated to support it
+    return;
+  }
+
+  Connect();
+  EXPECT_EQ(stderr, ssl_trace_iob);
+}
+#endif
+
+#ifdef NSS_ALLOW_SSLKEYLOGFILE
+TEST_P(TlsConnectGeneric, DebugEnvKeylogFileNotSet) {
+  char* ev = PR_GetEnvSecure("SSLKEYLOGFILE");
+  if (ev && ev[0]) {
+    // note: should use GTEST_SKIP when GTest gets updated to support it
+    return;
+  }
+
+  Connect();
+  EXPECT_EQ(nullptr, ssl_keylog_iob);
+}
+#endif
+
+}  // namespace nss_test
--- a/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/security/nss/gtests/ssl_gtest/ssl_gtest.gyp
@@ -16,28 +16,28 @@
         'selfencrypt_unittest.cc',
         'ssl_0rtt_unittest.cc',
         'ssl_agent_unittest.cc',
         'ssl_auth_unittest.cc',
         'ssl_cert_ext_unittest.cc',
         'ssl_ciphersuite_unittest.cc',
         'ssl_custext_unittest.cc',
         'ssl_damage_unittest.cc',
+        'ssl_debug_env_unittest.cc',
         'ssl_dhe_unittest.cc',
         'ssl_drop_unittest.cc',
         'ssl_ecdh_unittest.cc',
         'ssl_ems_unittest.cc',
         'ssl_exporter_unittest.cc',
         'ssl_extension_unittest.cc',
         'ssl_fuzz_unittest.cc',
         'ssl_fragment_unittest.cc',
         'ssl_gather_unittest.cc',
         'ssl_gtest.cc',
         'ssl_hrr_unittest.cc',
-        'ssl_keylog_unittest.cc',
         'ssl_keyupdate_unittest.cc',
         'ssl_loopback_unittest.cc',
         'ssl_misc_unittest.cc',
         'ssl_record_unittest.cc',
         'ssl_recordsize_unittest.cc',
         'ssl_resumption_unittest.cc',
         'ssl_renegotiation_unittest.cc',
         'ssl_skip_unittest.cc',
@@ -86,23 +86,31 @@
             '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
           ],
         }],
         [ 'disable_dbm==0', {
           'dependencies': [
             '<(DEPTH)/lib/dbm/src/src.gyp:dbm',
           ],
         }],
+        [ 'enable_sslkeylogfile==1', {
+          'sources': [
+            'ssl_keylog_unittest.cc',
+          ],
+          'defines': [
+            'NSS_ALLOW_SSLKEYLOGFILE',
+          ],
+        }],
       ],
     }
   ],
   'target_defaults': {
     'include_dirs': [
       '../../lib/ssl'
     ],
     'defines': [
-      'NSS_USE_STATIC_LIBS'
+      'NSS_USE_STATIC_LIBS',
     ],
   },
   'variables': {
     'module': 'nss',
   }
 }
--- a/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
+++ b/security/nss/gtests/ssl_gtest/ssl_keylog_unittest.cc
@@ -1,39 +1,76 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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/. */
 
-#ifdef NSS_ALLOW_SSLKEYLOGFILE
-
 #include <cstdlib>
 #include <fstream>
 #include <sstream>
 
 #include "gtest_utils.h"
 #include "tls_connect.h"
 
 namespace nss_test {
 
-static const std::string keylog_file_path = "keylog.txt";
-static const std::string keylog_env = "SSLKEYLOGFILE=" + keylog_file_path;
+static const std::string kKeylogFilePath = "keylog.txt";
+static const std::string kKeylogBlankEnv = "SSLKEYLOGFILE=";
+static const std::string kKeylogSetEnv = kKeylogBlankEnv + kKeylogFilePath;
+
+extern "C" {
+extern FILE* ssl_keylog_iob;
+}
 
-class KeyLogFileTest : public TlsConnectGeneric {
+class KeyLogFileTestBase : public TlsConnectGeneric {
+ private:
+  std::string env_to_set_;
+
  public:
+  virtual void CheckKeyLog() = 0;
+
+  KeyLogFileTestBase(std::string env) : env_to_set_(env) {}
+
   void SetUp() override {
     TlsConnectGeneric::SetUp();
     // Remove previous results (if any).
-    (void)remove(keylog_file_path.c_str());
-    PR_SetEnv(keylog_env.c_str());
+    (void)remove(kKeylogFilePath.c_str());
+    PR_SetEnv(env_to_set_.c_str());
   }
 
-  void CheckKeyLog() {
-    std::ifstream f(keylog_file_path);
+  void ConnectAndCheck() {
+    // This is a child process, ensure that error messages immediately
+    // propagate or else it will not be visible.
+    ::testing::GTEST_FLAG(throw_on_failure) = true;
+
+    if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
+      SetupForZeroRtt();
+      client_->Set0RttEnabled(true);
+      server_->Set0RttEnabled(true);
+      ExpectResumption(RESUME_TICKET);
+      ZeroRttSendReceive(true, true);
+      Handshake();
+      ExpectEarlyDataAccepted(true);
+      CheckConnected();
+      SendReceive();
+    } else {
+      Connect();
+    }
+    CheckKeyLog();
+    _exit(0);
+  }
+};
+
+class KeyLogFileTest : public KeyLogFileTestBase {
+ public:
+  KeyLogFileTest() : KeyLogFileTestBase(kKeylogSetEnv) {}
+
+  void CheckKeyLog() override {
+    std::ifstream f(kKeylogFilePath);
     std::map<std::string, size_t> labels;
     std::set<std::string> client_randoms;
     for (std::string line; std::getline(f, line);) {
       if (line[0] == '#') {
         continue;
       }
 
       std::istringstream iss(line);
@@ -60,38 +97,16 @@ class KeyLogFileTest : public TlsConnect
       ASSERT_EQ(2U, labels["EARLY_EXPORTER_SECRET"]);
       ASSERT_EQ(4U, labels["CLIENT_HANDSHAKE_TRAFFIC_SECRET"]);
       ASSERT_EQ(4U, labels["SERVER_HANDSHAKE_TRAFFIC_SECRET"]);
       ASSERT_EQ(4U, labels["CLIENT_TRAFFIC_SECRET_0"]);
       ASSERT_EQ(4U, labels["SERVER_TRAFFIC_SECRET_0"]);
       ASSERT_EQ(4U, labels["EXPORTER_SECRET"]);
     }
   }
-
-  void ConnectAndCheck() {
-    // This is a child process, ensure that error messages immediately
-    // propagate or else it will not be visible.
-    ::testing::GTEST_FLAG(throw_on_failure) = true;
-
-    if (version_ == SSL_LIBRARY_VERSION_TLS_1_3) {
-      SetupForZeroRtt();
-      client_->Set0RttEnabled(true);
-      server_->Set0RttEnabled(true);
-      ExpectResumption(RESUME_TICKET);
-      ZeroRttSendReceive(true, true);
-      Handshake();
-      ExpectEarlyDataAccepted(true);
-      CheckConnected();
-      SendReceive();
-    } else {
-      Connect();
-    }
-    CheckKeyLog();
-    _exit(0);
-  }
 };
 
 // Tests are run in a separate process to ensure that NSS is not initialized yet
 // and can process the SSLKEYLOGFILE environment variable.
 
 TEST_P(KeyLogFileTest, KeyLogFile) {
   testing::GTEST_FLAG(death_test_style) = "threadsafe";
 
@@ -108,11 +123,42 @@ INSTANTIATE_TEST_CASE_P(
                        TlsConnectTestBase::kTlsV10ToV12));
 #ifndef NSS_DISABLE_TLS_1_3
 INSTANTIATE_TEST_CASE_P(
     KeyLogFileTLS13, KeyLogFileTest,
     ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
                        TlsConnectTestBase::kTlsV13));
 #endif
 
-}  // namespace nss_test
+class KeyLogFileUnsetTest : public KeyLogFileTestBase {
+ public:
+  KeyLogFileUnsetTest() : KeyLogFileTestBase(kKeylogBlankEnv) {}
+
+  void CheckKeyLog() override {
+    std::ifstream f(kKeylogFilePath);
+    EXPECT_FALSE(f.good());
+
+    EXPECT_EQ(nullptr, ssl_keylog_iob);
+  }
+};
+
+TEST_P(KeyLogFileUnsetTest, KeyLogFile) {
+  testing::GTEST_FLAG(death_test_style) = "threadsafe";
 
-#endif  // NSS_ALLOW_SSLKEYLOGFILE
+  ASSERT_EXIT(ConnectAndCheck(), ::testing::ExitedWithCode(0), "");
+}
+
+INSTANTIATE_TEST_CASE_P(
+    KeyLogFileDTLS12, KeyLogFileUnsetTest,
+    ::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
+                       TlsConnectTestBase::kTlsV11V12));
+INSTANTIATE_TEST_CASE_P(
+    KeyLogFileTLS12, KeyLogFileUnsetTest,
+    ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+                       TlsConnectTestBase::kTlsV10ToV12));
+#ifndef NSS_DISABLE_TLS_1_3
+INSTANTIATE_TEST_CASE_P(
+    KeyLogFileTLS13, KeyLogFileUnsetTest,
+    ::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
+                       TlsConnectTestBase::kTlsV13));
+#endif
+
+}  // namespace nss_test
--- a/security/nss/help.txt
+++ b/security/nss/help.txt
@@ -46,8 +46,10 @@ NSS build tool options:
                      --with-nspr=<include>:<lib> sets include and lib paths
     --system-nspr    attempt to use system nspr
                      shorthand for --with-nspr=/usr/include/nspr:
     --system-sqlite  use system sqlite
     --enable-fips    enable FIPS checks
     --enable-libpkix make libpkix part of the build
     --mozpkix-only   build only static mozpkix and mozpkix-test libraries
                      support for this build option is limited
+    --disable-keylog enable support for logging key data to a file specified
+                     by the SSLKEYLOGFILE environment variable
--- a/security/nss/lib/ssl/ssl.gyp
+++ b/security/nss/lib/ssl/ssl.gyp
@@ -68,16 +68,21 @@
             'UNSAFE_FUZZER_MODE',
           ],
         }],
         [ 'OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd" or OS=="linux"', {
           'cflags': [
             '-std=gnu99',
           ],
         }],
+        [ 'enable_sslkeylogfile==1', {
+          'defines': [
+            'NSS_ALLOW_SSLKEYLOGFILE',
+          ],
+        }],
       ],
       'dependencies': [
         '<(DEPTH)/exports.gyp:nss_exports',
       ],
     },
     {
       'target_name': 'ssl3',
       'type': 'shared_library',
@@ -87,17 +92,12 @@
         '<(DEPTH)/lib/util/util.gyp:nssutil3',
         '<(DEPTH)/lib/freebl/freebl.gyp:freebl',
       ],
       'variables': {
         'mapfile': 'ssl.def'
       }
     }
   ],
-  'target_defaults': {
-    'defines': [
-      'NSS_ALLOW_SSLKEYLOGFILE=1'
-    ]
-  },
   'variables': {
     'module': 'nss'
   }
 }
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -3639,16 +3639,17 @@ ssl_SetDefaultsFromEnvironment(void)
 {
 #if defined(NSS_HAVE_GETENV)
     static int firsttime = 1;
 
     if (firsttime) {
         char *ev;
         firsttime = 0;
 #ifdef DEBUG
+        ssl_trace_iob = NULL;
         ev = PR_GetEnvSecure("SSLDEBUGFILE");
         if (ev && ev[0]) {
             ssl_trace_iob = fopen(ev, "w");
         }
         if (!ssl_trace_iob) {
             ssl_trace_iob = stderr;
         }
 #ifdef TRACE
@@ -3660,16 +3661,17 @@ ssl_SetDefaultsFromEnvironment(void)
 #endif /* TRACE */
         ev = PR_GetEnvSecure("SSLDEBUG");
         if (ev && ev[0]) {
             ssl_debug = atoi(ev);
             SSL_TRACE(("SSL: debugging set to %d", ssl_debug));
         }
 #endif /* DEBUG */
 #ifdef NSS_ALLOW_SSLKEYLOGFILE
+        ssl_keylog_iob = NULL;
         ev = PR_GetEnvSecure("SSLKEYLOGFILE");
         if (ev && ev[0]) {
             ssl_keylog_iob = fopen(ev, "a");
             if (!ssl_keylog_iob) {
                 SSL_TRACE(("SSL: failed to open key log file"));
             } else {
                 if (ftell(ssl_keylog_iob) == 0) {
                     fputs("# SSL/TLS secrets log file, generated by NSS\n",
--- a/toolkit/components/antitracking/AntiTrackingCommon.cpp
+++ b/toolkit/components/antitracking/AntiTrackingCommon.cpp
@@ -325,22 +325,16 @@ void ReportBlockingToConsole(nsPIDOMWind
             nsCOMPtr<nsIURIFixup> urifixup = services::GetURIFixup();
             NS_ENSURE_TRUE_VOID(urifixup);
             nsCOMPtr<nsIURI> exposableURI;
             nsresult rv =
                 urifixup->CreateExposableURI(uri, getter_AddRefs(exposableURI));
             NS_ENSURE_SUCCESS_VOID(rv);
 
             NS_ConvertUTF8toUTF16 spec(exposableURI->GetSpecOrDefault());
-            bool overflows = spec.Length() > sMaxSpecLength;
-            spec.Truncate(std::min(spec.Length(), sMaxSpecLength));
-            if (overflows) {
-              NS_NAMED_LITERAL_STRING(kEllipsis, u"\x2026");
-              spec.Append(kEllipsis);
-            }
             const char16_t* params[] = {spec.get()};
 
             nsContentUtils::ReportToConsole(
                 nsIScriptError::warningFlag, category, doc,
                 nsContentUtils::eNECKO_PROPERTIES, message, params,
                 ArrayLength(params), nullptr, sourceLine, lineNumber,
                 columnNumber);
           }),
--- a/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html
@@ -205,17 +205,20 @@ function testOnWindow(aTestData) {
       await BrowserTestUtils.waitForContentEvent(browser, "DOMContentLoaded");
       checkResults(aTestData, expected);
       win.close();
       resolve();
     })();
   });
 }
 SpecialPowers.pushPrefEnv(
-  {"set": [["browser.safebrowsing.phishing.enabled", true]]},
+  {"set": [
+    ["browser.safebrowsing.phishing.enabled", true],
+    ["dom.testing.sync-content-blocking-notifications", true],
+  ]},
   test);
 
 function test() {
   (async function() {
     await classifierHelper.waitForInit();
 
     for (let testData of testDatas) {
       await setupTestData(testData);
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -440,16 +440,17 @@ class ActivePS {
 #endif
   {
     // Deep copy aFilters.
     MOZ_ALWAYS_TRUE(mFilters.resize(aFilterCount));
     for (uint32_t i = 0; i < aFilterCount; ++i) {
       mFilters[i] = aFilters[i];
     }
 
+#if !defined(RELEASE_OR_BETA)
     if (mInterposeObserver) {
       // We need to register the observer on the main thread, because we want
       // to observe IO that happens on the main thread.
       // IOInterposer needs to be initialized before calling
       // IOInterposer::Register or our observer will be silently dropped.
       if (NS_IsMainThread()) {
         IOInterposer::Init();
         IOInterposer::Register(IOInterposeObserver::OpAll, mInterposeObserver);
@@ -457,33 +458,36 @@ class ActivePS {
         RefPtr<ProfilerIOInterposeObserver> observer = mInterposeObserver;
         NS_DispatchToMainThread(
             NS_NewRunnableFunction("ActivePS::ActivePS", [=]() {
               IOInterposer::Init();
               IOInterposer::Register(IOInterposeObserver::OpAll, observer);
             }));
       }
     }
+#endif
   }
 
   ~ActivePS() {
+#if !defined(RELEASE_OR_BETA)
     if (mInterposeObserver) {
       // We need to unregister the observer on the main thread, because that's
       // where we've registered it.
       if (NS_IsMainThread()) {
         IOInterposer::Unregister(IOInterposeObserver::OpAll,
                                  mInterposeObserver);
       } else {
         RefPtr<ProfilerIOInterposeObserver> observer = mInterposeObserver;
         NS_DispatchToMainThread(
             NS_NewRunnableFunction("ActivePS::~ActivePS", [=]() {
               IOInterposer::Unregister(IOInterposeObserver::OpAll, observer);
             }));
       }
     }
+#endif
   }
 
   bool ThreadSelected(const char* aThreadName) {
     MOZ_RELEASE_ASSERT(sInstance);
 
     if (mFilters.empty()) {
       return true;
     }