Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 07 Nov 2016 20:38:29 -0800
changeset 351499 f13e90d496cf1bc6dfc4fd398da33e4afe785bde
parent 351468 f88d94ae4967e2bd71ce2a7de16af7d8b9129291 (current diff)
parent 351498 d19cffeae1febc6d669a024340de25228e544475 (diff)
child 351500 8fae9d0d9d4ca849fb4a918eca445f37098f4379
child 351562 6fde51a1e17fefca53ad10ff5e3c4037d1524cf4
child 351656 4a7fb43aa9dc6e13dfa08288fa2d01f102e27b57
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.0a1
Merge m-i to m-c, a=merge MozReview-Commit-ID: 5599Z7kxjk3
devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
devtools/client/netmonitor/test/browser_net_copy_response.js
devtools/client/netmonitor/test/head.js
mobile/android/base/moz.build
--- a/browser/base/content/test/popupNotifications/browser.ini
+++ b/browser/base/content/test/popupNotifications/browser.ini
@@ -9,8 +9,10 @@ skip-if = (os == "linux" && (debug || as
 [browser_popupNotification_2.js]
 skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_3.js]
 skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_4.js]
 skip-if = (os == "linux" && (debug || asan))
 [browser_popupNotification_checkbox.js]
 skip-if = (os == "linux" && (debug || asan))
+[browser_reshow_in_background.js]
+skip-if = (os == "linux" && (debug || asan))
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/popupNotifications/browser_reshow_in_background.js
@@ -0,0 +1,52 @@
+"use strict";
+
+/**
+ * Tests that when PopupNotifications for background tabs are reshown, they
+ * don't show up in the foreground tab, but only in the background tab that
+ * they belong to.
+ */
+add_task(function* test_background_notifications_dont_reshow_in_foreground() {
+  // Our initial tab will be A. Let's open two more tabs B and C, but keep
+  // A selected. Then, we'll trigger a PopupNotification in C, and then make
+  // it reshow.
+  let tabB = gBrowser.addTab("about:blank");
+  let tabC = gBrowser.addTab("about:blank");
+
+  let seenEvents = [];
+
+  let options = {
+    dismissed: false,
+    eventCallback(popupEvent) {
+      seenEvents.push(popupEvent);
+    },
+  };
+
+  let notification =
+    PopupNotifications.show(tabC.linkedBrowser, "test-notification",
+                            "", "plugins-notification-icon",
+                            null, null, options);
+  Assert.deepEqual(seenEvents, [], "Should have seen no events yet.");
+
+  yield BrowserTestUtils.switchTab(gBrowser, tabB);
+  Assert.deepEqual(seenEvents, [], "Should have seen no events yet.");
+
+  notification.reshow();
+  Assert.deepEqual(seenEvents, [], "Should have seen no events yet.");
+
+  let panelShown =
+    BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+  yield BrowserTestUtils.switchTab(gBrowser, tabC);
+  yield panelShown;
+
+  Assert.equal(seenEvents.length, 2, "Should have seen two events.");
+  Assert.equal(seenEvents[0], "showing", "Should have said popup was showing.");
+  Assert.equal(seenEvents[1], "shown", "Should have said popup was shown.");
+
+  let panelHidden =
+    BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+  PopupNotifications.remove(notification);
+  yield panelHidden;
+
+  yield BrowserTestUtils.removeTab(tabB);
+  yield BrowserTestUtils.removeTab(tabC);
+});
--- a/devtools/client/netmonitor/test/browser_net_content-type.js
+++ b/devtools/client/netmonitor/test/browser_net_content-type.js
@@ -2,98 +2,122 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 /**
  * Tests if different response content types are handled correctly.
  */
 
-add_task(function* () {
+function* content_type_test(isHTTPS) {
   let { L10N } = require("devtools/client/netmonitor/l10n");
 
-  let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
+  let pageURL = isHTTPS ? HTTPS_CONTENT_TYPE_WITHOUT_CACHE_URL
+                        : CONTENT_TYPE_WITHOUT_CACHE_URL;
+  let imageURL = isHTTPS ? HTTPS_TEST_IMAGE
+                         : TEST_IMAGE;
+  let sjsURL = isHTTPS ? HTTPS_CONTENT_TYPE_SJS
+                       : CONTENT_TYPE_SJS;
+  let { tab, monitor } = yield initNetMonitor(pageURL);
   info("Starting test... ");
 
   let { document, Editor, NetMonitorView } = monitor.panelWin;
   let { RequestsMenu } = NetMonitorView;
 
   RequestsMenu.lazyUpdate = false;
 
-  let wait = waitForNetworkEvents(monitor, 7);
+  let wait = waitForNetworkEvents(monitor, 8);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
 
+  let okStatus = isHTTPS ? "Connected" : "OK";
+
   verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
-    "GET", CONTENT_TYPE_SJS + "?fmt=xml", {
+    "GET", sjsURL + "?fmt=xml", {
       status: 200,
-      statusText: "OK",
+      statusText: okStatus,
       type: "xml",
       fullMimeType: "text/xml; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 42),
       time: true
     });
   verifyRequestItemTarget(RequestsMenu.getItemAtIndex(1),
-    "GET", CONTENT_TYPE_SJS + "?fmt=css", {
+    "GET", sjsURL + "?fmt=css", {
       status: 200,
-      statusText: "OK",
+      statusText: okStatus,
       type: "css",
       fullMimeType: "text/css; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
       time: true
     });
   verifyRequestItemTarget(RequestsMenu.getItemAtIndex(2),
-    "GET", CONTENT_TYPE_SJS + "?fmt=js", {
+    "GET", sjsURL + "?fmt=js", {
       status: 200,
-      statusText: "OK",
+      statusText: okStatus,
       type: "js",
       fullMimeType: "application/javascript; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 34),
       time: true
     });
   verifyRequestItemTarget(RequestsMenu.getItemAtIndex(3),
-    "GET", CONTENT_TYPE_SJS + "?fmt=json", {
+    "GET", sjsURL + "?fmt=json", {
       status: 200,
-      statusText: "OK",
+      statusText: okStatus,
       type: "json",
       fullMimeType: "application/json; charset=utf-8",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 29),
       time: true
     });
-  verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
-    "GET", CONTENT_TYPE_SJS + "?fmt=bogus", {
-      status: 404,
-      statusText: "Not Found",
-      type: "html",
-      fullMimeType: "text/html; charset=utf-8",
-      size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
-      time: true
-    });
+  if (!isHTTPS) {
+    // 404 doesn't work on HTTPS test harness.
+    verifyRequestItemTarget(RequestsMenu.getItemAtIndex(4),
+      "GET", sjsURL + "?fmt=bogus", {
+        status: 404,
+        statusText: "Not Found",
+        type: "html",
+        fullMimeType: "text/html; charset=utf-8",
+        size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 24),
+        time: true
+      });
+  }
   verifyRequestItemTarget(RequestsMenu.getItemAtIndex(5),
-    "GET", TEST_IMAGE, {
+    "GET", imageURL, {
       fuzzyUrl: true,
       status: 200,
-      statusText: "OK",
+      statusText: okStatus,
       type: "png",
       fullMimeType: "image/png",
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 580),
       time: true
     });
   verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
-    "GET", CONTENT_TYPE_SJS + "?fmt=gzip", {
+    "GET", sjsURL + "?fmt=gzip", {
       status: 200,
-      statusText: "OK",
+      statusText: okStatus,
       type: "plain",
       fullMimeType: "text/plain",
       transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 73),
       size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73),
       time: true
     });
+  if (isHTTPS) {
+    // Brotli is enabled only on HTTPS.
+    verifyRequestItemTarget(RequestsMenu.getItemAtIndex(6),
+      "GET", sjsURL + "?fmt=gzip", {
+        status: 200,
+        statusText: okStatus,
+        type: "plain",
+        fullMimeType: "text/plain",
+        transferred: L10N.getFormatStrWithNumbers("networkMenu.sizeB", 73),
+        size: L10N.getFormatStrWithNumbers("networkMenu.sizeKB", 10.73),
+        time: true
+      });
+  }
 
   let onEvent = waitForResponseBodyDisplayed();
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.getElementById("details-pane-toggle"));
   EventUtils.sendMouseEvent({ type: "mousedown" },
     document.querySelectorAll("#details-pane tab")[3]);
   yield onEvent;
   yield testResponseTab("xml");
@@ -111,16 +135,21 @@ add_task(function* () {
   yield testResponseTab("html");
 
   yield selectIndexAndWaitForTabUpdated(5);
   yield testResponseTab("png");
 
   yield selectIndexAndWaitForTabUpdated(6);
   yield testResponseTab("gzip");
 
+  if (isHTTPS) {
+    yield selectIndexAndWaitForTabUpdated(7);
+    yield testResponseTab("br");
+  }
+
   yield teardown(monitor);
 
   function* testResponseTab(type) {
     let tabEl = document.querySelectorAll("#details-pane tab")[3];
     let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
 
     is(tabEl.getAttribute("selected"), "true",
       "The response tab in the network details pane should be selected.");
@@ -235,21 +264,40 @@ add_task(function* () {
         let expected = new Array(1000).join("Hello gzip!");
         let editor = yield NetMonitorView.editor("#response-content-textarea");
         is(editor.getText(), expected,
           "The text shown in the source editor is incorrect for the gzip request.");
         is(editor.getMode(), Editor.modes.text,
           "The mode active in the source editor is incorrect for the gzip request.");
         break;
       }
+      case "br": {
+        checkVisibility("textarea");
+
+        let expected = "X".repeat(64);
+        let editor = yield NetMonitorView.editor("#response-content-textarea");
+        is(editor.getText(), expected,
+          "The text shown in the source editor is incorrect for the brotli request.");
+        is(editor.getMode(), Editor.modes.text,
+          "The mode active in the source editor is incorrect for the brotli request.");
+        break;
+      }
     }
   }
 
   function selectIndexAndWaitForTabUpdated(index) {
     let onTabUpdated = monitor.panelWin.once(monitor.panelWin.EVENTS.TAB_UPDATED);
     RequestsMenu.selectedIndex = index;
     return onTabUpdated;
   }
 
   function waitForResponseBodyDisplayed() {
     return monitor.panelWin.once(monitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED);
   }
+}
+
+add_task(function* () {
+    yield* content_type_test(false);
 });
+
+add_task(function* () {
+    yield* content_type_test(true);
+});
--- a/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_image_as_data_uri.js
@@ -11,17 +11,17 @@ add_task(function* () {
   let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
   info("Starting test... ");
 
   let { NetMonitorView } = monitor.panelWin;
   let { RequestsMenu } = NetMonitorView;
 
   RequestsMenu.lazyUpdate = false;
 
-  let wait = waitForNetworkEvents(monitor, 7);
+  let wait = waitForNetworkEvents(monitor, 8);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
 
   let requestItem = RequestsMenu.getItemAtIndex(5);
   RequestsMenu.selectedItem = requestItem;
 
--- a/devtools/client/netmonitor/test/browser_net_copy_response.js
+++ b/devtools/client/netmonitor/test/browser_net_copy_response.js
@@ -13,17 +13,17 @@ add_task(function* () {
 
   const EXPECTED_RESULT = '{ "greeting": "Hello JSON!" }';
 
   let { NetMonitorView } = monitor.panelWin;
   let { RequestsMenu } = NetMonitorView;
 
   RequestsMenu.lazyUpdate = false;
 
-  let wait = waitForNetworkEvents(monitor, 7);
+  let wait = waitForNetworkEvents(monitor, 8);
   yield ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     content.wrappedJSObject.performRequests();
   });
   yield wait;
 
   let requestItem = RequestsMenu.getItemAtIndex(3);
   RequestsMenu.selectedItem = requestItem;
 
--- a/devtools/client/netmonitor/test/browser_net_icon-preview.js
+++ b/devtools/client/netmonitor/test/browser_net_icon-preview.js
@@ -39,17 +39,17 @@ add_task(function* () {
 
   info("Checking the image thumbnail after a reload.");
   checkImageThumbnail();
 
   yield teardown(monitor);
 
   function waitForEvents() {
     return promise.all([
-      waitForNetworkEvents(monitor, 7),
+      waitForNetworkEvents(monitor, 8),
       monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED)
     ]);
   }
 
   function performRequests() {
     return ContentTask.spawn(tab.linkedBrowser, {}, function* () {
       content.wrappedJSObject.performRequests();
     });
--- a/devtools/client/netmonitor/test/browser_net_image-tooltip.js
+++ b/devtools/client/netmonitor/test/browser_net_image-tooltip.js
@@ -10,17 +10,17 @@ add_task(function* test() {
   let { tab, monitor } = yield initNetMonitor(CONTENT_TYPE_WITHOUT_CACHE_URL);
   info("Starting test... ");
 
   let { $, EVENTS, ACTIVITY_TYPE, NetMonitorView, NetMonitorController } =
     monitor.panelWin;
   let { RequestsMenu } = NetMonitorView;
   RequestsMenu.lazyUpdate = true;
 
-  let onEvents = waitForNetworkEvents(monitor, 7);
+  let onEvents = waitForNetworkEvents(monitor, 8);
   let onThumbnail = monitor.panelWin.once(EVENTS.RESPONSE_IMAGE_THUMBNAIL_DISPLAYED);
 
   yield performRequests();
   yield onEvents;
   yield onThumbnail;
 
   info("Checking the image thumbnail after a few requests were made...");
   yield showTooltipAndVerify(RequestsMenu.tooltip, RequestsMenu.items[5]);
--- a/devtools/client/netmonitor/test/head.js
+++ b/devtools/client/netmonitor/test/head.js
@@ -8,22 +8,24 @@
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   this);
 
 var NetworkHelper = require("devtools/shared/webconsole/network-helper");
 var { Toolbox } = require("devtools/client/framework/toolbox");
 
 const EXAMPLE_URL = "http://example.com/browser/devtools/client/netmonitor/test/";
+const HTTPS_EXAMPLE_URL = "https://example.com/browser/devtools/client/netmonitor/test/";
 
 const API_CALLS_URL = EXAMPLE_URL + "html_api-calls-test-page.html";
 const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html";
 const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html";
 const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
 const CONTENT_TYPE_WITHOUT_CACHE_URL = EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
+const HTTPS_CONTENT_TYPE_WITHOUT_CACHE_URL = HTTPS_EXAMPLE_URL + "html_content-type-without-cache-test-page.html";
 const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
 const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
 const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
 const POST_JSON_URL = EXAMPLE_URL + "html_post-json-test-page.html";
 const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
 const POST_RAW_WITH_HEADERS_URL = EXAMPLE_URL + "html_post-raw-with-headers-test-page.html";
 const PARAMS_URL = EXAMPLE_URL + "html_params-test-page.html";
 const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
@@ -39,26 +41,28 @@ const SINGLE_GET_URL = EXAMPLE_URL + "ht
 const STATISTICS_URL = EXAMPLE_URL + "html_statistics-test-page.html";
 const CURL_URL = EXAMPLE_URL + "html_copy-as-curl.html";
 const CURL_UTILS_URL = EXAMPLE_URL + "html_curl-utils.html";
 const SEND_BEACON_URL = EXAMPLE_URL + "html_send-beacon.html";
 const CORS_URL = EXAMPLE_URL + "html_cors-test-page.html";
 
 const SIMPLE_SJS = EXAMPLE_URL + "sjs_simple-test-server.sjs";
 const CONTENT_TYPE_SJS = EXAMPLE_URL + "sjs_content-type-test-server.sjs";
+const HTTPS_CONTENT_TYPE_SJS = HTTPS_EXAMPLE_URL + "sjs_content-type-test-server.sjs";
 const STATUS_CODES_SJS = EXAMPLE_URL + "sjs_status-codes-test-server.sjs";
 const SORTING_SJS = EXAMPLE_URL + "sjs_sorting-test-server.sjs";
 const HTTPS_REDIRECT_SJS = EXAMPLE_URL + "sjs_https-redirect-test-server.sjs";
 const CORS_SJS_PATH = "/browser/devtools/client/netmonitor/test/sjs_cors-test-server.sjs";
 const HSTS_SJS = EXAMPLE_URL + "sjs_hsts-test-server.sjs";
 
 const HSTS_BASE_URL = EXAMPLE_URL;
 const HSTS_PAGE_URL = CUSTOM_GET_URL;
 
 const TEST_IMAGE = EXAMPLE_URL + "test-image.png";
+const HTTPS_TEST_IMAGE = HTTPS_EXAMPLE_URL + "test-image.png";
 const TEST_IMAGE_DATA_URI = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
 
 const FRAME_SCRIPT_UTILS_URL = "chrome://devtools/content/shared/frame-script-utils.js";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 const gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log");
--- a/devtools/client/netmonitor/test/html_content-type-without-cache-test-page.html
+++ b/devtools/client/netmonitor/test/html_content-type-without-cache-test-page.html
@@ -30,17 +30,19 @@
       function performRequests() {
         get("sjs_content-type-test-server.sjs?fmt=xml", function() {
           get("sjs_content-type-test-server.sjs?fmt=css", function() {
             get("sjs_content-type-test-server.sjs?fmt=js", function() {
               get("sjs_content-type-test-server.sjs?fmt=json", function() {
                 get("sjs_content-type-test-server.sjs?fmt=bogus", function() {
                   get("test-image.png?v=" + Math.random(), function() {
                     get("sjs_content-type-test-server.sjs?fmt=gzip", function() {
-                      // Done.
+                      get("sjs_content-type-test-server.sjs?fmt=br", function() {
+                        // Done.
+                      });
                     });
                   });
                 });
               });
             });
           });
         });
       }
--- a/devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
+++ b/devtools/client/netmonitor/test/sjs_content-type-test-server.sjs
@@ -227,16 +227,27 @@ function handleRequest(request, response
             response.write(buffer);
             response.finish();
           }
         };
         let data = new Array(1000).join("Hello gzip!");
         doubleGzipCompressString(data, observer);
         break;
       }
+      case "br": {
+        response.setStatusLine(request.httpVersion, status, "Connected");
+        response.setHeader("Content-Type", "text/plain", false);
+        response.setHeader("Content-Encoding", "br", false);
+        setCacheHeaders();
+        response.setHeader("Content-Length", "10", false);
+        // Use static data since we cannot encode brotli.
+        response.write("\x1b\x3f\x00\x00\x24\xb0\xe2\x99\x80\x12");
+        response.finish();
+        break;
+      }
       case "hls-m3u8": {
         response.setStatusLine(request.httpVersion, status, "OK");
         response.setHeader("Content-Type", "application/x-mpegurl", false);
         setCacheHeaders();
         response.write("#EXTM3U\n");
         response.finish();
         break;
       }
--- a/devtools/client/shared/view-source.js
+++ b/devtools/client/shared/view-source.js
@@ -57,17 +57,17 @@ exports.viewSourceInDebugger = Task.asyn
   let debuggerAlreadyOpen = toolbox.getPanel("jsdebugger");
   let dbg = yield toolbox.loadTool("jsdebugger");
 
   // New debugger frontend
   if (Services.prefs.getBoolPref("devtools.debugger.new-debugger-frontend")) {
     yield toolbox.selectTool("jsdebugger");
     const source = dbg._selectors().getSourceByURL(dbg._getState(), sourceURL);
     if (source) {
-      dbg._actions().selectSourceByURL(sourceURL, { line: sourceLine });
+      dbg._actions().selectSourceURL(sourceURL, { line: sourceLine });
       return true;
     }
 
     exports.viewSource(toolbox, sourceURL, sourceLine);
     return false;
   }
 
   const win = dbg.panelWin;
--- a/devtools/client/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js
+++ b/devtools/client/webconsole/test/browser_webconsole_bug_766001_JS_Console_in_Debugger.js
@@ -6,18 +6,19 @@
 // Test that message source links for js errors and console API calls open in
 // the jsdebugger when clicked.
 
 "use strict";
 
 const TEST_URI = "http://example.com/browser/devtools/client/webconsole/test" +
                  "/test-bug-766001-js-console-links.html";
 
-// Force the old debugger UI since it's directly used (see Bug 1301705)
-Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
+// Force the new debugger UI, in case this gets uplifted with the old
+// debugger still turned on
+Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", true);
 registerCleanupFunction(function* () {
   Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
 });
 
 function test() {
   let hud;
 
   requestLongerTimeout(2);
@@ -74,15 +75,14 @@ function test() {
 
     executeSoon(() => {
       EventUtils.sendMouseEvent({ type: "click" }, node.querySelector(".frame-link-filename"));
     });
 
     yield hud.ui.once("source-in-debugger-opened");
 
     let toolbox = yield gDevTools.getToolbox(hud.target);
-    let {panelWin: { DebuggerView: view }} = toolbox.getPanel("jsdebugger");
-    is(view.Sources.selectedValue,
-       getSourceActor(view.Sources, url),
+    let dbg = toolbox.getPanel("jsdebugger");
+    is(dbg._selectors().getSelectedSource(dbg._getState()).get("url"),
+       url,
        "expected source url");
-    is(view.editor.getCursor().line, line - 1, "expected source line");
   }
 }
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -441,17 +441,17 @@ NetworkResponseListener.prototype = {
         channel instanceof Ci.nsIEncodedChannel &&
         channel.contentEncodings &&
         !channel.applyConversion) {
       let encodingHeader = channel.getResponseHeader("Content-Encoding");
       let scs = Cc["@mozilla.org/streamConverters;1"]
         .getService(Ci.nsIStreamConverterService);
       let encodings = encodingHeader.split(/\s*\t*,\s*\t*/);
       let nextListener = this;
-      let acceptedEncodings = ["gzip", "deflate", "x-gzip", "x-deflate"];
+      let acceptedEncodings = ["gzip", "deflate", "br", "x-gzip", "x-deflate"];
       for (let i in encodings) {
         // There can be multiple conversions applied
         let enc = encodings[i].toLowerCase();
         if (acceptedEncodings.indexOf(enc) > -1) {
           this.converter = scs.asyncConvertData(enc, "uncompressed",
                                                 nextListener, null);
           nextListener = this.converter;
         }
--- a/dom/base/nsAttrValue.cpp
+++ b/dom/base/nsAttrValue.cpp
@@ -639,21 +639,18 @@ nsAttrValue::ToString(nsAString& aResult
       aResult = intStr + NS_LITERAL_STRING("%");
 
       break;
     }
     case eCSSDeclaration:
     {
       aResult.Truncate();
       MiscContainer *container = GetMiscContainer();
-      DeclarationBlock* decl = container->mValue.mCSSDeclaration;
-      // XXXheycam Once we support CSSOM access to them, we should
-      // probably serialize ServoDeclarationBlock like this too.
-      if (decl && decl->IsGecko()) {
-        decl->AsGecko()->ToString(aResult);
+      if (DeclarationBlock* decl = container->mValue.mCSSDeclaration) {
+        decl->ToString(aResult);
       }
       const_cast<nsAttrValue*>(this)->SetMiscAtomOrString(&aResult);
 
       break;
     }
     case eDoubleValue:
     {
       aResult.Truncate();
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -105,16 +105,17 @@
 #include "nsCSSPseudoElements.h"            // for CSSPseudoElementType
 #include "nsNetUtil.h"
 #include "nsDocument.h"
 #include "HTMLImageElement.h"
 #include "mozilla/css/ImageLoader.h"
 #include "mozilla/layers/APZCTreeManager.h" // for layers::ZoomToRectBehavior
 #include "mozilla/dom/Promise.h"
 #include "mozilla/StyleSheetInlines.h"
+#include "mozilla/gfx/GPUProcessManager.h"
 
 #ifdef XP_WIN
 #undef GetClassName
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
@@ -4087,16 +4088,39 @@ nsDOMWindowUtils::ForceReflowInterrupt()
   nsPresContext* pc = GetPresContext();
   if (!pc) {
     return NS_ERROR_NOT_AVAILABLE;
   }
   pc->SetPendingInterruptFromTest();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsDOMWindowUtils::TerminateGPUProcess()
+{
+  GPUProcessManager* pm = GPUProcessManager::Get();
+  if (pm) {
+    pm->KillProcess();
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::GetGpuProcessPid(int32_t* aPid)
+{
+  GPUProcessManager* pm = GPUProcessManager::Get();
+  if (pm) {
+    *aPid = pm->GPUProcessPid();
+  } else {
+    *aPid = -1;
+  }
+
+  return NS_OK;
+}
+
 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_ADDREF(nsTranslationNodeList)
 NS_IMPL_RELEASE(nsTranslationNodeList)
 
--- a/dom/base/test/chrome/window_groupedSHistory.xul
+++ b/dom/base/test/chrome/window_groupedSHistory.xul
@@ -263,16 +263,22 @@ https://bugzilla.mozilla.org/show_bug.cg
     let promises = [];
     let pagehide1, pagehide2;
 
     // For swapping there should be a pagehide followed by a pageshow.
     promises.push(BrowserTestUtils.waitForMessage(b1.messageManager, 'test:pagehide', msg => pagehide1 = true));
     promises.push(BrowserTestUtils.waitForMessage(b2.messageManager, 'test:pagehide', msg => pagehide2 = true));
     promises.push(BrowserTestUtils.waitForMessage(b1.messageManager, 'test:pageshow', msg => pagehide1));
     promises.push(BrowserTestUtils.waitForMessage(b2.messageManager, 'test:pageshow', msg => pagehide2));
+
+    // For swapping remote browsers, we'll also receive Content:LocationChange
+    if (b1.isRemoteBrowser) {
+      promises.push(BrowserTestUtils.waitForMessage(b1.messageManager, 'Content:LocationChange'));
+    }
+
     promises.push(Promise.resolve().then(() => {
       let f1 = b1.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
       let f2 = b2.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
       f1.appendPartialSessionHistoryAndSwap(f2);
     }));
 
     return Promise.all(promises);
   }
@@ -281,16 +287,22 @@ https://bugzilla.mozilla.org/show_bug.cg
     let promises = [];
     let pagehide = false;
     let pageshowCount = 0;
 
     if (expectSwap) {
       // For swapping there should be a pagehide followed by a pageshow.
       promises.push(BrowserTestUtils.waitForMessage(browser.messageManager,
         'test:pagehide', msg => pagehide = true));
+
+      // For swapping remote browsers, we'll also receive Content:LocationChange
+      if (browser.isRemoteBrowser) {
+        promises.push(BrowserTestUtils.waitForMessage(browser.messageManager,
+          'Content:LocationChange'));
+      }
     }
     promises.push(BrowserTestUtils.waitForMessage(browser.messageManager,
       'test:pageshow', msg => {
         // Only count events after pagehide for swapping case.
         if (!expectSwap || pagehide) {
           return !--expectPageshowCount;
         }
         return false;
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -44,17 +44,17 @@ interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 interface nsIObserver;
 
-[scriptable, uuid(46b44e33-13c2-4eb3-bf80-76a4e0857ccc)]
+[scriptable, uuid(c471d440-004b-4c50-a6f2-747db5f443b6)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1960,16 +1960,26 @@ interface nsIDOMWindowUtils : nsISupport
   void respectDisplayPortSuppression(in boolean aEnabled);
 
   /**
    * Set a flag that forces the next reflow interrupt check to return true. This
    * can be used by tests to force execution of the interrupted reflow codepaths.
    */
   void forceReflowInterrupt();
 
+  /**
+   * Terminate the GPU process. Used for testing GPU process restarts.
+   */
+  void terminateGPUProcess();
+
+  /**
+    * Returns the GPU process pid, or -1 if there is no GPU process.
+    */
+  readonly attribute int32_t gpuProcessPid;
+
   const long MOUSE_BUTTONS_NO_BUTTON = 0x00;
   const long MOUSE_BUTTONS_LEFT_BUTTON = 0x01;
   const long MOUSE_BUTTONS_RIGHT_BUTTON = 0x02;
   const long MOUSE_BUTTONS_MIDDLE_BUTTON = 0x04;
   // Typically, "back" button being left side of 5-button
   // mice, see "buttons" attribute document of DOM3 Events.
   const long MOUSE_BUTTONS_4TH_BUTTON = 0x08;
   // Typically, "forward" button being right side of 5-button
--- a/gfx/ipc/GPUProcessHost.cpp
+++ b/gfx/ipc/GPUProcessHost.cpp
@@ -219,16 +219,22 @@ GPUProcessHost::GetProcessToken() const
 static void
 DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
 {
   XRE_GetIOMessageLoop()->
     PostTask(mozilla::MakeAndAddRef<DeleteTask<GeckoChildProcessHost>>(aSubprocess));
 }
 
 void
+GPUProcessHost::KillProcess()
+{
+  KillHard("DiagnosticKill");
+}
+
+void
 GPUProcessHost::DestroyProcess()
 {
   // Cancel all tasks. We don't want anything triggering after our caller
   // expects this to go away.
   {
     MonitorAutoLock lock(mMonitor);
     mTaskFactory.RevokeAll();
   }
--- a/gfx/ipc/GPUProcessHost.h
+++ b/gfx/ipc/GPUProcessHost.h
@@ -91,16 +91,19 @@ public:
   }
 
   // Called on the IO thread.
   void OnChannelConnected(int32_t peer_pid) override;
   void OnChannelError() override;
 
   void SetListener(Listener* aListener);
 
+  // Used for tests and diagnostics
+  void KillProcess();
+
 private:
   // Called on the main thread.
   void OnChannelConnectedTask();
   void OnChannelErrorTask();
 
   // Called on the main thread after a connection has been established.
   void InitAfterConnect(bool aSucceeded);
 
--- a/gfx/ipc/GPUProcessManager.cpp
+++ b/gfx/ipc/GPUProcessManager.cpp
@@ -382,16 +382,26 @@ GPUProcessManager::NotifyRemoteActorDest
 void
 GPUProcessManager::CleanShutdown()
 {
   DestroyProcess();
   mVsyncIOThread = nullptr;
 }
 
 void
+GPUProcessManager::KillProcess()
+{
+  if (!mProcess) {
+    return;
+  }
+
+  mProcess->KillProcess();
+}
+
+void
 GPUProcessManager::DestroyProcess()
 {
   if (!mProcess) {
     return;
   }
 
   mProcess->Shutdown();
   mProcessToken = 0;
@@ -601,16 +611,25 @@ GPUProcessManager::CreateContentImageBri
       return false;
     }
   }
 
   *aOutEndpoint = Move(childPipe);
   return true;
 }
 
+base::ProcessId
+GPUProcessManager::GPUProcessPid()
+{
+  base::ProcessId gpuPid = mGPUChild
+                           ? mGPUChild->OtherPid()
+                           : -1;
+  return gpuPid;
+}
+
 bool
 GPUProcessManager::CreateContentVRManager(base::ProcessId aOtherProcess,
                                           ipc::Endpoint<PVRManagerChild>* aOutEndpoint)
 {
   EnsureVRManager();
 
   base::ProcessId gpuPid = mGPUChild
                            ? mGPUChild->OtherPid()
--- a/gfx/ipc/GPUProcessManager.h
+++ b/gfx/ipc/GPUProcessManager.h
@@ -128,16 +128,22 @@ public:
 
   void AddListener(GPUProcessListener* aListener);
   void RemoveListener(GPUProcessListener* aListener);
 
   // Send a message to the GPU process observer service to broadcast. Returns
   // true if the message was sent, false if not.
   bool NotifyGpuObservers(const char* aTopic);
 
+  // Used for tests and diagnostics
+  void KillProcess();
+
+  // Returns -1 if there is no GPU process, or the platform pid for it.
+  base::ProcessId GPUProcessPid();
+
   // Returns access to the PGPU protocol if a GPU process is present.
   GPUChild* GetGPUChild() {
     return mGPUChild;
   }
 
   // Returns whether or not a GPU process was ever launched.
   bool AttemptedGPUProcess() const {
     return mNumProcessAttempts > 0;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -599,35 +599,41 @@ Layer::SnapTransformTranslation(const Ma
     *aResidualTransform = Matrix();
   }
 
   if (!mManager->IsSnappingEffectiveTransforms()) {
     return aTransform;
   }
 
   Matrix matrix2D;
-  Matrix4x4 result;
   if (aTransform.CanDraw2D(&matrix2D) &&
       !matrix2D.HasNonTranslation() &&
       matrix2D.HasNonIntegerTranslation()) {
     auto snappedTranslation = IntPoint::Round(matrix2D.GetTranslation());
     Matrix snappedMatrix = Matrix::Translation(snappedTranslation.x,
                                                snappedTranslation.y);
-    result = Matrix4x4::From2D(snappedMatrix);
+    Matrix4x4 result = Matrix4x4::From2D(snappedMatrix);
     if (aResidualTransform) {
       // set aResidualTransform so that aResidual * snappedMatrix == matrix2D.
       // (I.e., appying snappedMatrix after aResidualTransform gives the
       // ideal transform.)
       *aResidualTransform =
         Matrix::Translation(matrix2D._31 - snappedTranslation.x,
                             matrix2D._32 - snappedTranslation.y);
     }
     return result;
   }
 
+  return SnapTransformTranslation3D(aTransform, aResidualTransform);
+}
+
+Matrix4x4
+Layer::SnapTransformTranslation3D(const Matrix4x4& aTransform,
+                                  Matrix* aResidualTransform)
+{
   if(aTransform.IsSingular() ||
      aTransform.HasPerspectiveComponent() ||
      aTransform.HasNonTranslation() ||
      !aTransform.HasNonIntegerTranslation()) {
     // For a singular transform, there is no reversed matrix, so we
     // don't snap it.
     // For a perspective transform, the content is transformed in
     // non-linear, so we don't snap it too.
@@ -667,17 +673,17 @@ Layer::SnapTransformTranslation(const Ma
     // The residual transform is to translate the snap to the origin
     // of the content buffer.
     *aResidualTransform = Matrix::Translation(-snap.x, -snap.y);
   }
 
   // Translate transformed origin to transformed snap since the
   // residual transform would trnslate the snap to the origin.
   Point3D transformedShift = transformedSnap - transformedOrigin;
-  result = aTransform;
+  Matrix4x4 result = aTransform;
   result.PostTranslate(transformedShift.x,
                        transformedShift.y,
                        transformedShift.z);
 
   // For non-2d transform, residual translation could be more than
   // 0.5 pixels for every axis.
 
   return result;
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1816,16 +1816,18 @@ protected:
    * layer's content can be rendered unpredictably (jiggling) as the scale
    * interacts with the snapping of the translation, especially with animated
    * transforms.
    * @param aResidualTransform a transform to apply before the result transform
    * in order to get the results to completely match aTransform.
    */
   gfx::Matrix4x4 SnapTransformTranslation(const gfx::Matrix4x4& aTransform,
                                           gfx::Matrix* aResidualTransform);
+  gfx::Matrix4x4 SnapTransformTranslation3D(const gfx::Matrix4x4& aTransform,
+                                            gfx::Matrix* aResidualTransform);
   /**
    * See comment for SnapTransformTranslation.
    * This function implements type 2 snapping. If aTransform is a translation
    * and/or scale, transform aSnapRect by aTransform, snap to pixel boundaries,
    * and return the transform that maps aSnapRect to that rect. Otherwise
    * just return aTransform.
    * @param aSnapRect a rectangle whose edges should be snapped to pixel
    * boundaries in the destination surface.
--- a/gfx/layers/basic/BasicContainerLayer.cpp
+++ b/gfx/layers/basic/BasicContainerLayer.cpp
@@ -32,28 +32,33 @@ BasicContainerLayer::~BasicContainerLaye
 
 void
 BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSurface)
 {
   // We push groups for container layers if we need to, which always
   // are aligned in device space, so it doesn't really matter how we snap
   // containers.
   Matrix residual;
-  Matrix4x4 idealTransform = GetLocalTransform() * aTransformToSurface;
-  if (!Extend3DContext() && !Is3DContextLeaf()) {
-    // For 3D transform leaked from extended parent layer.
+  Matrix4x4 transformToSurface = aTransformToSurface;
+  bool participate3DCtx = Extend3DContext() || Is3DContextLeaf();
+  if (!participate3DCtx &&
+      GetContentFlags() & CONTENT_BACKFACE_HIDDEN) {
+    // For backface-hidden layers
+    transformToSurface.ProjectTo2D();
+  }
+  Matrix4x4 idealTransform = GetLocalTransform() * transformToSurface;
+  if (!participate3DCtx &&
+      !(GetContentFlags() & CONTENT_BACKFACE_HIDDEN)) {
+    // For non-backface-hidden layers,
+    // 3D components are required to handle CONTENT_BACKFACE_HIDDEN.
     idealTransform.ProjectTo2D();
   }
 
   if (!idealTransform.CanDraw2D()) {
-    if (!Extend3DContext() ||
-        (!idealTransform.Is2D() && Creates3DContextWithExtendingChildren())) {
-      if (!Creates3DContextWithExtendingChildren()) {
-        idealTransform.ProjectTo2D();
-      }
+    if (!Extend3DContext()) {
       mEffectiveTransform = idealTransform;
       ComputeEffectiveTransformsForChildren(Matrix4x4());
       ComputeEffectiveTransformForMaskLayers(Matrix4x4());
       mUseIntermediateSurface = true;
       return;
     }
 
     mEffectiveTransform = idealTransform;
@@ -79,22 +84,22 @@ BasicContainerLayer::ComputeEffectiveTra
    * Having a blend mode also always forces our own push group
    */
   mUseIntermediateSurface =
     GetMaskLayer() ||
     GetForceIsolatedGroup() ||
     (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) ||
     (GetEffectiveOpacity() != 1.0 && ((HasMultipleChildren() && !Extend3DContext()) || hasSingleBlendingChild));
 
-  if (!Extend3DContext()) {
-    idealTransform.ProjectTo2D();
-  }
   mEffectiveTransform =
     !mUseIntermediateSurface ?
-    idealTransform : SnapTransformTranslation(idealTransform, &residual);
+    idealTransform :
+    (!(GetContentFlags() & CONTENT_BACKFACE_HIDDEN) ?
+     SnapTransformTranslation(idealTransform, &residual) :
+     SnapTransformTranslation3D(idealTransform, &residual));
   Matrix4x4 childTransformToSurface =
     (!mUseIntermediateSurface ||
      (mUseIntermediateSurface && !Extend3DContext() /* 2D */)) ?
     idealTransform : Matrix4x4::From2D(residual);
   ComputeEffectiveTransformsForChildren(childTransformToSurface);
 
   ComputeEffectiveTransformForMaskLayers(aTransformToSurface);
 }
--- a/js/src/jit-test/tests/wasm/jsapi.js
+++ b/js/src/jit-test/tests/wasm/jsapi.js
@@ -1,13 +1,13 @@
 load(libdir + 'wasm.js');
 
 const WasmPage = 64 * 1024;
 
-const emptyModule = wasmTextToBinary('(module)');
+const moduleBinary = wasmTextToBinary('(module (func (export "f") (result i32) (i32.const 42)))');
 
 // 'WebAssembly' data property on global object
 const wasmDesc = Object.getOwnPropertyDescriptor(this, 'WebAssembly');
 assertEq(typeof wasmDesc.value, "object");
 assertEq(wasmDesc.writable, true);
 assertEq(wasmDesc.enumerable, false);
 assertEq(wasmDesc.configurable, true);
 
@@ -65,34 +65,34 @@ assertEq(Module.length, 1);
 assertEq(Module.name, "Module");
 assertErrorMessage(() => Module(), TypeError, /constructor without new is forbidden/);
 assertErrorMessage(() => new Module(), TypeError, /requires more than 0 arguments/);
 assertErrorMessage(() => new Module(undefined), TypeError, "first argument must be an ArrayBuffer or typed array object");
 assertErrorMessage(() => new Module(1), TypeError, "first argument must be an ArrayBuffer or typed array object");
 assertErrorMessage(() => new Module({}), TypeError, "first argument must be an ArrayBuffer or typed array object");
 assertErrorMessage(() => new Module(new Uint8Array()), CompileError, /failed to match magic number/);
 assertErrorMessage(() => new Module(new ArrayBuffer()), CompileError, /failed to match magic number/);
-assertEq(new Module(emptyModule) instanceof Module, true);
-assertEq(new Module(emptyModule.buffer) instanceof Module, true);
+assertEq(new Module(moduleBinary) instanceof Module, true);
+assertEq(new Module(moduleBinary.buffer) instanceof Module, true);
 
 // 'WebAssembly.Module.prototype' data property
 const moduleProtoDesc = Object.getOwnPropertyDescriptor(Module, 'prototype');
 assertEq(typeof moduleProtoDesc.value, "object");
 assertEq(moduleProtoDesc.writable, false);
 assertEq(moduleProtoDesc.enumerable, false);
 assertEq(moduleProtoDesc.configurable, false);
 
 // 'WebAssembly.Module.prototype' object
 const moduleProto = Module.prototype;
 assertEq(moduleProto, moduleProtoDesc.value);
 assertEq(String(moduleProto), "[object Object]");
 assertEq(Object.getPrototypeOf(moduleProto), Object.prototype);
 
 // 'WebAssembly.Module' instance objects
-const m1 = new Module(emptyModule);
+const m1 = new Module(moduleBinary);
 assertEq(typeof m1, "object");
 assertEq(String(m1), "[object WebAssembly.Module]");
 assertEq(Object.getPrototypeOf(m1), moduleProto);
 
 // 'WebAssembly.Instance' data property
 const instanceDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Instance');
 assertEq(typeof instanceDesc.value, "function");
 assertEq(instanceDesc.writable, true);
@@ -132,16 +132,24 @@ assertEq(Object.getPrototypeOf(i1), inst
 
 // 'WebAssembly.Instance' 'exports' data property
 const exportsDesc = Object.getOwnPropertyDescriptor(i1, 'exports');
 assertEq(typeof exportsDesc.value, "object");
 assertEq(exportsDesc.writable, true);
 assertEq(exportsDesc.enumerable, true);
 assertEq(exportsDesc.configurable, true);
 
+// Exported WebAssembly functions
+const f = i1.exports.f;
+assertEq(f instanceof Function, true);
+assertEq(f.length, 0);
+assertEq('name' in f, true);
+assertEq(Function.prototype.call.call(f), 42);
+assertErrorMessage(() => new f(), TypeError, /is not a constructor/);
+
 // 'WebAssembly.Memory' data property
 const memoryDesc = Object.getOwnPropertyDescriptor(WebAssembly, 'Memory');
 assertEq(typeof memoryDesc.value, "function");
 assertEq(memoryDesc.writable, true);
 assertEq(memoryDesc.enumerable, false);
 assertEq(memoryDesc.configurable, true);
 
 // 'WebAssembly.Memory' constructor function
@@ -374,10 +382,10 @@ assertCompileError([{}], /first argument
 assertCompileError([new Uint8Array()], /failed to match magic number/);
 assertCompileError([new ArrayBuffer()], /failed to match magic number/);
 function assertCompileSuccess(bytes) {
     var module = null;
     compile(bytes).then(m => module = m);
     drainJobQueue();
     assertEq(module instanceof Module, true);
 }
-assertCompileSuccess(emptyModule);
-assertCompileSuccess(emptyModule.buffer);
+assertCompileSuccess(moduleBinary);
+assertCompileSuccess(moduleBinary.buffer);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -926,16 +926,27 @@ class MacroAssembler : public MacroAssem
     // On x86_shared, temp may be Invalid only if the chip has the POPCNT instruction.
     // On ARM, temp may never be Invalid.
     inline void popcnt32(Register src, Register dest, Register temp) PER_SHARED_ARCH;
 
     // temp may be invalid only if the chip has the POPCNT instruction.
     inline void popcnt64(Register64 src, Register64 dest, Register temp) PER_ARCH;
 
     // ===============================================================
+    // Condition functions
+
+    template <typename T1, typename T2>
+    inline void cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
+        DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
+
+    template <typename T1, typename T2>
+    inline void cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
+        PER_ARCH;
+
+    // ===============================================================
     // Branch functions
 
     template <class L>
     inline void branch32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH;
     template <class L>
     inline void branch32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH;
     inline void branch32(Condition cond, Register length, const RegisterOrInt32Constant& key,
                          Label* label);
@@ -960,17 +971,17 @@ class MacroAssembler : public MacroAssem
     inline void branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label)
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
 
     // The supported condition are Equal, NotEqual, LessThan(orEqual), GreaterThan(orEqual),
     // Below(orEqual) and Above(orEqual).
     // When a fail label is not defined it will fall through to next instruction,
     // else jump to the fail label.
     inline void branch64(Condition cond, Register64 lhs, Imm64 val, Label* success,
-                         Label* fail = nullptr) DEFINED_ON(x86, x64, arm, mips32, mips64);
+                         Label* fail = nullptr) PER_ARCH;
     inline void branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success,
                          Label* fail = nullptr) DEFINED_ON(x86, x64, arm, mips32, mips64);
     // On x86 and x64 NotEqual and Equal conditions are allowed for the branch64 variants
     // with Address as lhs. On others only the NotEqual condition.
     inline void branch64(Condition cond, const Address& lhs, Imm64 val, Label* label) PER_ARCH;
 
     // Compare the value at |lhs| with the value at |rhs|.  The scratch
     // register *must not* be the base of |lhs| or |rhs|.
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -993,16 +993,35 @@ MacroAssembler::rotateRight64(Register s
     as_mov(dest.low, lsl(src.low, shift_value));
     as_rsb(shift_value, shift_value, Imm8(32));
     as_orr(dest.low, dest.low, lsr(temp, shift_value));
 
     bind(&done);
 }
 
 // ===============================================================
+// Condition functions
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    cmp32(lhs, rhs);
+    emitSet(cond, dest);
+}
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    cmpPtr(lhs, rhs);
+    emitSet(cond, dest);
+}
+
+// ===============================================================
 // Bit counting functions
 
 void
 MacroAssembler::clz32(Register src, Register dest, bool knownNotZero)
 {
     ma_clz(src, dest);
 }
 
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1454,29 +1454,16 @@ class MacroAssemblerARMCompat : public M
 
     void
     emitSet(Assembler::Condition cond, Register dest)
     {
         ma_mov(Imm32(0), dest);
         ma_mov(Imm32(1), dest, cond);
     }
 
-    template <typename T1, typename T2>
-    void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        cmpPtr(lhs, rhs);
-        emitSet(cond, dest);
-    }
-    template <typename T1, typename T2>
-    void cmp32Set(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        cmp32(lhs, rhs);
-        emitSet(cond, dest);
-    }
-
     void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
         cond = testNull(cond, value);
         emitSet(cond, dest);
     }
 
     void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
         cond = testObject(cond, value);
         emitSet(cond, dest);
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -669,16 +669,35 @@ MacroAssembler::rshift64Arithmetic(Imm32
 
 void
 MacroAssembler::rshift64Arithmetic(Register shift, Register64 srcDest)
 {
     MOZ_CRASH("NYI: rshift64Arithmetic");
 }
 
 // ===============================================================
+// Condition functions
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    cmp32(lhs, rhs);
+    emitSet(cond, dest);
+}
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    cmpPtr(lhs, rhs);
+    emitSet(cond, dest);
+}
+
+// ===============================================================
 // Rotation functions
 
 void
 MacroAssembler::rotateLeft(Imm32 count, Register input, Register dest)
 {
     MOZ_CRASH("NYI: rotateLeft by immediate");
 }
 
@@ -825,16 +844,22 @@ MacroAssembler::branch32(Condition cond,
 {
     vixl::UseScratchRegisterScope temps(this);
     const Register scratch = temps.AcquireX().asUnsized();
     movePtr(lhs, scratch);
     branch32(cond, Address(scratch, 0), rhs, label);
 }
 
 void
+MacroAssembler::branch64(Condition cond, Register64 lhs, Imm64 val, Label* success, Label* fail)
+{
+    MOZ_CRASH("NYI: branch64 reg-imm");
+}
+
+void
 MacroAssembler::branch64(Condition cond, const Address& lhs, Imm64 val, Label* label)
 {
     MOZ_ASSERT(cond == Assembler::NotEqual,
                "other condition codes not supported");
 
     branchPtr(cond, lhs, ImmWord(val.value), label);
 }
 
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -415,28 +415,16 @@ class MacroAssemblerCompat : public vixl
     }
 
     inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
 
     void emitSet(Condition cond, Register dest) {
         Cset(ARMRegister(dest, 64), cond);
     }
 
-    template <typename T1, typename T2>
-    void cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest) {
-        cmpPtr(lhs, rhs);
-        emitSet(cond, dest);
-    }
-
-    template <typename T1, typename T2>
-    void cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest) {
-        cmp32(lhs, rhs);
-        emitSet(cond, dest);
-    }
-
     void testNullSet(Condition cond, const ValueOperand& value, Register dest) {
         cond = testNull(cond, value);
         emitSet(cond, dest);
     }
     void testObjectSet(Condition cond, const ValueOperand& value, Register dest) {
         cond = testObject(cond, value);
         emitSet(cond, dest);
     }
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -658,16 +658,30 @@ MacroAssembler::rotateRight64(Register s
 
     ma_sll(dest.low, src.low, temp);
     ma_srl(SecondScratchReg, src.high, shift_value);
     as_or(dest.low, dest.low, SecondScratchReg);
 
     bind(&done);
 }
 
+template <typename T1, typename T2>
+void
+MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    ma_cmp_set(dest, lhs, rhs, cond);
+}
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    ma_cmp_set(dest, lhs, rhs, cond);
+}
+
 // ===============================================================
 // Bit counting functions
 
 void
 MacroAssembler::clz64(Register64 src, Register dest)
 {
     Label done, low;
 
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -964,28 +964,16 @@ class MacroAssemblerMIPSCompat : public 
     void alignStackPointer();
     void restoreStackPointer();
     static void calculateAlignedStackPointer(void** stackPointer);
 
     // If source is a double, load it into dest. If source is int32,
     // convert it to double. Else, branch to failure.
     void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
 
-    template <typename T1, typename T2>
-    void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        ma_cmp_set(dest, lhs, rhs, cond);
-    }
-
-    template <typename T1, typename T2>
-    void cmp32Set(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        ma_cmp_set(dest, lhs, rhs, cond);
-    }
-
   protected:
     bool buildOOLFakeExitFrame(void* fakeReturnAddr);
 
   public:
     CodeOffset labelForPatch() {
         return CodeOffset(nextOffset().getOffset());
     }
 
--- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h
@@ -396,16 +396,33 @@ MacroAssembler::rotateRight64(Imm32 coun
 void
 MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest, Register temp)
 {
     MOZ_ASSERT(temp == InvalidReg);
     ma_dror(dest.reg, src.reg, count);
 }
 
 // ===============================================================
+// Condition functions
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    ma_cmp_set(dest, lhs, rhs, cond);
+}
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    ma_cmp_set(dest, lhs, rhs, cond);
+}
+
+// ===============================================================
 // Bit counting functions
 
 void
 MacroAssembler::clz64(Register64 src, Register dest)
 {
     as_dclz(dest, src.reg);
 }
 
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -977,29 +977,19 @@ class MacroAssemblerMIPS64Compat : publi
     void checkStackAlignment();
 
     static void calculateAlignedStackPointer(void** stackPointer);
 
     // If source is a double, load it into dest. If source is int32,
     // convert it to double. Else, branch to failure.
     void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
 
-    template <typename T1, typename T2>
-    void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        ma_cmp_set(dest, lhs, rhs, cond);
-    }
     void cmpPtrSet(Assembler::Condition cond, Address lhs, ImmPtr rhs, Register dest);
     void cmpPtrSet(Assembler::Condition cond, Register lhs, Address rhs, Register dest);
 
-    template <typename T1, typename T2>
-    void cmp32Set(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        ma_cmp_set(dest, lhs, rhs, cond);
-    }
     void cmp32Set(Assembler::Condition cond, Register lhs, Address rhs, Register dest);
 
     void cmp64Set(Assembler::Condition cond, Register lhs, Imm32 rhs, Register dest)
     {
         ma_cmp_set(dest, lhs, rhs, cond);
     }
 
   protected:
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -451,16 +451,27 @@ MacroAssembler::rotateRight64(Imm32 coun
 void
 MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest, Register temp)
 {
     MOZ_ASSERT(temp == InvalidReg);
     rotateRight64(count, src, dest);
 }
 
 // ===============================================================
+// Condition functions
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    cmpPtr(lhs, rhs);
+    emitSet(cond, dest);
+}
+
+// ===============================================================
 // Bit counting functions
 
 void
 MacroAssembler::clz64(Register64 src, Register dest)
 {
     // On very recent chips (Haswell and newer) there is actually an
     // LZCNT instruction that does all of this.
 
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -508,23 +508,16 @@ class MacroAssemblerX64 : public MacroAs
     }
     void testPtr(Register lhs, Imm32 rhs) {
         testq(rhs, lhs);
     }
     void testPtr(const Operand& lhs, Imm32 rhs) {
         testq(rhs, lhs);
     }
 
-    template <typename T1, typename T2>
-    void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        cmpPtr(lhs, rhs);
-        emitSet(cond, dest);
-    }
-
     /////////////////////////////////////////////////////////////////
     // Common interface.
     /////////////////////////////////////////////////////////////////
 
     CodeOffsetJump jumpWithPatch(RepatchLabel* label, Label* documentation = nullptr) {
         JmpSrc src = jmpSrc(label);
         return CodeOffsetJump(size(), addPatchableJump(src, Relocation::HARDCODED));
     }
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h
@@ -449,16 +449,27 @@ MacroAssembler::rshift32(Imm32 shift, Re
 
 void
 MacroAssembler::rshift32Arithmetic(Imm32 shift, Register srcDest)
 {
     sarl(shift, srcDest);
 }
 
 // ===============================================================
+// Condition functions
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    cmp32(lhs, rhs);
+    emitSet(cond, dest);
+}
+
+// ===============================================================
 // Branch instructions
 
 template <class L>
 void
 MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, L label)
 {
     cmp32(lhs, rhs);
     j(cond, label);
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.h
@@ -1297,23 +1297,16 @@ class MacroAssemblerX86Shared : public A
                 j(Assembler::Parity, &end);
             bind(&ifFalse);
             mov(ImmWord(0), dest);
 
             bind(&end);
         }
     }
 
-    template <typename T1, typename T2>
-    void cmp32Set(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        cmp32(lhs, rhs);
-        emitSet(cond, dest);
-    }
-
     // Emit a JMP that can be toggled to a CMP. See ToggleToJmp(), ToggleToCmp().
     CodeOffset toggledJump(Label* label) {
         CodeOffset offset(size());
         jump(label);
         return offset;
     }
 
     template <typename T>
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -606,16 +606,27 @@ MacroAssembler::popcnt64(Register64 src,
         popcnt32(src.low, dest.high, tmp);
         popcnt32(src.high, dest.low, tmp);
     }
     addl(dest.high, dest.low);
     xorl(dest.high, dest.high);
 }
 
 // ===============================================================
+// Condition functions
+
+template <typename T1, typename T2>
+void
+MacroAssembler::cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
+{
+    cmpPtr(lhs, rhs);
+    emitSet(cond, dest);
+}
+
+// ===============================================================
 // Branch functions
 
 void
 MacroAssembler::branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
 {
     cmp32(Operand(lhs), rhs);
     j(cond, label);
 }
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -548,23 +548,16 @@ class MacroAssemblerX86 : public MacroAs
     }
     void testPtr(const Operand& lhs, Imm32 rhs) {
         test32(lhs, rhs);
     }
     void testPtr(const Operand& lhs, ImmWord rhs) {
         test32(lhs, Imm32(rhs.value));
     }
 
-    template <typename T1, typename T2>
-    void cmpPtrSet(Assembler::Condition cond, T1 lhs, T2 rhs, Register dest)
-    {
-        cmpPtr(lhs, rhs);
-        emitSet(cond, dest);
-    }
-
     /////////////////////////////////////////////////////////////////
     // Common interface.
     /////////////////////////////////////////////////////////////////
 
     template <typename T, typename S>
     void branchPtr(Condition cond, T lhs, S ptr, RepatchLabel* label) {
         cmpPtr(Operand(lhs), ptr);
         j(cond, label);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -373,17 +373,17 @@ static const JSPropertySpec function_pro
     JS_PSGS("arguments", ArgumentsGetter, ArgumentsSetter, 0),
     JS_PSGS("caller", CallerGetter, CallerSetter, 0),
     JS_PS_END
 };
 
 static bool
 ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id)
 {
-    MOZ_ASSERT(fun->isInterpreted() || fun->isWasmNative());
+    MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative());
     MOZ_ASSERT(id == NameToId(cx->names().prototype));
 
     // Assert that fun is not a compiler-created function object, which
     // must never leak to script or embedding code and then be mutated.
     // Also assert that fun is not bound, per the ES5 15.3.4.5 ref above.
     MOZ_ASSERT(!IsInternalFunctionObject(*fun));
     MOZ_ASSERT(!fun->isBoundFunction());
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -35,17 +35,17 @@ class JSFunction : public js::NativeObje
 
     enum FunctionKind {
         NormalFunction = 0,
         Arrow,                      /* ES6 '(args) => body' syntax */
         Method,                     /* ES6 MethodDefinition */
         ClassConstructor,
         Getter,
         Setter,
-        Wasm,                       /* function is wasm module or exported function */
+        AsmJS,                      /* function is an asm.js module or exported function */
         FunctionKindLimit
     };
 
     enum Flags {
         INTERPRETED      = 0x0001,  /* function has a JSScript and environment. */
         CONSTRUCTOR      = 0x0002,  /* function that can be called as a constructor */
         EXTENDED         = 0x0004,  /* structure is FunctionExtended */
         BOUND_FUN        = 0x0008,  /* function was created with Function.prototype.bind. */
@@ -61,29 +61,29 @@ class JSFunction : public js::NativeObje
         HAS_REST         = 0x0100,  /* function has a rest (...) parameter */
         INTERPRETED_LAZY = 0x0200,  /* function is interpreted but doesn't have a script yet */
         RESOLVED_LENGTH  = 0x0400,  /* f.length has been resolved (see fun_resolve). */
         RESOLVED_NAME    = 0x0800,  /* f.name has been resolved (see fun_resolve). */
 
         FUNCTION_KIND_SHIFT = 13,
         FUNCTION_KIND_MASK  = 0x7 << FUNCTION_KIND_SHIFT,
 
-        WASM_KIND = Wasm << FUNCTION_KIND_SHIFT,
+        ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
         ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
         METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
         CLASSCONSTRUCTOR_KIND = ClassConstructor << FUNCTION_KIND_SHIFT,
         GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
         SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
 
         /* Derived Flags values for convenience: */
         NATIVE_FUN = 0,
         NATIVE_CTOR = NATIVE_FUN | CONSTRUCTOR,
         NATIVE_CLASS_CTOR = NATIVE_FUN | CONSTRUCTOR | CLASSCONSTRUCTOR_KIND,
-        WASM_CTOR = WASM_KIND | NATIVE_CTOR,
-        ASMJS_LAMBDA_CTOR = WASM_KIND | NATIVE_CTOR | LAMBDA,
+        ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
+        ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
         INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
         INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND,
         INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
         INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
         INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
         INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
         INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
         INTERPRETED_LAMBDA_GENERATOR = INTERPRETED | LAMBDA,
@@ -168,17 +168,17 @@ class JSFunction : public js::NativeObje
 
     /* A function can be classified as either native (C++) or interpreted (JS): */
     bool isInterpreted()            const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
     bool isNative()                 const { return !isInterpreted(); }
 
     bool isConstructor()            const { return flags() & CONSTRUCTOR; }
 
     /* Possible attributes of a native function: */
-    bool isWasmNative()            const { return kind() == Wasm; }
+    bool isAsmJSNative()            const { return kind() == AsmJS; }
 
     /* Possible attributes of an interpreted function: */
     bool isExprBody()               const { return flags() & EXPR_BODY; }
     bool hasGuessedAtom()           const { return flags() & HAS_GUESSED_ATOM; }
     bool isLambda()                 const { return flags() & LAMBDA; }
     bool isBoundFunction()          const { return flags() & BOUND_FUN; }
     bool hasRest()                  const { return flags() & HAS_REST; }
     bool isInterpretedLazy()        const { return flags() & INTERPRETED_LAZY; }
@@ -210,17 +210,17 @@ class JSFunction : public js::NativeObje
         if (!hasScript())
             return false;
 
         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
     }
 
     /* Compound attributes: */
     bool isBuiltin() const {
-        return (isNative() && !isWasmNative()) || isSelfHostedBuiltin();
+        return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin();
     }
 
     bool isNamedLambda() const {
         return isLambda() && displayAtom() && !hasGuessedAtom();
     }
 
     bool hasLexicalThis() const {
         return isArrow() || nonLazyScript()->isGeneratorExp();
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -786,17 +786,17 @@ js::XDRScript(XDRState<mode>* xdr, Handl
             if (mode == XDR_ENCODE) {
                 RootedFunction function(cx, &(*objp)->as<JSFunction>());
 
                 if (function->isInterpretedLazy()) {
                     funEnclosingScope = function->lazyScript()->enclosingScope();
                 } else if (function->isInterpreted()) {
                     funEnclosingScope = function->nonLazyScript()->enclosingScope();
                 } else {
-                    MOZ_ASSERT(function->isWasmNative());
+                    MOZ_ASSERT(function->isAsmJSNative());
                     return xdr->fail(JS::TranscodeResult_Failure_AsmJSNotSupported);
                 }
 
                 funEnclosingScopeIndex = FindScopeIndex(script, *funEnclosingScope);
             }
 
             if (!xdr->codeUint32(&funEnclosingScopeIndex))
                 return false;
@@ -3205,17 +3205,17 @@ js::detail::CopyScript(JSContext* cx, Ha
             obj = vector[i];
             clone = nullptr;
             if (obj->is<RegExpObject>()) {
                 clone = CloneScriptRegExpObject(cx, obj->as<RegExpObject>());
             } else if (obj->is<JSFunction>()) {
                 RootedFunction innerFun(cx, &obj->as<JSFunction>());
                 if (innerFun->isNative()) {
                     if (cx->compartment() != innerFun->compartment()) {
-                        MOZ_ASSERT(innerFun->isWasmNative());
+                        MOZ_ASSERT(innerFun->isAsmJSNative());
                         JS_ReportErrorASCII(cx, "AsmJS modules do not yet support cloning.");
                         return false;
                     }
                     clone = innerFun;
                 } else {
                     if (innerFun->isInterpretedLazy()) {
                         AutoCompartment ac(cx, innerFun);
                         if (!innerFun->getOrCreateScript(cx))
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -8147,17 +8147,17 @@ InstantiateAsmJS(JSContext* cx, unsigned
 }
 
 static JSFunction*
 NewAsmJSModuleFunction(ExclusiveContext* cx, JSFunction* origFun, HandleObject moduleObj)
 {
     RootedAtom name(cx, origFun->name());
 
     JSFunction::Flags flags = origFun->isLambda() ? JSFunction::ASMJS_LAMBDA_CTOR
-                                                  : JSFunction::WASM_CTOR;
+                                                  : JSFunction::ASMJS_CTOR;
     JSFunction* moduleFun =
         NewNativeConstructor(cx, InstantiateAsmJS, origFun->nargs(), name,
                              gc::AllocKind::FUNCTION_EXTENDED, TenuredObject,
                              flags);
     if (!moduleFun)
         return nullptr;
 
     moduleFun->setExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT, ObjectValue(*moduleObj));
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -186,32 +186,32 @@ static const Register StackPointer = Rea
 #ifdef JS_CODEGEN_X86
 // The selection of EBX here steps gingerly around: the need for EDX
 // to be allocatable for multiply/divide; ECX to be allocatable for
 // shift/rotate; EAX (= ReturnReg) to be allocatable as the joinreg;
 // EBX not being one of the WasmTableCall registers; and needing a
 // temp register for load/store that has a single-byte persona.
 static const Register ScratchRegX86 = ebx;
 
-# define QUOT_REM_I64_CALLOUT
+# define INT_DIV_I64_CALLOUT
 #endif
 
 #ifdef JS_CODEGEN_ARM
 // We need a temp for funcPtrCall.  It can't be any of the
 // WasmTableCall registers, an argument register, or a scratch
 // register, and probably should not be ReturnReg.
 static const Register FuncPtrCallTemp = CallTempReg1;
 
 // We use our own scratch register, because the macro assembler uses
 // the regular scratch register(s) pretty liberally.  We could
 // work around that in several cases but the mess does not seem
 // worth it yet.  CallTempReg2 seems safe.
 static const Register ScratchRegARM = CallTempReg2;
 
-# define QUOT_REM_I64_CALLOUT
+# define INT_DIV_I64_CALLOUT
 # define I64_TO_FLOAT_CALLOUT
 # define FLOAT_TO_I64_CALLOUT
 #endif
 
 class BaseCompiler
 {
     // We define our own ScratchRegister abstractions, deferring to
     // the platform's when possible.
@@ -940,21 +940,17 @@ class BaseCompiler
         return RegI64(invalidRegister64());
     }
 
     RegF64 invalidF64() {
         return RegF64(InvalidFloatReg);
     }
 
     RegI32 fromI64(RegI64 r) {
-#ifdef JS_PUNBOX64
-        return RegI32(r.reg.reg);
-#else
-        return RegI32(r.reg.low);
-#endif
+        return RegI32(lowPart(r));
     }
 
     RegI64 widenI32(RegI32 r) {
         MOZ_ASSERT(!isAvailable(r.reg));
 #ifdef JS_PUNBOX64
         return RegI64(Register64(r.reg));
 #else
         RegI32 high = needI32();
@@ -995,18 +991,16 @@ class BaseCompiler
     void freeI64Except(RegI64 r, RegI32 except) {
 #ifdef JS_PUNBOX64
         MOZ_ASSERT(r.reg.reg == except.reg);
 #else
         MOZ_ASSERT(r.reg.high == except.reg || r.reg.low == except.reg);
         freeI64(r);
         needI32(except);
 #endif
-
-
     }
 
     void freeF64(RegF64 r) {
         freeFPU(r.reg);
     }
 
     void freeF32(RegF32 r) {
         freeFPU(r.reg);
@@ -2517,29 +2511,20 @@ class BaseCompiler
             masm.move32(Imm32(0), srcDest.reg);
             masm.jump(done);
             masm.bind(&notDivByZero);
         } else {
             masm.branchTest32(Assembler::Zero, rhs.reg, rhs.reg, trap(Trap::IntegerDivideByZero));
         }
     }
 
-    void checkDivideByZeroI64(RegI64 rhs, RegI64 srcDest, Label* done) {
+    void checkDivideByZeroI64(RegI64 r) {
         MOZ_ASSERT(!isCompilingAsmJS());
-#if defined(JS_CODEGEN_X64)
-        masm.testq(rhs.reg.reg, rhs.reg.reg);
-        masm.j(Assembler::Zero, trap(Trap::IntegerDivideByZero));
-#elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
-        Label nonZero;
-        masm.branchTest32(Assembler::NonZero, rhs.reg.low, rhs.reg.low, &nonZero);
-        masm.branchTest32(Assembler::Zero, rhs.reg.high, rhs.reg.high, trap(Trap::IntegerDivideByZero));
-        masm.bind(&nonZero);
-#else
-        MOZ_CRASH("BaseCompiler platform hook: checkDivideByZeroI64");
-#endif
+        ScratchI32 scratch(*this);
+        masm.branchTest64(Assembler::Zero, r.reg, r.reg, scratch, trap(Trap::IntegerDivideByZero));
     }
 
     void checkDivideSignedOverflowI32(RegI32 rhs, RegI32 srcDest, Label* done, bool zeroOnOverflow) {
         Label notMin;
         masm.branch32(Assembler::NotEqual, srcDest.reg, Imm32(INT32_MIN), &notMin);
         if (zeroOnOverflow) {
             masm.branch32(Assembler::NotEqual, rhs.reg, Imm32(-1), &notMin);
             masm.move32(Imm32(0), srcDest.reg);
@@ -2549,38 +2534,34 @@ class BaseCompiler
             masm.branch32(Assembler::Equal, rhs.reg, Imm32(-1), done);
         } else {
             masm.branch32(Assembler::Equal, rhs.reg, Imm32(-1), trap(Trap::IntegerOverflow));
         }
         masm.bind(&notMin);
     }
 
     void checkDivideSignedOverflowI64(RegI64 rhs, RegI64 srcDest, Label* done, bool zeroOnOverflow) {
-#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
         MOZ_ASSERT(!isCompilingAsmJS());
         Label notmin;
         masm.branch64(Assembler::NotEqual, srcDest.reg, Imm64(INT64_MIN), &notmin);
         masm.branch64(Assembler::NotEqual, rhs.reg, Imm64(-1), &notmin);
         if (zeroOnOverflow) {
             masm.xor64(srcDest.reg, srcDest.reg);
             masm.jump(done);
         } else {
             masm.jump(trap(Trap::IntegerOverflow));
         }
         masm.bind(&notmin);
-#else
-        MOZ_CRASH("BaseCompiler platform hook: checkDivideSignedOverflowI64");
-#endif
-    }
-
-#ifndef QUOT_REM_I64_CALLOUT
+    }
+
+#ifndef INT_DIV_I64_CALLOUT
     void quotientI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned) {
         Label done;
 
-        checkDivideByZeroI64(rhs, srcDest, &done);
+        checkDivideByZeroI64(rhs);
 
         if (!isUnsigned)
             checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(false));
 
 # if defined(JS_CODEGEN_X64)
         // The caller must set up the following situation.
         MOZ_ASSERT(srcDest.reg.reg == rax);
         MOZ_ASSERT(isAvailable(rdx));
@@ -2595,17 +2576,17 @@ class BaseCompiler
         MOZ_CRASH("BaseCompiler platform hook: quotientI64");
 # endif
         masm.bind(&done);
     }
 
     void remainderI64(RegI64 rhs, RegI64 srcDest, IsUnsigned isUnsigned) {
         Label done;
 
-        checkDivideByZeroI64(rhs, srcDest, &done);
+        checkDivideByZeroI64(rhs);
 
         if (!isUnsigned)
             checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(true));
 
 # if defined(JS_CODEGEN_X64)
         // The caller must set up the following situation.
         MOZ_ASSERT(srcDest.reg.reg == rax);
         MOZ_ASSERT(isAvailable(rdx));
@@ -2618,17 +2599,17 @@ class BaseCompiler
             masm.idivq(rhs.reg.reg);
         }
         masm.movq(rdx, rax);
 # else
         MOZ_CRASH("BaseCompiler platform hook: remainderI64");
 # endif
         masm.bind(&done);
     }
-#endif
+#endif // INT_DIV_I64_CALLOUT
 
     void pop2xI32ForShiftOrRotate(RegI32* r0, RegI32* r1) {
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
         *r1 = popI32(specific_ecx);
         *r0 = popI32();
 #else
         pop2xI32(r0, r1);
 #endif
@@ -2707,29 +2688,42 @@ class BaseCompiler
         masm.movl(src.reg.reg, dest.reg);
 #elif defined(JS_NUNBOX32)
         masm.move32(src.reg.low, dest.reg);
 #else
         MOZ_CRASH("BaseCompiler platform hook: wrapI64ToI32");
 #endif
     }
 
-    void extendI32ToI64(RegI32 src, RegI64 dest) {
+    RegI64 popI32ForSignExtendI64() {
+#if defined(JS_CODEGEN_X86)
+        need2xI32(specific_edx, specific_eax);
+        RegI32 r0 = popI32ToSpecific(specific_eax);
+        RegI64 x0 = RegI64(Register64(specific_edx.reg, specific_eax.reg));
+        (void)r0;               // x0 is the widening of r0
+#else
+        RegI32 r0 = popI32();
+        RegI64 x0 = widenI32(r0);
+#endif
+        return x0;
+    }
+
+    void signExtendI32ToI64(RegI32 src, RegI64 dest) {
 #if defined(JS_CODEGEN_X64)
         masm.movslq(src.reg, dest.reg.reg);
 #elif defined(JS_CODEGEN_X86)
         MOZ_ASSERT(dest.reg.low == src.reg);
         MOZ_ASSERT(dest.reg.low == eax);
         MOZ_ASSERT(dest.reg.high == edx);
         masm.cdq();
 #elif defined(JS_CODEGEN_ARM)
         masm.ma_mov(src.reg, dest.reg.low);
         masm.ma_asr(Imm32(31), src.reg, dest.reg.high);
 #else
-        MOZ_CRASH("BaseCompiler platform hook: extendI32ToI64");
+        MOZ_CRASH("BaseCompiler platform hook: signExtendI32ToI64");
 #endif
     }
 
     void extendU32ToI64(RegI32 src, RegI64 dest) {
 #if defined(JS_CODEGEN_X64)
         masm.movl(src.reg, dest.reg.reg);
 #elif defined(JS_NUNBOX32)
         masm.move32(src.reg, dest.reg.low);
@@ -2918,17 +2912,17 @@ class BaseCompiler
         else
             masm.wasmTruncateDoubleToInt64(src.reg, dest.reg, ool->entry(),
                                            ool->rejoin(), temp.reg);
 # else
         MOZ_CRASH("BaseCompiler platform hook: truncateF64ToI64");
 # endif
         return true;
     }
-#endif
+#endif // FLOAT_TO_I64_CALLOUT
 
 #ifndef I64_TO_FLOAT_CALLOUT
     bool convertI64ToFloatNeedsTemp(bool isUnsigned) const {
 # if defined(JS_CODEGEN_X86)
         return isUnsigned && AssemblerX86Shared::HasSSE3();
 # else
         return false;
 # endif
@@ -2950,17 +2944,17 @@ class BaseCompiler
         if (isUnsigned)
             masm.convertUInt64ToDouble(src.reg, dest.reg, temp.reg);
         else
             masm.convertInt64ToDouble(src.reg, dest.reg);
 # else
         MOZ_CRASH("BaseCompiler platform hook: convertI64ToF64");
 # endif
     }
-#endif
+#endif // I64_TO_FLOAT_CALLOUT
 
     void cmp64Set(Assembler::Condition cond, RegI64 lhs, RegI64 rhs, RegI32 dest) {
 #if defined(JS_CODEGEN_X64)
         masm.cmpq(rhs.reg.reg, lhs.reg.reg);
         masm.emitSet(cond, dest.reg);
 #elif defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_ARM)
         // TODO / OPTIMIZE: This is pretty branchy, we should be able to do better.
         Label done, condTrue;
@@ -3181,27 +3175,24 @@ class BaseCompiler
             Unused << viewType;
             Unused << dest;
             MOZ_CRASH("Compiler bug: Unexpected platform.");
 # endif
         }
     };
 #endif
 
-  private:
     void checkOffset(MemoryAccessDesc* access, RegI32 ptr) {
         if (access->offset() >= OffsetGuardLimit) {
-            masm.branchAdd32(Assembler::CarrySet,
-                             Imm32(access->offset()), ptr.reg,
+            masm.branchAdd32(Assembler::CarrySet, Imm32(access->offset()), ptr.reg,
                              trap(Trap::OutOfBounds));
             access->clearOffset();
         }
     }
 
-  public:
     // This is the temp register passed as the last argument to load()
     MOZ_MUST_USE size_t loadStoreTemps(MemoryAccessDesc& access) {
 #if defined(JS_CODEGEN_ARM)
         if (access.isUnaligned()) {
             switch (access.type()) {
               case Scalar::Float32:
                 return 1;
               case Scalar::Float64:
@@ -3500,17 +3491,17 @@ class BaseCompiler
             masm.emitUnalignedStore(ByteSize(4), ptr.reg, tmp1.reg, 0);
             masm.emitUnalignedStore(ByteSize(4), ptr.reg, tmp2.reg, 4);
         } else {
             BufferOffset st =
                 masm.ma_vstr(src.reg, VFPAddr(ptr.reg, VFPOffImm(0)), Assembler::Always);
             masm.append(access, st.getOffset(), masm.framePushed());
         }
     }
-#endif
+#endif // JS_CODEGEN_ARM
 
     ////////////////////////////////////////////////////////////
 
     // Generally speaking, ABOVE this point there should be no value
     // stack manipulation (calls to popI32 etc).
 
     // Generally speaking, BELOW this point there should be no
     // platform dependencies.  We make an exception for x86 register
@@ -3592,17 +3583,17 @@ class BaseCompiler
     MOZ_MUST_USE bool emitReturn();
     MOZ_MUST_USE bool emitCallArgs(const ValTypeVector& args, FunctionCall& baselineCall);
     MOZ_MUST_USE bool emitCall();
     MOZ_MUST_USE bool emitCallIndirect(bool oldStyle);
     MOZ_MUST_USE bool emitCommonMathCall(uint32_t lineOrBytecode, SymbolicAddress callee,
                                          ValTypeVector& signature, ExprType retType);
     MOZ_MUST_USE bool emitUnaryMathBuiltinCall(SymbolicAddress callee, ValType operandType);
     MOZ_MUST_USE bool emitBinaryMathBuiltinCall(SymbolicAddress callee, ValType operandType);
-#ifdef QUOT_REM_I64_CALLOUT
+#ifdef INT_DIV_I64_CALLOUT
     MOZ_MUST_USE bool emitDivOrModI64BuiltinCall(SymbolicAddress callee, ValType operandType);
 #endif
     MOZ_MUST_USE bool emitGetLocal();
     MOZ_MUST_USE bool emitSetLocal();
     MOZ_MUST_USE bool emitTeeLocal();
     MOZ_MUST_USE bool emitGetGlobal();
     MOZ_MUST_USE bool emitSetGlobal();
     MOZ_MUST_USE bool emitTeeGlobal();
@@ -3636,17 +3627,17 @@ class BaseCompiler
     void emitMultiplyI32();
     void emitMultiplyI64();
     void emitMultiplyF32();
     void emitMultiplyF64();
     void emitQuotientI32();
     void emitQuotientU32();
     void emitRemainderI32();
     void emitRemainderU32();
-#ifndef QUOT_REM_I64_CALLOUT
+#ifndef INT_DIV_I64_CALLOUT
     void emitQuotientI64();
     void emitQuotientU64();
     void emitRemainderI64();
     void emitRemainderU64();
 #endif
     void emitDivideF32();
     void emitDivideF64();
     void emitMinI32();
@@ -3688,49 +3679,47 @@ class BaseCompiler
     void emitAbsF64();
     void emitNegateI32();
     void emitNegateF32();
     void emitNegateF64();
     void emitSqrtF32();
     void emitSqrtF64();
     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF32ToI32();
     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF64ToI32();
-#ifndef FLOAT_TO_I64_CALLOUT
+#ifdef FLOAT_TO_I64_CALLOUT
+    MOZ_MUST_USE bool emitConvertFloatingToInt64Callout(SymbolicAddress callee, ValType operandType,
+                                                        ValType resultType);
+#else
     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF32ToI64();
     template<bool isUnsigned> MOZ_MUST_USE bool emitTruncateF64ToI64();
 #endif
     void emitWrapI64ToI32();
     void emitExtendI32ToI64();
     void emitExtendU32ToI64();
     void emitReinterpretF32AsI32();
     void emitReinterpretF64AsI64();
     void emitConvertF64ToF32();
     void emitConvertI32ToF32();
     void emitConvertU32ToF32();
     void emitConvertF32ToF64();
     void emitConvertI32ToF64();
     void emitConvertU32ToF64();
-#ifndef I64_TO_FLOAT_CALLOUT
+#ifdef I64_TO_FLOAT_CALLOUT
+    MOZ_MUST_USE bool emitConvertInt64ToFloatingCallout(SymbolicAddress callee, ValType operandType,
+                                                        ValType resultType);
+#else
     void emitConvertI64ToF32();
     void emitConvertU64ToF32();
     void emitConvertI64ToF64();
     void emitConvertU64ToF64();
 #endif
     void emitReinterpretI32AsF32();
     void emitReinterpretI64AsF64();
     MOZ_MUST_USE bool emitGrowMemory();
     MOZ_MUST_USE bool emitCurrentMemory();
-#ifdef I64_TO_FLOAT_CALLOUT
-    MOZ_MUST_USE bool emitConvertInt64ToFloatingCallout(SymbolicAddress callee, ValType operandType,
-                                                        ValType resultType);
-#endif
-#ifdef FLOAT_TO_I64_CALLOUT
-    MOZ_MUST_USE bool emitConvertFloatingToInt64Callout(SymbolicAddress callee, ValType operandType,
-                                                        ValType resultType);
-#endif
 };
 
 void
 BaseCompiler::emitAddI32()
 {
     int32_t c;
     if (popConstI32(c)) {
         RegI32 r = popI32();
@@ -3905,46 +3894,16 @@ BaseCompiler::emitQuotientU32()
     checkDivideByZeroI32(r1, r0, &done);
     masm.quotient32(r1.reg, r0.reg, IsUnsigned(true));
     masm.bind(&done);
 
     freeI32(r1);
     pushI32(r0);
 }
 
-#ifndef QUOT_REM_I64_CALLOUT
-void
-BaseCompiler::emitQuotientI64()
-{
-# ifdef JS_PUNBOX64
-    RegI64 r0, r1;
-    pop2xI64ForIntDiv(&r0, &r1);
-    quotientI64(r1, r0, IsUnsigned(false));
-    freeI64(r1);
-    pushI64(r0);
-# else
-    MOZ_CRASH("BaseCompiler platform hook: emitQuotientI64");
-# endif
-}
-
-void
-BaseCompiler::emitQuotientU64()
-{
-# ifdef JS_PUNBOX64
-    RegI64 r0, r1;
-    pop2xI64ForIntDiv(&r0, &r1);
-    quotientI64(r1, r0, IsUnsigned(true));
-    freeI64(r1);
-    pushI64(r0);
-# else
-    MOZ_CRASH("BaseCompiler platform hook: emitQuotientU64");
-# endif
-}
-#endif
-
 void
 BaseCompiler::emitRemainderI32()
 {
     // TODO / OPTIMIZE: Fast case if lhs >= 0 and rhs is power of two.
     RegI32 r0, r1;
     pop2xI32ForIntMulDiv(&r0, &r1);
 
     Label done;
@@ -3968,17 +3927,45 @@ BaseCompiler::emitRemainderU32()
     checkDivideByZeroI32(r1, r0, &done);
     masm.remainder32(r1.reg, r0.reg, IsUnsigned(true));
     masm.bind(&done);
 
     freeI32(r1);
     pushI32(r0);
 }
 
-#ifndef QUOT_REM_I64_CALLOUT
+#ifndef INT_DIV_I64_CALLOUT
+void
+BaseCompiler::emitQuotientI64()
+{
+# ifdef JS_PUNBOX64
+    RegI64 r0, r1;
+    pop2xI64ForIntDiv(&r0, &r1);
+    quotientI64(r1, r0, IsUnsigned(false));
+    freeI64(r1);
+    pushI64(r0);
+# else
+    MOZ_CRASH("BaseCompiler platform hook: emitQuotientI64");
+# endif
+}
+
+void
+BaseCompiler::emitQuotientU64()
+{
+# ifdef JS_PUNBOX64
+    RegI64 r0, r1;
+    pop2xI64ForIntDiv(&r0, &r1);
+    quotientI64(r1, r0, IsUnsigned(true));
+    freeI64(r1);
+    pushI64(r0);
+# else
+    MOZ_CRASH("BaseCompiler platform hook: emitQuotientU64");
+# endif
+}
+
 void
 BaseCompiler::emitRemainderI64()
 {
 # ifdef JS_PUNBOX64
     RegI64 r0, r1;
     pop2xI64ForIntDiv(&r0, &r1);
     remainderI64(r1, r0, IsUnsigned(false));
     freeI64(r1);
@@ -3996,17 +3983,17 @@ BaseCompiler::emitRemainderU64()
     pop2xI64ForIntDiv(&r0, &r1);
     remainderI64(r1, r0, IsUnsigned(true));
     freeI64(r1);
     pushI64(r0);
 # else
     MOZ_CRASH("BaseCompiler platform hook: emitRemainderU64");
 # endif
 }
-#endif
+#endif // INT_DIV_I64_CALLOUT
 
 void
 BaseCompiler::emitDivideF32()
 {
     RegF32 r0, r1;
     pop2xF32(&r0, &r1);
     masm.divFloat32(r1.reg, r0.reg);
     freeF32(r1);
@@ -4574,40 +4561,34 @@ BaseCompiler::emitTruncateF64ToI64()
     } else {
         if (!truncateF64ToI64(r0, x0, isUnsigned, invalidF64()))
             return false;
     }
     freeF64(r0);
     pushI64(x0);
     return true;
 }
-#endif
+#endif // FLOAT_TO_I64_CALLOUT
 
 void
 BaseCompiler::emitWrapI64ToI32()
 {
     RegI64 r0 = popI64();
     RegI32 i0 = fromI64(r0);
     wrapI64ToI32(r0, i0);
     freeI64Except(r0, i0);
     pushI32(i0);
 }
 
 void
 BaseCompiler::emitExtendI32ToI64()
 {
-#if defined(JS_CODEGEN_X86)
-    need2xI32(specific_edx, specific_eax);
-    RegI32 r0 = popI32ToSpecific(specific_eax);
-    RegI64 x0 = RegI64(Register64(specific_edx.reg, specific_eax.reg));
-#else
-    RegI32 r0 = popI32();
-    RegI64 x0 = widenI32(r0);
-#endif
-    extendI32ToI64(r0, x0);
+    RegI64 x0 = popI32ForSignExtendI64();
+    RegI32 r0 = RegI32(lowPart(x0));
+    signExtendI32ToI64(r0, x0);
     pushI64(x0);
     // Note: no need to free r0, since it is part of x0
 }
 
 void
 BaseCompiler::emitExtendU32ToI64()
 {
     RegI32 r0 = popI32();
@@ -4744,17 +4725,17 @@ BaseCompiler::emitConvertU64ToF64()
     if (convertI64ToFloatNeedsTemp(IsUnsigned(true)))
         temp = needI32();
     convertI64ToF64(r0, IsUnsigned(true), d0, temp);
     if (temp.reg != Register::Invalid())
         freeI32(temp);
     freeI64(r0);
     pushF64(d0);
 }
-#endif
+#endif // I64_TO_FLOAT_CALLOUT
 
 void
 BaseCompiler::emitReinterpretI32AsF32()
 {
     RegI32 r0 = popI32();
     RegF32 f0 = needF32();
     masm.moveGPRToFloat32(r0.reg, f0.reg);
     freeI32(r0);
@@ -5520,17 +5501,17 @@ BaseCompiler::emitBinaryMathBuiltinCall(
     }
 
     if (deadCode_)
         return true;
 
     return emitCommonMathCall(lineOrBytecode, callee, SigDD_, ExprType::F64);
 }
 
-#ifdef QUOT_REM_I64_CALLOUT
+#ifdef INT_DIV_I64_CALLOUT
 bool
 BaseCompiler::emitDivOrModI64BuiltinCall(SymbolicAddress callee, ValType operandType)
 {
     MOZ_ASSERT(operandType == ValType::I64);
 
     if (deadCode_)
         return true;
 
@@ -5539,17 +5520,17 @@ BaseCompiler::emitDivOrModI64BuiltinCall
     needI64(abiReturnRegI64);
 
     RegI32 temp = needI32();
     RegI64 rhs = popI64();
     RegI64 srcDest = popI64ToSpecific(abiReturnRegI64);
 
     Label done;
 
-    checkDivideByZeroI64(rhs, srcDest, &done);
+    checkDivideByZeroI64(rhs);
 
     if (callee == SymbolicAddress::DivI64)
         checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(false));
     else if (callee == SymbolicAddress::ModI64)
         checkDivideSignedOverflowI64(rhs, srcDest, &done, ZeroOnOverflow(true));
 
     masm.setupUnalignedABICall(temp.reg);
     masm.passABIArg(srcDest.reg.high);
@@ -5561,17 +5542,17 @@ BaseCompiler::emitDivOrModI64BuiltinCall
     masm.bind(&done);
 
     freeI32(temp);
     freeI64(rhs);
     pushI64(srcDest);
 
     return true;
 }
-#endif
+#endif // INT_DIV_I64_CALLOUT
 
 #ifdef I64_TO_FLOAT_CALLOUT
 bool
 BaseCompiler::emitConvertInt64ToFloatingCallout(SymbolicAddress callee, ValType operandType,
                                                 ValType resultType)
 {
     sync();
 
@@ -5600,17 +5581,17 @@ BaseCompiler::emitConvertInt64ToFloating
         freeF64(rv);
         pushF32(rv2);
     } else {
         pushF64(rv);
     }
 
     return true;
 }
-#endif
+#endif // I64_TO_FLOAT_CALLOUT
 
 #ifdef FLOAT_TO_I64_CALLOUT
 // `Callee` always takes a double, so a float32 input must be converted.
 bool
 BaseCompiler::emitConvertFloatingToInt64Callout(SymbolicAddress callee, ValType operandType,
                                                 ValType resultType)
 {
     RegF64 doubleInput;
@@ -5657,17 +5638,17 @@ BaseCompiler::emitConvertFloatingToInt64
     masm.branch64(Assembler::Equal, rv.reg, Imm64(0x8000000000000000), ool->entry());
     masm.bind(ool->rejoin());
 
     pushI64(rv);
     freeF64(inputVal);
 
     return true;
 }
-#endif
+#endif // FLOAT_TO_I64_CALLOUT
 
 bool
 BaseCompiler::emitGetLocal()
 {
     uint32_t slot;
     if (!iter_.readGetLocal(locals_, &slot))
         return false;
 
@@ -6730,35 +6711,35 @@ BaseCompiler::emitBody()
           }
           case Expr::I64Add:
             CHECK_NEXT(emitBinary(emitAddI64, ValType::I64));
           case Expr::I64Sub:
             CHECK_NEXT(emitBinary(emitSubtractI64, ValType::I64));
           case Expr::I64Mul:
             CHECK_NEXT(emitBinary(emitMultiplyI64, ValType::I64));
           case Expr::I64DivS:
-#ifdef QUOT_REM_I64_CALLOUT
+#ifdef INT_DIV_I64_CALLOUT
             CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::DivI64, ValType::I64));
 #else
             CHECK_NEXT(emitBinary(emitQuotientI64, ValType::I64));
 #endif
           case Expr::I64DivU:
-#ifdef QUOT_REM_I64_CALLOUT
+#ifdef INT_DIV_I64_CALLOUT
             CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::UDivI64, ValType::I64));
 #else
             CHECK_NEXT(emitBinary(emitQuotientU64, ValType::I64));
 #endif
           case Expr::I64RemS:
-#ifdef QUOT_REM_I64_CALLOUT
+#ifdef INT_DIV_I64_CALLOUT
             CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::ModI64, ValType::I64));
 #else
             CHECK_NEXT(emitBinary(emitRemainderI64, ValType::I64));
 #endif
           case Expr::I64RemU:
-#ifdef QUOT_REM_I64_CALLOUT
+#ifdef INT_DIV_I64_CALLOUT
             CHECK_NEXT(emitDivOrModI64BuiltinCall(SymbolicAddress::UModI64, ValType::I64));
 #else
             CHECK_NEXT(emitBinary(emitRemainderU64, ValType::I64));
 #endif
           case Expr::I64TruncSF32:
 #ifdef FLOAT_TO_I64_CALLOUT
             CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
                                                 SymbolicAddress::TruncateDoubleToInt64,
@@ -7192,23 +7173,16 @@ BaseCompiler::emitFunction()
         return false;
 
     beginFunction();
 
     UniquePooledLabel functionEnd(newLabel());
     if (!pushControl(&functionEnd))
         return false;
 
-#ifdef JS_CODEGEN_ARM64
-    // FIXME: There is a hack up at the top to allow the baseline
-    // compiler to compile on ARM64 (by defining StackPointer), but
-    // the resulting code cannot run.  So prevent it from running.
-    MOZ_CRASH("Several adjustments required for ARM64 operation");
-#endif
-
     if (!emitBody())
         return false;
 
     if (!iter_.readFunctionEnd())
         return false;
 
     if (!endFunction())
         return false;
@@ -7458,11 +7432,11 @@ js::wasm::BaselineCompileFunction(IonCom
     if (!f.emitFunction())
         return false;
 
     f.finish();
 
     return true;
 }
 
-#undef QUOT_REM_I64_CALLOUT
+#undef INT_DIV_I64_CALLOUT
 #undef I64_TO_FLOAT_CALLOUT
 #undef FLOAT_TO_I64_CALLOUT
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -651,21 +651,21 @@ Instance::callExport(JSContext* cx, uint
         JitActivation jitActivation(cx, /* active */ false);
 
         // Call the per-exported-function trampoline created by GenerateEntry.
         auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeBase() + func.entryOffset());
         if (!CALL_GENERATED_2(funcPtr, exportArgs.begin(), &tlsData_))
             return false;
     }
 
-    if (args.isConstructing()) {
-        // By spec, when a function is called as a constructor and this function
-        // returns a primary type, which is the case for all wasm exported
-        // functions, the returned value is discarded and an empty object is
-        // returned instead.
+    if (isAsmJS() && args.isConstructing()) {
+        // By spec, when a JS function is called as a constructor and this
+        // function returns a primary type, which is the case for all asm.js
+        // exported functions, the returned value is discarded and an empty
+        // object is returned instead.
         PlainObject* obj = NewBuiltinClassInstance<PlainObject>(cx);
         if (!obj)
             return false;
         args.rval().set(ObjectValue(*obj));
         return true;
     }
 
     void* retAddr = &exportArgs[0];
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -770,18 +770,25 @@ WasmInstanceObject::getExportedFunction(
     }
 
     const Instance& instance = instanceObj->instance();
     RootedAtom name(cx, instance.code().getFuncAtom(cx, funcIndex));
     if (!name)
         return false;
 
     unsigned numArgs = instance.metadata().lookupFuncExport(funcIndex).sig().args().length();
-    fun.set(NewNativeConstructor(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED,
-                                 SingletonObject, JSFunction::WASM_CTOR));
+
+    // asm.js needs to active like a normal JS function which are allowed to be
+    // used as constructors.
+    if (instance.isAsmJS()) {
+        fun.set(NewNativeConstructor(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED,
+                                     SingletonObject, JSFunction::ASMJS_CTOR));
+    } else {
+        fun.set(NewNativeFunction(cx, WasmCall, numArgs, name, gc::AllocKind::FUNCTION_EXTENDED));
+    }
     if (!fun)
         return false;
 
     fun->setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, ObjectValue(*instanceObj));
     fun->setExtendedSlot(FunctionExtended::WASM_FUNC_INDEX_SLOT, Int32Value(funcIndex));
 
     if (!instanceObj->exports().putNew(funcIndex, fun)) {
         ReportOutOfMemory(cx);
--- a/layout/tools/reftest/mach_commands.py
+++ b/layout/tools/reftest/mach_commands.py
@@ -134,20 +134,16 @@ class ReftestRunner(MozbuildObject):
             raise Exception(ADB_NOT_FOUND % ('%s-remote' % args.suite, b2g_home))
 
         args.b2gPath = b2g_home
         args.logdir = self.reftest_dir
         args.httpdPath = os.path.join(self.topsrcdir, 'netwerk', 'test', 'httpserver')
         args.xrePath = xre_path
         args.ignoreWindowSize = True
 
-        # Don't enable oop for crashtest until they run oop in automation
-        if args.suite == 'reftest':
-            args.oop = True
-
         return runreftestb2g.run_test_harness(parser, args)
 
     def run_mulet_test(self, **kwargs):
         """Runs a mulet reftest."""
         args = Namespace(**kwargs)
         self._setup_objdir(args)
 
         import runreftestmulet
@@ -165,20 +161,17 @@ class ReftestRunner(MozbuildObject):
 
         if os.path.isfile(os.path.join(args.profile, 'extensions',
                                        'httpd@gaiamobile.org')):
             print(GAIA_PROFILE_IS_DEBUG % args.profile)
             return 1
 
         args.app = self.get_binary_path()
         args.mulet = True
-        args.oop = True
 
-        if args.oop:
-            args.browser_arg = '-oop'
         if not args.app.endswith('-bin'):
             args.app = '%s-bin' % args.app
         if not os.path.isfile(args.app):
             args.app = args.app[:-len('-bin')]
 
         return runreftestmulet.run_test_harness(parser, args)
 
     def run_desktop_test(self, **kwargs):
@@ -216,18 +209,16 @@ class ReftestRunner(MozbuildObject):
         return rv
 
     def run_android_test(self, **kwargs):
         """Runs a reftest, in Firefox for Android."""
 
         args = Namespace(**kwargs)
         if args.suite not in ('reftest', 'crashtest', 'jstestbrowser'):
             raise Exception('None or unrecognized reftest suite type.')
-        if hasattr(args, 'ipc'):
-            raise Exception('IPC tests not supported on Android.')
 
         self._setup_objdir(args)
         import remotereftest
 
         default_manifest = {
             "reftest": (self.topsrcdir, "layout", "reftests", "reftest.list"),
             "crashtest": (self.topsrcdir, "testing", "crashtest", "crashtests.list"),
             "jstestbrowser": ("jsreftest", "tests", "jstests.list")
@@ -333,42 +324,24 @@ class MachCommands(MachCommandBase):
              parser=get_parser)
     def run_jstestbrowser(self, **kwargs):
         self._mach_context.commands.dispatch("build",
                                              self._mach_context,
                                              what=["stage-jstests"])
         kwargs["suite"] = "jstestbrowser"
         return self._run_reftest(**kwargs)
 
-    @Command('reftest-ipc',
-             category='testing',
-             description='Run IPC reftests (layout and graphics correctness, separate process).',
-             parser=get_parser)
-    def run_ipc(self, **kwargs):
-        kwargs["ipc"] = True
-        kwargs["suite"] = "reftest"
-        return self._run_reftest(**kwargs)
-
     @Command('crashtest',
              category='testing',
              description='Run crashtests (Check if crashes on a page).',
              parser=get_parser)
     def run_crashtest(self, **kwargs):
         kwargs["suite"] = "crashtest"
         return self._run_reftest(**kwargs)
 
-    @Command('crashtest-ipc',
-             category='testing',
-             description='Run IPC crashtests (Check if crashes on a page, separate process).',
-             parser=get_parser)
-    def run_crashtest_ipc(self, **kwargs):
-        kwargs["ipc"] = True
-        kwargs["suite"] = "crashtest"
-        return self._run_reftest(**kwargs)
-
     def _run_reftest(self, **kwargs):
         process_test_objects(kwargs)
         reftest = self._spawn(ReftestRunner)
         if conditions.is_android(self):
             from mozrunner.devices.android_device import verify_android_device
             verify_android_device(self, install=True, xre=True)
             return reftest.run_android_test(**kwargs)
         elif conditions.is_mulet(self):
--- a/layout/tools/reftest/reftestcommandline.py
+++ b/layout/tools/reftest/reftestcommandline.py
@@ -312,43 +312,24 @@ class DesktopArgumentsParser(ReftestArgu
         super(DesktopArgumentsParser, self).__init__(**kwargs)
 
         self.add_argument("--run-tests-in-parallel",
                           action="store_true",
                           default=False,
                           dest="runTestsInParallel",
                           help="run tests in parallel if possible")
 
-        self.add_argument("--ipc",
-                          action="store_true",
-                          default=False,
-                          help="Run in out-of-processes mode")
-
-    def _prefs_oop(self):
-        import mozinfo
-        prefs = ["layers.async-pan-zoom.enabled=true",
-                 "browser.tabs.remote.autostart=true"]
-        if mozinfo.os == "win":
-            prefs.append("layers.acceleration.disabled=true")
-
-        return prefs
-
     def _prefs_gpu(self):
         if mozinfo.os != "win":
             return ["layers.acceleration.force-enabled=true"]
         return []
 
     def validate(self, options, reftest):
         super(DesktopArgumentsParser, self).validate(options, reftest)
 
-        if options.ipc:
-            for item in self._prefs_oop():
-                if item not in options.extraPrefs:
-                    options.extraPrefs.append(item)
-
         if options.runTestsInParallel:
             if options.logFile is not None:
                 self.error("cannot specify logfile with parallel tests")
             if options.totalChunks is not None or options.thisChunk is not None:
                 self.error(
                     "cannot specify thisChunk or totalChunks with parallel tests")
             if options.focusFilterMode != "all":
                 self.error("cannot specify focusFilterMode with parallel tests")
@@ -497,22 +478,16 @@ class B2GArgumentParser(ReftestArguments
                           "gaia profile to use")
 
         self.add_argument("--mulet",
                           action="store_true",
                           dest="mulet",
                           default=False,
                           help="Run the tests on a B2G desktop build")
 
-        self.add_argument("--enable-oop",
-                          action="store_true",
-                          dest="oop",
-                          default=False,
-                          help="Run the tests out of process")
-
         self.set_defaults(remoteTestRoot=None,
                           logFile="reftest.log",
                           autorun=True,
                           closeWhenDone=True,
                           testPath="")
 
     def validate_remote(self, options, automation):
         if not options.app:
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -256,20 +256,16 @@ class B2GRemoteReftest(RefTest):
         prefs["app.update.url"] = ""
         prefs["app.update.url.override"] = ""
         # Disable webapp updates
         prefs["webapps.update.enabled"] = False
         # Disable tiles also
         prefs["browser.newtabpage.directory.source"] = ""
         prefs["browser.newtabpage.directory.ping"] = ""
 
-        if options.oop:
-            prefs['browser.tabs.remote.autostart'] = True
-            prefs['reftest.browser.iframe.enabled'] = True
-
         # Set the extra prefs.
         profile.set_preferences(prefs)
 
         # Copy the profile to the device.
         self._devicemanager.removeDir(self.remoteProfile)
         try:
             self._devicemanager.pushDir(profileDir, self.remoteProfile)
         except DMError:
--- a/mfbt/Range.h
+++ b/mfbt/Range.h
@@ -3,16 +3,17 @@
 /* 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/. */
 
 #ifndef mozilla_Range_h
 #define mozilla_Range_h
 
 #include "mozilla/RangedPtr.h"
+#include "mozilla/TypeTraits.h"
 
 #include <stddef.h>
 
 namespace mozilla {
 
 // Range<T> is a tuple containing a pointer and a length.
 template <typename T>
 class Range
@@ -30,16 +31,24 @@ public:
     : mStart(aStart.get(), aStart.get(), aEnd.get()),
       mEnd(aEnd.get(), aStart.get(), aEnd.get())
   {
     // Only accept two RangedPtrs within the same range.
     aStart.checkIdenticalRange(aEnd);
     MOZ_ASSERT(aStart <= aEnd);
   }
 
+  template<typename U,
+           class = typename EnableIf<IsConvertible<U (*)[], T (*)[]>::value,
+                                     int>::Type>
+  MOZ_IMPLICIT Range(const Range<U>& aOther)
+    : mStart(aOther.mStart),
+      mEnd(aOther.mEnd)
+  {}
+
   RangedPtr<T> begin() const { return mStart; }
   RangedPtr<T> end() const { return mEnd; }
   size_t length() const { return mEnd - mStart; }
 
   T& operator[](size_t aOffset) const { return mStart[aOffset]; }
 
   explicit operator bool() const { return mStart != nullptr; }
 };
new file mode 100644
--- /dev/null
+++ b/mfbt/tests/TestRange.cpp
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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 "mozilla/Range.h"
+#include "mozilla/TypeTraits.h"
+
+using mozilla::IsConvertible;
+using mozilla::Range;
+
+static_assert(IsConvertible<Range<int>, Range<const int>>::value,
+              "Range should convert into const");
+static_assert(!IsConvertible<Range<const int>, Range<int>>::value,
+              "Range should not drop const in conversion");
+
+// We need a proper program so we have someplace to hang the static_asserts.
+int
+main()
+{
+  return 0;
+}
--- a/mfbt/tests/moz.build
+++ b/mfbt/tests/moz.build
@@ -28,16 +28,17 @@ CppUnitTests([
     'TestJSONWriter',
     'TestLinkedList',
     'TestMacroArgs',
     'TestMacroForEach',
     'TestMathAlgorithms',
     'TestMaybe',
     'TestNotNull',
     'TestPair',
+    'TestRange',
     'TestRefPtr',
     'TestRollingMean',
     'TestSaturate',
     'TestScopeExit',
     'TestSegmentedVector',
     'TestSHA1',
     'TestSplayTree',
     'TestTemplateLib',
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -2404,16 +2404,20 @@ public abstract class GeckoApp
             if (cleanupVersion != CURRENT_CLEANUP_VERSION) {
                 SharedPreferences.Editor editor = GeckoSharedPrefs.forApp(context).edit();
                 editor.putInt(CLEANUP_VERSION, CURRENT_CLEANUP_VERSION);
                 editor.apply();
             }
         }
     }
 
+    protected void onDone() {
+        moveTaskToBack(true);
+    }
+
     @Override
     public void onBackPressed() {
         if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
             super.onBackPressed();
             return;
         }
 
         if (autoHideTabs()) {
@@ -2434,17 +2438,17 @@ public abstract class GeckoApp
         if (mLayerView != null && mLayerView.isFullScreen()) {
             GeckoAppShell.notifyObservers("FullScreen:Exit", null);
             return;
         }
 
         final Tabs tabs = Tabs.getInstance();
         final Tab tab = tabs.getSelectedTab();
         if (tab == null) {
-            moveTaskToBack(true);
+            onDone();
             return;
         }
 
         // Give Gecko a chance to handle the back press first, then fallback to the Java UI.
         GeckoAppShell.sendRequestToGecko(new GeckoRequest("Browser:OnBackPressed", null) {
             @Override
             public void onResponse(NativeJSObject nativeJSObject) {
                 if (!nativeJSObject.getBoolean("handled")) {
@@ -2464,17 +2468,17 @@ public abstract class GeckoApp
                 ThreadUtils.postToUiThread(new Runnable() {
                     @Override
                     public void run() {
                         if (tab.doBack()) {
                             return;
                         }
 
                         if (tab.isExternal()) {
-                            moveTaskToBack(true);
+                            onDone();
                             Tab nextSelectedTab = Tabs.getInstance().getNextTab(tab);
                             if (nextSelectedTab != null) {
                                 int nextSelectedTabId = nextSelectedTab.getId();
                                 GeckoAppShell.notifyObservers("Tab:KeepZombified", Integer.toString(nextSelectedTabId));
                             }
                             tabs.closeTab(tab);
                             return;
                         }
@@ -2482,17 +2486,17 @@ public abstract class GeckoApp
                         final int parentId = tab.getParentId();
                         final Tab parent = tabs.getTab(parentId);
                         if (parent != null) {
                             // The back button should always return to the parent (not a sibling).
                             tabs.closeTab(tab, parent);
                             return;
                         }
 
-                        moveTaskToBack(true);
+                        onDone();
                     }
                 });
             }
         });
     }
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -1,67 +1,146 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.customtabs;
 
+import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
 
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.util.ColorUtil;
 import org.mozilla.gecko.util.GeckoRequest;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ThreadUtils;
 
-public class CustomTabsActivity extends GeckoApp {
+import java.lang.reflect.Field;
+
+import static android.support.customtabs.CustomTabsIntent.EXTRA_TOOLBAR_COLOR;
+
+public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedListener {
+    private static final String LOGTAG = "CustomTabsActivity";
+    private static final int NO_COLOR = -1;
+    private Toolbar toolbar;
+
+    private ActionBar actionBar;
+    private int tabId = -1;
+    private boolean useDomainTitle = true;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+        updateActionBarWithToolbar(toolbar);
+        try {
+            // Since we don't create the Toolbar's TextView ourselves, this seems
+            // to be the only way of changing the ellipsize setting.
+            Field f = toolbar.getClass().getDeclaredField("mTitleTextView");
+            f.setAccessible(true);
+            TextView textView = (TextView) f.get(toolbar);
+            textView.setEllipsize(TextUtils.TruncateAt.START);
+        } catch (Exception e) {
+            // If we can't ellipsize at the start of the title, we shouldn't display the host
+            // so as to avoid displaying a misleadingly truncated host.
+            Log.w(LOGTAG, "Failed to get Toolbar TextView, using default title.");
+            useDomainTitle = false;
+        }
+        actionBar = getSupportActionBar();
+        updateToolbarColor(toolbar);
+
+        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                onBackPressed();
+            }
+        });
+
+        Tabs.registerOnTabsChangedListener(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Tabs.unregisterOnTabsChangedListener(this);
     }
 
     @Override
     public int getLayout() {
         return R.layout.customtabs_activity;
     }
 
     @Override
-    public void onBackPressed() {
-        final Tabs tabs = Tabs.getInstance();
-        final Tab tab = tabs.getSelectedTab();
+    protected void onDone() {
+        finish();
+    }
+
+    @Override
+    public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
+        if (tab == null) {
+            return;
+        }
+
+        if (tabId >= 0 && tab.getId() != tabId) {
+            return;
+        }
 
-        // Give Gecko a chance to handle the back press first, then fallback to the Java UI.
-        GeckoAppShell.sendRequestToGecko(new GeckoRequest("Browser:OnBackPressed", null) {
-            @Override
-            public void onResponse(NativeJSObject nativeJSObject) {
-                if (!nativeJSObject.getBoolean("handled")) {
-                    // Default behavior is Gecko didn't prevent.
-                    onDefault();
-                }
+        if (msg == Tabs.TabEvents.LOCATION_CHANGE) {
+            tabId = tab.getId();
+            final Uri uri = Uri.parse(tab.getURL());
+            String title = null;
+            if (uri != null) {
+                title = uri.getHost();
             }
+            if (!useDomainTitle || title == null || title.isEmpty()) {
+                actionBar.setTitle(AppConstants.MOZ_APP_BASENAME);
+            } else {
+                actionBar.setTitle(title);
+            }
+        }
+    }
 
-            @Override
-            public void onError(NativeJSObject error) {
-                // Default behavior is Gecko didn't prevent, via failure.
-                onDefault();
-            }
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                finish();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
 
-            // Return from Gecko thread, then back-press through the Java UI.
-            private void onDefault() {
-                ThreadUtils.postToUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (tab.doBack()) {
-                            return;
-                        }
+    private void updateActionBarWithToolbar(final Toolbar toolbar) {
+        setSupportActionBar(toolbar);
+        final ActionBar ab = getSupportActionBar();
+        if (ab != null) {
+            ab.setDisplayHomeAsUpEnabled(true);
+        }
+    }
 
-                        tabs.closeTab(tab);
-                        finish();
-                    }
-                });
-            }
-        });
+    private void updateToolbarColor(final Toolbar toolbar) {
+        final int color = getIntent().getIntExtra(EXTRA_TOOLBAR_COLOR, NO_COLOR);
+        if (color == NO_COLOR) {
+            return;
+        }
+        toolbar.setBackgroundColor(color);
+        final Window window = getWindow();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            window.setStatusBarColor(ColorUtil.darken(color, 0.25));
+        }
     }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/util/ColorUtil.java
@@ -0,0 +1,25 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko.util;
+
+import android.graphics.Color;
+
+public class ColorUtil {
+    public static int darken(final int color, final double fraction) {
+        int red = Color.red(color);
+        int green = Color.green(color);
+        int blue = Color.blue(color);
+        red = darkenColor(red, fraction);
+        green = darkenColor(green, fraction);
+        blue = darkenColor(blue, fraction);
+        final int alpha = Color.alpha(color);
+        return Color.argb(alpha, red, green, blue);
+    }
+
+    private static int darkenColor(final int color, final double fraction) {
+        return (int) Math.max(color - (color * fraction), 0);
+    }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -731,16 +731,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'toolbar/ToolbarEditLayout.java',
     'toolbar/ToolbarEditText.java',
     'toolbar/ToolbarPrefs.java',
     'toolbar/ToolbarProgressView.java',
     'trackingprotection/TrackingProtectionPrompt.java',
     'updater/PostUpdateHandler.java',
     'updater/UpdateService.java',
     'updater/UpdateServiceHelper.java',
+    'util/ColorUtil.java',
     'util/DrawableUtil.java',
     'util/ResourceDrawableUtils.java',
     'util/TouchTargetUtil.java',
     'widget/ActivityChooserModel.java',
     'widget/AllCapsTextView.java',
     'widget/AnchoredPopup.java',
     'widget/AnimatedHeightLayout.java',
     'widget/BasicColorPicker.java',
--- a/mobile/android/base/resources/layout/customtabs_activity.xml
+++ b/mobile/android/base/resources/layout/customtabs_activity.xml
@@ -1,27 +1,38 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/root_layout"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
     <!--
         This layout is quite complex because GeckoApp accesses all view groups
         in this tree. In a perfect world this should just include a GeckoView.
     -->
 
+    <android.support.v7.widget.Toolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="?attr/actionBarSize"
+        android:elevation="4dp"
+        android:background="@color/text_and_tabs_tray_grey"
+        app:layout_scrollFlags="scroll|enterAlways"/>
+
     <view class="org.mozilla.gecko.GeckoApp$MainLayout"
         android:id="@+id/main_layout"
         android:layout_width="match_parent"
+        android:layout_below="@+id/toolbar"
         android:layout_height="match_parent"
         android:background="@android:color/transparent">
 
         <RelativeLayout android:id="@+id/gecko_layout"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_below="@+id/tablet_tab_strip"
             android:layout_above="@+id/find_in_page">
--- a/taskcluster/ci/upload-symbols/job-template.yml
+++ b/taskcluster/ci/upload-symbols/job-template.yml
@@ -5,15 +5,15 @@ expires-after: 7 days
 deadline-after: 24 hours
 run-on-projects:
     - try
 worker-type: aws-provisioner-v1/symbol-upload
 worker:
     implementation: docker-worker
     max-run-time: 600
     command: ["/bin/bash", "bin/upload.sh"]
-    docker-image: taskclusterprivate/upload_symbols:0.0.3
+    docker-image: taskclusterprivate/upload_symbols:0.0.4
     env:
         GECKO_HEAD_REPOSITORY: # see transforms
         GECKO_HEAD_REV: # see transforms
         ARTIFACT_TASKID: {"task-reference": "<build>"}
 scopes:
-    - docker-worker:image:taskclusterprivate/upload_symbols:0.0.3
+    - docker-worker:image:taskclusterprivate/upload_symbols:0.0.4
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -51,21 +51,16 @@ TEST_SUITES = {
         'mach_command': 'cppunittest',
         'kwargs': {'test_file': None},
     },
     'crashtest': {
         'aliases': ('C', 'Rc', 'RC', 'rc'),
         'mach_command': 'crashtest',
         'kwargs': {'test_file': None},
     },
-    'crashtest-ipc': {
-        'aliases': ('Cipc', 'cipc'),
-        'mach_command': 'crashtest-ipc',
-        'kwargs': {'test_file': None},
-    },
     'firefox-ui-functional': {
         'aliases': ('Fxfn',),
         'mach_command': 'firefox-ui-functional',
         'kwargs': {},
     },
     'firefox-ui-update': {
         'aliases': ('Fxup',),
         'mach_command': 'firefox-ui-update',
@@ -107,21 +102,16 @@ TEST_SUITES = {
         'mach_command': 'python-test',
         'kwargs': {'tests': None},
     },
     'reftest': {
         'aliases': ('RR', 'rr', 'Rr'),
         'mach_command': 'reftest',
         'kwargs': {'tests': None},
     },
-    'reftest-ipc': {
-        'aliases': ('Ripc',),
-        'mach_command': 'reftest-ipc',
-        'kwargs': {'test_file': None},
-    },
     'web-platform-tests': {
         'aliases': ('wpt',),
         'mach_command': 'web-platform-tests',
         'kwargs': {}
     },
     'valgrind': {
         'aliases': ('V', 'v'),
         'mach_command': 'valgrind-test',
--- a/testing/mochitest/manifests/autophone-webrtc.ini
+++ b/testing/mochitest/manifests/autophone-webrtc.ini
@@ -7,17 +7,16 @@ skip-if = true  # Bug 1189784
 [../tests/dom/media/tests/mochitest/test_dataChannel_basicAudioVideo.html]
 [../tests/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html]
 [../tests/dom/media/tests/mochitest/test_dataChannel_basicDataOnly.html]
 [../tests/dom/media/tests/mochitest/test_dataChannel_basicVideo.html]
 [../tests/dom/media/tests/mochitest/test_dataChannel_bug1013809.html]
 [../tests/dom/media/tests/mochitest/test_dataChannel_noOffer.html]
 [../tests/dom/media/tests/mochitest/test_enumerateDevices.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html]
-skip-if = true  # Bug 1282897
 [../tests/dom/media/tests/mochitest/test_getUserMedia_audioCapture.html]
 skip-if = true  # timeouts, see Bug 1264333
 [../tests/dom/media/tests/mochitest/test_getUserMedia_basicAudio.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html]
 skip-if = true  # OverConstrained error, no screenshare on Android
 [../tests/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_basicVideoAudio.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_basicVideo.html]
@@ -27,21 +26,18 @@ skip-if = true  # OverConstrained error,
 [../tests/dom/media/tests/mochitest/test_getUserMedia_bug1223696.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_callbacks.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_constraints.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_gumWithinGum.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_loadedmetadata.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_mediaStreamConstructors.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_playAudioTwice.html]
-skip-if = true  # Bug 1282897
 [../tests/dom/media/tests/mochitest/test_getUserMedia_playVideoAudioTwice.html]
-skip-if = true  # Bug 1282897
 [../tests/dom/media/tests/mochitest/test_getUserMedia_playVideoTwice.html]
-skip-if = true  # Bug 1282897
 [../tests/dom/media/tests/mochitest/test_getUserMedia_spinEventLoop.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_stopAudioStream.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStream.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_stopVideoStream.html]
 [../tests/dom/media/tests/mochitest/test_getUserMedia_stopVideoStreamWithFollowupVideo.html]
 [../tests/dom/media/tests/mochitest/test_peerConnection_addDataChannel.html]
--- a/testing/mozharness/configs/unittests/linux_unittest.py
+++ b/testing/mozharness/configs/unittests/linux_unittest.py
@@ -201,57 +201,33 @@ config = {
         "mochitest-devtools-chrome-coverage": ["--flavor=browser", "--subsuite=devtools", "--chunk-by-runtime", "--timeout=1200"],
         "jetpack-package": ["--flavor=jetpack-package"],
         "jetpack-package-clipboard": ["--flavor=jetpack-package", "--subsuite=clipboard"],
         "jetpack-addon": ["--flavor=jetpack-addon"],
         "a11y": ["--flavor=a11y"],
     },
     # local reftest suites
     "all_reftest_suites": {
-        "reftest": {
-            "options": ["--suite=reftest"],
-            "tests": ["tests/reftest/tests/layout/reftests/reftest.list"]
-        },
         "crashtest": {
             "options": ["--suite=crashtest"],
             "tests": ["tests/reftest/tests/testing/crashtest/crashtests.list"]
         },
         "jsreftest": {
             "options": ["--extra-profile-file=tests/jsreftest/tests/user.js",
                        "--suite=jstestbrowser"],
             "tests": ["tests/jsreftest/tests/jstests.list"]
         },
-        "reftest-ipc": {
-            "env": {
-                "MOZ_OMTC_ENABLED": "1",
-                "MOZ_DISABLE_CONTEXT_SHARING_GLX": "1"
-            },
-            "options": ["--suite=reftest",
-                        "--setpref=browser.tabs.remote=true",
-                        "--setpref=browser.tabs.remote.autostart=true",
-                        "--setpref=extensions.e10sBlocksEnabling=false",
-                        "--setpref=layers.async-pan-zoom.enabled=true"],
-            "tests": ["tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list"]
+        "reftest": {
+            "options": ["--suite=reftest"],
+            "tests": ["tests/reftest/tests/layout/reftests/reftest.list"]
         },
         "reftest-no-accel": {
             "options": ["--suite=reftest",
                         "--setpref=layers.acceleration.force-enabled=disabled"],
             "tests": ["tests/reftest/tests/layout/reftests/reftest.list"]},
-        "crashtest-ipc": {
-            "env": {
-                "MOZ_OMTC_ENABLED": "1",
-                "MOZ_DISABLE_CONTEXT_SHARING_GLX": "1"
-            },
-            "options": ["--suite=crashtest",
-                        "--setpref=browser.tabs.remote=true",
-                        "--setpref=browser.tabs.remote.autostart=true",
-                        "--setpref=extensions.e10sBlocksEnabling=false",
-                        "--setpref=layers.async-pan-zoom.enabled=true"],
-            "tests": ["tests/reftest/tests/testing/crashtest/crashtests.list"]
-        },
     },
     "all_xpcshell_suites": {
         "xpcshell": {
             "options": ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME,
                         "--manifest=tests/xpcshell/tests/xpcshell.ini"],
             "tests": []
         },
         "xpcshell-addons": {
--- a/testing/mozharness/configs/unittests/mac_unittest.py
+++ b/testing/mozharness/configs/unittests/mac_unittest.py
@@ -166,43 +166,27 @@ config = {
         "mochitest-devtools-chrome-chunked": ["--flavor=browser", "--subsuite=devtools", "--chunk-by-runtime"],
         "jetpack-package": ["--flavor=jetpack-package"],
         "jetpack-package-clipboard": ["--flavor=jetpack-package", "--subsuite=clipboard"],
         "jetpack-addon": ["--flavor=jetpack-addon"],
         "a11y": ["--flavor=a11y"],
     },
     # local reftest suites
     "all_reftest_suites": {
-        "reftest": {
-            'options': ["--suite=reftest"],
-            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
-        },
         "crashtest": {
             'options': ["--suite=crashtest"],
             'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"]
         },
         "jsreftest": {
             'options':["--extra-profile-file=tests/jsreftest/tests/user.js"],
             'tests': ["tests/jsreftest/tests/jstests.list"]
         },
-        "reftest-ipc": {
-            'options': ['--suite=reftest',
-                        '--setpref=browser.tabs.remote=true',
-                        '--setpref=browser.tabs.remote.autostart=true',
-                        '--setpref=extensions.e10sBlocksEnabling=false',
-                        '--setpref=layers.async-pan-zoom.enabled=true'],
-            'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list']
-        },
-        "crashtest-ipc": {
-            'options': ['--suite=crashtest',
-                        '--setpref=browser.tabs.remote=true',
-                        '--setpref=browser.tabs.remote.autostart=true',
-                        '--setpref=extensions.e10sBlocksEnabling=false',
-                        '--setpref=layers.async-pan-zoom.enabled=true'],
-            'tests': ['tests/reftest/tests/testing/crashtest/crashtests.list']
+        "reftest": {
+            'options': ["--suite=reftest"],
+            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
         },
     },
     "all_xpcshell_suites": {
         "xpcshell": {
             'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME,
                         "--manifest=tests/xpcshell/tests/xpcshell.ini"],
             'tests': []
         },
--- a/testing/mozharness/configs/unittests/win_taskcluster_unittest.py
+++ b/testing/mozharness/configs/unittests/win_taskcluster_unittest.py
@@ -179,50 +179,39 @@ config = {
         "mochitest-metro-chrome": ["--flavor=browser", "--metro-immersive"],
         "jetpack-package": ["--flavor=jetpack-package"],
         "jetpack-package-clipboard": ["--flavor=jetpack-package", "--subsuite=clipboard"],
         "jetpack-addon": ["--flavor=jetpack-addon"],
         "a11y": ["--flavor=a11y"],
     },
     # local reftest suites
     "all_reftest_suites": {
-        "reftest": {
-            'options': ["--suite=reftest"],
-            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
-        },
         "crashtest": {
             'options': ["--suite=crashtest"],
             'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"]
         },
         "jsreftest": {
             'options':["--extra-profile-file=tests/jsreftest/tests/user.js"],
             'tests': ["tests/jsreftest/tests/jstests.list"]
         },
-        "reftest-ipc": {
-            'options': ['--suite=reftest',
-                        '--setpref=browser.tabs.remote=true',
-                        '--setpref=browser.tabs.remote.autostart=true',
-                        '--setpref=extensions.e10sBlocksEnabling=false',
-                        '--setpref=layers.async-pan-zoom.enabled=true'],
-            'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list']
+        "reftest": {
+            'options': ["--suite=reftest"],
+            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
+        },
+        "reftest-gpu": {
+            'options': ["--suite=reftest",
+                        "--setpref=layers.gpu-process.force-enabled=true"],
+            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
         },
         "reftest-no-accel": {
             "options": ["--suite=reftest",
                         "--setpref=gfx.direct2d.disabled=true",
                         "--setpref=layers.acceleration.disabled=true"],
             "tests": ["tests/reftest/tests/layout/reftests/reftest.list"]
         },
-        "crashtest-ipc": {
-            "options": ["--suite=crashtest",
-                        '--setpref=browser.tabs.remote=true',
-                        '--setpref=browser.tabs.remote.autostart=true',
-                        '--setpref=extensions.e10sBlocksEnabling=false',
-                        '--setpref=layers.async-pan-zoom.enabled=true'],
-            "tests": ['tests/reftest/tests/testing/crashtest/crashtests.list'],
-        },
     },
     "all_xpcshell_suites": {
         "xpcshell": {
             'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME,
                         "--manifest=tests/xpcshell/tests/xpcshell.ini"],
             'tests': []
         },
         "xpcshell-addons": {
--- a/testing/mozharness/configs/unittests/win_unittest.py
+++ b/testing/mozharness/configs/unittests/win_unittest.py
@@ -179,50 +179,39 @@ config = {
         "mochitest-metro-chrome": ["--flavor=browser", "--metro-immersive"],
         "jetpack-package": ["--flavor=jetpack-package"],
         "jetpack-package-clipboard": ["--flavor=jetpack-package", "--subsuite=clipboard"],
         "jetpack-addon": ["--flavor=jetpack-addon"],
         "a11y": ["--flavor=a11y"],
     },
     # local reftest suites
     "all_reftest_suites": {
-        "reftest": {
-            'options': ["--suite=reftest"],
-            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
-        },
         "crashtest": {
             'options': ["--suite=crashtest"],
             'tests': ["tests/reftest/tests/testing/crashtest/crashtests.list"]
         },
         "jsreftest": {
             'options':["--extra-profile-file=tests/jsreftest/tests/user.js"],
             'tests': ["tests/jsreftest/tests/jstests.list"]
         },
-        "reftest-ipc": {
-            'options': ['--suite=reftest',
-                        '--setpref=browser.tabs.remote=true',
-                        '--setpref=browser.tabs.remote.autostart=true',
-                        '--setpref=extensions.e10sBlocksEnabling=false',
-                        '--setpref=layers.async-pan-zoom.enabled=true'],
-            'tests': ['tests/reftest/tests/layout/reftests/reftest-sanity/reftest.list']
+        "reftest": {
+            'options': ["--suite=reftest"],
+            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
+        },
+        "reftest-gpu": {
+            'options': ["--suite=reftest",
+                        "--setpref=layers.gpu-process.force-enabled=true"],
+            'tests': ["tests/reftest/tests/layout/reftests/reftest.list"]
         },
         "reftest-no-accel": {
             "options": ["--suite=reftest",
                         "--setpref=gfx.direct2d.disabled=true",
                         "--setpref=layers.acceleration.disabled=true"],
             "tests": ["tests/reftest/tests/layout/reftests/reftest.list"]
         },
-        "crashtest-ipc": {
-            "options": ["--suite=crashtest",
-                        '--setpref=browser.tabs.remote=true',
-                        '--setpref=browser.tabs.remote.autostart=true',
-                        '--setpref=extensions.e10sBlocksEnabling=false',
-                        '--setpref=layers.async-pan-zoom.enabled=true'],
-            "tests": ['tests/reftest/tests/testing/crashtest/crashtests.list'],
-        },
     },
     "all_xpcshell_suites": {
         "xpcshell": {
             'options': ["--xpcshell=%(abs_app_dir)s/" + XPCSHELL_NAME,
                         "--manifest=tests/xpcshell/tests/xpcshell.ini"],
             'tests': []
         },
         "xpcshell-addons": {
--- a/testing/mozharness/mach_commands.py
+++ b/testing/mozharness/mach_commands.py
@@ -73,46 +73,36 @@ class MozharnessRunner(MozbuildObject):
                 "config": desktop_unittest_config + [
                     "--mochitest-suite", "browser-chrome"]
             },
             "mochitest-devtools-chrome": {
                 "script": "desktop_unittest.py",
                 "config": desktop_unittest_config + [
                     "--mochitest-suite", "mochitest-devtools-chrome"]
             },
-            "reftest": {
-                "script": "desktop_unittest.py",
-                "config": desktop_unittest_config + [
-                    "--reftest-suite", "reftest"]
-            },
             "crashtest": {
                 "script": "desktop_unittest.py",
                 "config": desktop_unittest_config + [
                     "--reftest-suite", "crashtest"]
             },
             "jsreftest": {
                 "script": "desktop_unittest.py",
                 "config": desktop_unittest_config + [
                     "--reftest-suite", "jsreftest"]
             },
-            "reftest-ipc": {
+            "reftest": {
                 "script": "desktop_unittest.py",
                 "config": desktop_unittest_config + [
-                    "--reftest-suite", "reftest-ipc"]
+                    "--reftest-suite", "reftest"]
             },
             "reftest-no-accel": {
                 "script": "desktop_unittest.py",
                 "config": desktop_unittest_config + [
                     "--reftest-suite", "reftest-no-accel"]
             },
-            "crashtest-ipc": {
-                "script": "desktop_unittest.py",
-                "config": desktop_unittest_config + [
-                    "--reftest-suite", "crashtest-ipc"]
-            },
             "cppunittest": {
                 "script": "desktop_unittest.py",
                 "config": desktop_unittest_config + [
                     "--cppunittest-suite", "cppunittest"]
             },
             "xpcshell": {
                 "script": "desktop_unittest.py",
                 "config": desktop_unittest_config + [
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -108,41 +108,21 @@ reftest-b2g:
 		if [ '${REFTEST_PATH}' != '' ]; then \
 			$(call RUN_REFTEST_B2G,tests/${REFTEST_PATH}); \
 		else \
 			$(call RUN_REFTEST_B2G,tests/$(TEST_PATH)); \
 		fi; \
         $(CHECK_TEST_ERROR); \
 	fi
 
-reftest-ipc: TEST_PATH?=layout/reftests/reftest.list
-reftest-ipc:
-	$(call RUN_REFTEST,'$(topsrcdir)/$(TEST_PATH)' $(OOP_CONTENT))
-	$(CHECK_TEST_ERROR)
-
-reftest-ipc-gpu: TEST_PATH?=layout/reftests/reftest.list
-reftest-ipc-gpu:
-	$(call RUN_REFTEST,'$(topsrcdir)/$(TEST_PATH)' $(OOP_CONTENT) $(GPU_RENDERING))
-	$(CHECK_TEST_ERROR)
-
 crashtest: TEST_PATH?=testing/crashtest/crashtests.list
 crashtest:
 	$(call RUN_REFTEST,'$(topsrcdir)/$(TEST_PATH)')
 	$(CHECK_TEST_ERROR)
 
-crashtest-ipc: TEST_PATH?=testing/crashtest/crashtests.list
-crashtest-ipc:
-	$(call RUN_REFTEST,'$(topsrcdir)/$(TEST_PATH)' $(OOP_CONTENT))
-	$(CHECK_TEST_ERROR)
-
-crashtest-ipc-gpu: TEST_PATH?=testing/crashtest/crashtests.list
-crashtest-ipc-gpu:
-	$(call RUN_REFTEST,'$(topsrcdir)/$(TEST_PATH)' $(OOP_CONTENT) $(GPU_RENDERING))
-	$(CHECK_TEST_ERROR)
-
 jstestbrowser: TESTS_PATH?=test-stage/jsreftest/tests/
 jstestbrowser:
 	$(MAKE) -C $(DEPTH)/config
 	$(MAKE) stage-jstests
 	$(call RUN_REFTEST,'$(DIST)/$(TESTS_PATH)/jstests.list' --extra-profile-file=$(DIST)/test-stage/jsreftest/tests/user.js)
 	$(CHECK_TEST_ERROR)
 
 GARBAGE += $(addsuffix .log,$(MOCHITESTS) reftest crashtest jstestbrowser)
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -1080,23 +1080,16 @@ TelemetryImpl::AddSQLInfo(JSContext *cx,
   }
 
   return JS_DefineProperty(cx, rootObj,
                            mainThread ? "mainThread" : "otherThreads",
                            statsObj, JSPROP_ENUMERATE);
 }
 
 NS_IMETHODIMP
-TelemetryImpl::HistogramFrom(const nsACString &name, const nsACString &existing_name,
-                             JSContext *cx, JS::MutableHandle<JS::Value> ret)
-{
-  return TelemetryHistogram::HistogramFrom(name, existing_name, cx, ret);
-}
-
-NS_IMETHODIMP
 TelemetryImpl::RegisterAddonHistogram(const nsACString &id,
                                       const nsACString &name,
                                       uint32_t histogramType,
                                       uint32_t min, uint32_t max,
                                       uint32_t bucketCount,
                                       uint8_t optArgCount)
 {
   return TelemetryHistogram::RegisterAddonHistogram
--- a/toolkit/components/telemetry/TelemetryHistogram.cpp
+++ b/toolkit/components/telemetry/TelemetryHistogram.cpp
@@ -589,16 +589,19 @@ internal_GetHistogramByName(const nsACSt
   GeckoProcessType process = GetProcessFromName(name);
   rv = internal_GetHistogramByEnumId(id, ret, process);
   if (NS_FAILED(rv))
     return rv;
 
   return NS_OK;
 }
 
+
+#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
+
 /**
  * This clones a histogram |existing| with the id |existingId| to a
  * new histogram with the name |newName|.
  * For simplicity this is limited to registered histograms.
  */
 Histogram*
 internal_CloneHistogram(const nsACString& newName,
                         mozilla::Telemetry::ID existingId,
@@ -619,36 +622,16 @@ internal_CloneHistogram(const nsACString
 
   Histogram::SampleSet ss;
   existing.SnapshotSample(&ss);
   clone->AddSampleSet(ss);
 
   return clone;
 }
 
-/**
- * This clones a histogram with the id |existingId| to a new histogram
- * with the name |newName|.
- * For simplicity this is limited to registered histograms.
- */
-Histogram*
-internal_CloneHistogram(const nsACString& newName,
-                        mozilla::Telemetry::ID existingId)
-{
-  Histogram *existing = nullptr;
-  nsresult rv = internal_GetHistogramByEnumId(existingId, &existing, GeckoProcessType_Default);
-  if (NS_FAILED(rv)) {
-    return nullptr;
-  }
-
-  return internal_CloneHistogram(newName, existingId, *existing);
-}
-
-#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
-
 GeckoProcessType
 GetProcessFromName(const std::string& aString)
 {
   nsDependentCString string(aString.c_str(), aString.length());
   return GetProcessFromName(string);
 }
 
 Histogram*
@@ -2373,43 +2356,16 @@ const char*
 TelemetryHistogram::GetHistogramName(mozilla::Telemetry::ID id)
 {
   StaticMutexAutoLock locker(gTelemetryHistogramMutex);
   const HistogramInfo& h = gHistograms[id];
   return h.id();
 }
 
 nsresult
-TelemetryHistogram::HistogramFrom(const nsACString &name,
-                                  const nsACString &existing_name,
-                                  JSContext *cx,
-                                  JS::MutableHandle<JS::Value> ret)
-{
-  Histogram* clone = nullptr;
-  {
-    StaticMutexAutoLock locker(gTelemetryHistogramMutex);
-    mozilla::Telemetry::ID id;
-    nsresult rv
-      = internal_GetHistogramEnumId(PromiseFlatCString(existing_name).get(),
-                                    &id);
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-
-    clone = internal_CloneHistogram(name, id);
-    if (!clone) {
-      return NS_ERROR_FAILURE;
-    }
-  }
-
-  // Runs without protection from |gTelemetryHistogramMutex|
-  return internal_WrapAndReturnHistogram(clone, cx, ret);
-}
-
-nsresult
 TelemetryHistogram::CreateHistogramSnapshots(JSContext *cx,
                                              JS::MutableHandle<JS::Value> ret,
                                              bool subsession,
                                              bool clearSubsession)
 {
   // Runs without protection from |gTelemetryHistogramMutex|
   JS::Rooted<JSObject*> root_obj(cx, JS_NewPlainObject(cx));
   if (!root_obj)
--- a/toolkit/components/telemetry/TelemetryHistogram.h
+++ b/toolkit/components/telemetry/TelemetryHistogram.h
@@ -57,20 +57,16 @@ GetHistogramById(const nsACString &name,
 nsresult
 GetKeyedHistogramById(const nsACString &name, JSContext *cx,
                       JS::MutableHandle<JS::Value> ret);
 
 const char*
 GetHistogramName(mozilla::Telemetry::ID id);
 
 nsresult
-HistogramFrom(const nsACString &name, const nsACString &existing_name,
-              JSContext *cx, JS::MutableHandle<JS::Value> ret);
-
-nsresult
 CreateHistogramSnapshots(JSContext *cx, JS::MutableHandle<JS::Value> ret,
                          bool subsession, bool clearSubsession);
 
 nsresult
 RegisteredHistograms(uint32_t aDataset, uint32_t *aCount,
                      char*** aHistograms);
 
 nsresult
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -650,19 +650,16 @@ this.TelemetrySession = Object.freeze({
   },
 });
 
 var Impl = {
   _histograms: {},
   _initialized: false,
   _logger: null,
   _prevValues: {},
-  // Regex that matches histograms we care about during startup.
-  // Keep this in sync with gen-histogram-bucket-ranges.py.
-  _startupHistogramRegex: /SQLITE|HTTP|SPDY|CACHE|DNS/,
   _slowSQLStartup: {},
   _hasWindowRestoredObserver: false,
   _hasXulWindowVisibleObserver: false,
   _startupIO : {},
   // The previous build ID, if this is the first run with a new build.
   // Null if this is the first run, or the previous build ID is unknown.
   _previousBuildId: null,
   // Telemetry payloads sent by child processes.
@@ -1224,46 +1221,21 @@ var Impl = {
     let h = this._histograms[id];
     if (!h) {
       h = Telemetry.getHistogramById(id);
       this._histograms[id] = h;
     }
     h.add(val);
   },
 
-  /**
-   * Return true if we're interested in having a STARTUP_* histogram for
-   * the given histogram name.
-   */
-  isInterestingStartupHistogram: function isInterestingStartupHistogram(name) {
-    return this._startupHistogramRegex.test(name);
-  },
-
   getChildPayloads: function getChildPayloads() {
     return this._childTelemetry.map(child => child.payload);
   },
 
   /**
-   * Make a copy of interesting histograms at startup.
-   */
-  gatherStartupHistograms: function gatherStartupHistograms() {
-    this._log.trace("gatherStartupHistograms");
-
-    let info =
-      Telemetry.registeredHistograms(this.getDatasetType(), []);
-    let snapshots = Telemetry.histogramSnapshots;
-    for (let name of info) {
-      // Only duplicate histograms with actual data.
-      if (this.isInterestingStartupHistogram(name) && name in snapshots) {
-        Telemetry.histogramFrom("STARTUP_" + name, name);
-      }
-    }
-  },
-
-  /**
    * Get the current session's payload using the provided
    * simpleMeasurements and info, which are typically obtained by a call
    * to |this.getSimpleMeasurements| and |this.getMetadata|,
    * respectively.
    */
   assemblePayloadWithMeasurements: function(simpleMeasurements, info, reason, clearSubsession) {
     const isSubsession = IS_UNIFIED_TELEMETRY && !this._isClassicReason(reason);
     clearSubsession = IS_UNIFIED_TELEMETRY && clearSubsession;
@@ -1575,18 +1547,16 @@ var Impl = {
       this._log.trace("setupContentProcess - base recording is disabled, not initializing");
       return;
     }
 
     Services.obs.addObserver(this, "content-child-shutdown", false);
     cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_THREAD_HANGS, this);
     cpml.addMessageListener(MESSAGE_TELEMETRY_GET_CHILD_USS, this);
 
-    this.gatherStartupHistograms();
-
     let delayedTask = new DeferredTask(function* () {
       this._initialized = true;
 
       this.attachObservers();
       this.gatherMemory();
 
       if (Telemetry.canRecordExtended) {
         GCTelemetry.init();
@@ -1798,17 +1768,16 @@ var Impl = {
   },
 
   getPayload: function getPayload(reason, clearSubsession) {
     this._log.trace("getPayload - clearSubsession: " + clearSubsession);
     reason = reason || REASON_GATHER_PAYLOAD;
     // This function returns the current Telemetry payload to the caller.
     // We only gather startup info once.
     if (Object.keys(this._slowSQLStartup).length == 0) {
-      this.gatherStartupHistograms();
       this._slowSQLStartup = Telemetry.slowSQL;
     }
     this.gatherMemory();
     return this.getSessionPayload(reason, clearSubsession);
   },
 
   getChildThreadHangs: function getChildThreadHangs() {
     return new Promise((resolve) => {
@@ -1856,17 +1825,16 @@ var Impl = {
 
   gatherStartup: function gatherStartup() {
     this._log.trace("gatherStartup");
     let counters = processInfo.getCounters();
     if (counters) {
       [this._startupIO.startupSessionRestoreReadBytes,
         this._startupIO.startupSessionRestoreWriteBytes] = counters;
     }
-    this.gatherStartupHistograms();
     this._slowSQLStartup = Telemetry.slowSQL;
   },
 
   setAddOns: function setAddOns(aAddOns) {
     this._addons = aAddOns;
   },
 
   testPing: function testPing() {
--- a/toolkit/components/telemetry/gen-histogram-bucket-ranges.py
+++ b/toolkit/components/telemetry/gen-histogram-bucket-ranges.py
@@ -8,19 +8,16 @@
 
 import sys
 import re
 import histogram_tools
 import json
 
 from collections import OrderedDict
 
-# Keep this in sync with TelemetryController.
-startup_histogram_re = re.compile("SQLITE|HTTP|SPDY|CACHE|DNS")
-
 def main(argv):
     filenames = argv
 
     all_histograms = OrderedDict()
 
     for histogram in histogram_tools.from_files(filenames):
         name = histogram.name()
         parameters = OrderedDict()
@@ -45,14 +42,11 @@ def main(argv):
             parameters['buckets'] = buckets
             parameters['max'] = buckets[-1]
             parameters['bucket_count'] = len(buckets)
         except histogram_tools.DefinitionException:
             continue
 
         all_histograms.update({ name: parameters });
 
-        if startup_histogram_re.search(name) is not None:
-            all_histograms.update({ "STARTUP_" + name: parameters })
-
     print json.dumps({ 'histograms': all_histograms})
 
 main(sys.argv[1:])
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -174,31 +174,16 @@ interface nsITelemetry : nsISupports
    *
    * @param dataset - DATASET_RELEASE_CHANNEL_OPTOUT or DATASET_RELEASE_CHANNEL_OPTIN
    */
   void registeredHistograms(in uint32_t dataset,
                             out uint32_t count,
                             [retval, array, size_is(count)] out string histograms);
 
   /**
-   * Create a histogram using the current state of an existing histogram.  The
-   * existing histogram must be registered in TelemetryHistograms.h.
-   *
-   * @param name Unique histogram name
-   * @param existing_name Existing histogram name
-   * The returned object has the following functions:
-   *   add(int) - Adds an int value to the appropriate bucket
-   *   snapshot() - Returns a snapshot of the histogram with the same data fields as in histogramSnapshots()
-   *   clear() - Zeros out the histogram's buckets and sum
-   *   dataset() - identifies what dataset this is in: DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
-   */
-  [implicit_jscontext]
-  jsval histogramFrom(in ACString name, in ACString existing_name);
-
-  /**
    * Create and return a histogram registered in TelemetryHistograms.h.
    *
    * @param id - unique identifier from TelemetryHistograms.h
    * The returned object has the following functions:
    *   add(int) - Adds an int value to the appropriate bucket
    *   snapshot() - Returns a snapshot of the histogram with the same data fields as in histogramSnapshots()
    *   clear() - Zeros out the histogram's buckets and sum
    *   dataset() - identifies what dataset this is in: DATASET_RELEASE_CHANNEL_OPTOUT or ...OPTIN
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -105,17 +105,16 @@ function fakeGenerateUUID(sessionFunc, s
 
 function fakeIdleNotification(topic) {
   let session = Cu.import("resource://gre/modules/TelemetrySession.jsm");
   return session.TelemetryScheduler.observe(null, topic, null);
 }
 
 function setupTestData() {
 
-  Telemetry.histogramFrom(IGNORE_CLONED_HISTOGRAM, IGNORE_HISTOGRAM_TO_CLONE);
   Services.startup.interrupted = true;
   Telemetry.registerAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM,
                                    Telemetry.HISTOGRAM_LINEAR,
                                    1, 5, 6);
   let h1 = Telemetry.getAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM);
   h1.add(1);
   let h2 = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
   h2.add();
@@ -329,24 +328,16 @@ function checkPayload(payload, reason, s
   const TELEMETRY_TEST_KEYED_COUNT = "TELEMETRY_TEST_KEYED_COUNT";
 
   if (successfulPings > 0) {
     Assert.ok(TELEMETRY_PING in payload.histograms);
   }
   Assert.ok(TELEMETRY_TEST_FLAG in payload.histograms);
   Assert.ok(TELEMETRY_TEST_COUNT in payload.histograms);
 
-  let rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
-  for (let name of rh) {
-    if (/SQLITE/.test(name) && name in payload.histograms) {
-      let histogramName = ("STARTUP_" + name);
-      Assert.ok(histogramName in payload.histograms, histogramName + " must be available.");
-    }
-  }
-
   Assert.ok(!(IGNORE_CLONED_HISTOGRAM in payload.histograms));
 
   // Flag histograms should automagically spring to life.
   const expected_flag = {
     range: [1, 2],
     bucket_count: 3,
     histogram_type: 3,
     values: {0:1, 1:0},
--- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
+++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js
@@ -240,45 +240,16 @@ add_task(function* test_getHistogramById
   }
   var h = Telemetry.getHistogramById("CYCLE_COLLECTOR");
   var s = h.snapshot();
   do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_EXPONENTIAL);
   do_check_eq(s.min, 1);
   do_check_eq(s.max, 10000);
 });
 
-add_task(function* test_histogramFrom() {
-  // Test one histogram of each type.
-  let names = [
-      "CYCLE_COLLECTOR",      // EXPONENTIAL
-      "GC_REASON_2",          // LINEAR
-      "GC_RESET",             // BOOLEAN
-      "TELEMETRY_TEST_FLAG",  // FLAG
-      "TELEMETRY_TEST_COUNT", // COUNT
-  ];
-
-  for (let name of names) {
-    let [min, max, bucket_count] = [1, INT_MAX - 1, 10]
-    let original = Telemetry.getHistogramById(name);
-    let clone = Telemetry.histogramFrom("clone" + name, name);
-    compareHistograms(original, clone);
-  }
-
-  // Additionally, set TELEMETRY_TEST_FLAG and TELEMETRY_TEST_COUNT
-  // and check they get set on the clone.
-  let testFlag = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG");
-  testFlag.add(1);
-  let testCount = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT");
-  testCount.add();
-  let clone = Telemetry.histogramFrom("FlagClone", "TELEMETRY_TEST_FLAG");
-  compareHistograms(testFlag, clone);
-  clone = Telemetry.histogramFrom("CountClone", "TELEMETRY_TEST_COUNT");
-  compareHistograms(testCount, clone);
-});
-
 add_task(function* test_getSlowSQL() {
   var slow = Telemetry.slowSQL;
   do_check_true(("mainThread" in slow) && ("otherThreads" in slow));
 });
 
 add_task(function* test_getWebrtc() {
   var webrtc = Telemetry.webrtcStats;
   do_check_true("IceCandidatesStats" in webrtc);
@@ -437,28 +408,24 @@ add_task(function* test_addons() {
   snapshots = Telemetry.addonHistogramSnapshots;
   do_check_false(addon_id in snapshots);
   // Make sure other addons are unaffected.
   do_check_true(extra_addon in snapshots);
 });
 
 add_task(function* test_expired_histogram() {
   var test_expired_id = "TELEMETRY_TEST_EXPIRED";
-  var clone_id = "ExpiredClone";
   var dummy = Telemetry.getHistogramById(test_expired_id);
-  var dummy_clone = Telemetry.histogramFrom(clone_id, test_expired_id);
   var rh = Telemetry.registeredHistograms(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, []);
   Assert.ok(!!rh);
 
   dummy.add(1);
-  dummy_clone.add(1);
 
   do_check_eq(Telemetry.histogramSnapshots["__expired__"], undefined);
   do_check_eq(Telemetry.histogramSnapshots[test_expired_id], undefined);
-  do_check_eq(Telemetry.histogramSnapshots[clone_id], undefined);
   do_check_eq(rh[test_expired_id], undefined);
 });
 
 add_task(function* test_keyed_histogram() {
   // Check that invalid names get rejected.
 
   let threw = false;
   try {
--- a/toolkit/components/timermanager/nsUpdateTimerManager.js
+++ b/toolkit/components/timermanager/nsUpdateTimerManager.js
@@ -29,18 +29,17 @@ XPCOMUtils.defineLazyGetter(this, "gLogE
  *           The default value to return in the event the preference has
  *           no setting
  *  @returns The value of the preference, or undefined if there was no
  *           user or default value.
  */
 function getPref(func, preference, defaultValue) {
   try {
     return Services.prefs[func](preference);
-  }
-  catch (e) {
+  } catch (e) {
   }
   return defaultValue;
 }
 
 /**
  *  Logs a string to the error console.
  *  @param   string
  *           The string to write to the error console.
@@ -62,79 +61,81 @@ function TimerManager() {
 }
 TimerManager.prototype = {
   /**
    * The Checker Timer
    */
   _timer: null,
 
   /**
- *    The Checker Timer minimum delay interval as specified by the
- *    app.update.timerMinimumDelay pref. If the app.update.timerMinimumDelay
- *    pref doesn't exist this will default to 120000.
+   * The Checker Timer minimum delay interval as specified by the
+   * app.update.timerMinimumDelay pref. If the app.update.timerMinimumDelay
+   * pref doesn't exist this will default to 120000.
    */
-   _timerMinimumDelay: null,
+  _timerMinimumDelay: null,
 
   /**
    * The set of registered timers.
    */
   _timers: { },
 
   /**
    * See nsIObserver.idl
    */
   observe: function TM_observe(aSubject, aTopic, aData) {
     // Prevent setting the timer interval to a value of less than 30 seconds.
     var minInterval = 30000;
     // Prevent setting the first timer interval to a value of less than 10
     // seconds.
     var minFirstInterval = 10000;
     switch (aTopic) {
-    case "utm-test-init":
-      // Enforce a minimum timer interval of 500 ms for tests and fall through
-      // to profile-after-change to initialize the timer.
-      minInterval = 500;
-      minFirstInterval = 500;
-    case "profile-after-change":
-      // Cancel the timer if it has already been initialized. This is primarily
-      // for tests.
-      this._timerMinimumDelay = Math.max(1000 * getPref("getIntPref", PREF_APP_UPDATE_TIMERMINIMUMDELAY, 120),
-                                         minInterval);
-      let firstInterval = Math.max(getPref("getIntPref", PREF_APP_UPDATE_TIMERFIRSTINTERVAL,
-                                           this._timerMinimumDelay), minFirstInterval);
-      this._canEnsureTimer = true;
-      this._ensureTimer(firstInterval);
-      break;
-    case "xpcom-shutdown":
-      Services.obs.removeObserver(this, "xpcom-shutdown");
+      case "utm-test-init":
+        // Enforce a minimum timer interval of 500 ms for tests and fall through
+        // to profile-after-change to initialize the timer.
+        minInterval = 500;
+        minFirstInterval = 500;
+      case "profile-after-change":
+        // Cancel the timer if it has already been initialized. This is primarily
+        // for tests.
+        this._timerMinimumDelay = Math.max(1000 * getPref("getIntPref", PREF_APP_UPDATE_TIMERMINIMUMDELAY, 120),
+                                           minInterval);
+        let firstInterval = Math.max(getPref("getIntPref", PREF_APP_UPDATE_TIMERFIRSTINTERVAL,
+                                             this._timerMinimumDelay), minFirstInterval);
+        this._canEnsureTimer = true;
+        this._ensureTimer(firstInterval);
+        break;
+      case "xpcom-shutdown":
+        Services.obs.removeObserver(this, "xpcom-shutdown");
 
-      // Release everything we hold onto.
-      this._cancelTimer();
-      for (var timerID in this._timers)
-        delete this._timers[timerID];
-      this._timers = null;
-      break;
+        // Release everything we hold onto.
+        this._cancelTimer();
+        for (var timerID in this._timers) {
+          delete this._timers[timerID];
+        }
+        this._timers = null;
+        break;
     }
   },
 
   /**
    * Called when the checking timer fires.
    *
    * We only fire one notification each time, so that the operations are
    * staggered. We don't want too many to happen at once, which could
    * negatively impact responsiveness.
    *
    * @param   timer
    *          The checking timer that fired.
    */
   notify: function TM_notify(timer) {
     var nextDelay = null;
     function updateNextDelay(delay) {
-      if (nextDelay === null || delay < nextDelay)
+      if (nextDelay === null || delay < nextDelay) {
         nextDelay = delay;
+      }
     }
 
     // Each timer calls tryFire(), which figures out which is the one that
     // wanted to be called earliest. That one will be fired; the others are
     // skipped and will be done later.
     var now = Math.round(Date.now() / 1000);
 
     var callbackToFire = null;
@@ -144,28 +145,29 @@ TimerManager.prototype = {
     function tryFire(callback, intendedTime) {
       var selected = false;
       if (intendedTime <= now) {
         if (intendedTime < earliestIntendedTime ||
             earliestIntendedTime === null) {
           callbackToFire = callback;
           earliestIntendedTime = intendedTime;
           selected = true;
+        } else if (earliestIntendedTime !== null) {
+          skippedFirings = true;
         }
-        else if (earliestIntendedTime !== null)
-          skippedFirings = true;
       }
       // We do not need to updateNextDelay for the timer that actually fires;
       // we'll update right after it fires, with the proper intended time.
       // Note that we might select one, then select another later (with an
       // earlier intended time); it is still ok that we did not update for
       // the first one, since if we have skipped firings, the next delay
       // will be the minimum delay anyhow.
-      if (!selected)
+      if (!selected) {
         updateNextDelay(intendedTime - now);
+      }
     }
 
     var catMan = Cc["@mozilla.org/categorymanager;1"].
                  getService(Ci.nsICategoryManager);
     var entries = catMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
     while (entries.hasMoreElements()) {
       let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
       let value = catMan.getCategoryEntry(CATEGORY_UPDATE_TIMER, entry);
@@ -185,28 +187,29 @@ TimerManager.prototype = {
                                                                       timerID);
       // Initialize the last update time to 0 when the preference isn't set so
       // the timer will be notified soon after a new profile's first use.
       lastUpdateTime = getPref("getIntPref", prefLastUpdate, 0);
 
       // If the last update time is greater than the current time then reset
       // it to 0 and the timer manager will correct the value when it fires
       // next for this consumer.
-      if (lastUpdateTime > now)
+      if (lastUpdateTime > now) {
         lastUpdateTime = 0;
+      }
 
-      if (lastUpdateTime == 0)
+      if (lastUpdateTime == 0) {
         Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
+      }
 
-      tryFire(function() {
+      tryFire(function () {
         try {
           Components.classes[cid][method](Ci.nsITimerCallback).notify(timer);
           LOG("TimerManager:notify - notified " + cid);
-        }
-        catch (e) {
+        } catch (e) {
           LOG("TimerManager:notify - error notifying component id: " +
               cid + " ,error: " + e);
         }
         lastUpdateTime = now;
         Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
         updateNextDelay(lastUpdateTime + interval - now);
       }, lastUpdateTime + interval);
     }
@@ -217,74 +220,75 @@ TimerManager.prototype = {
       // If the last update time is greater than the current time then reset
       // it to 0 and the timer manager will correct the value when it fires
       // next for this consumer.
       if (timerData.lastUpdateTime > now) {
         let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, timerID);
         timerData.lastUpdateTime = 0;
         Services.prefs.setIntPref(prefLastUpdate, timerData.lastUpdateTime);
       }
-      tryFire(function() {
+      tryFire(function () {
         if (timerData.callback && timerData.callback.notify) {
           try {
             timerData.callback.notify(timer);
             LOG("TimerManager:notify - notified timerID: " + timerID);
-          }
-          catch (e) {
+          } catch (e) {
             LOG("TimerManager:notify - error notifying timerID: " + timerID +
                 ", error: " + e);
           }
-        }
-        else {
+        } else {
           LOG("TimerManager:notify - timerID: " + timerID + " doesn't " +
               "implement nsITimerCallback - skipping");
         }
         lastUpdateTime = now;
         timerData.lastUpdateTime = lastUpdateTime;
         let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, timerID);
         Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
         updateNextDelay(timerData.lastUpdateTime + timerData.interval - now);
       }, timerData.lastUpdateTime + timerData.interval);
     }
 
-    if (callbackToFire)
+    if (callbackToFire) {
       callbackToFire();
+    }
 
     if (nextDelay !== null) {
-      if (skippedFirings)
+      if (skippedFirings) {
         timer.delay = this._timerMinimumDelay;
-      else
+      } else {
         timer.delay = Math.max(nextDelay * 1000, this._timerMinimumDelay);
+      }
       this.lastTimerReset = Date.now();
     } else {
       this._cancelTimer();
     }
   },
 
   /**
    * Starts the timer, if necessary, and ensures that it will fire soon enough
    * to happen after time |interval| (in milliseconds).
    */
-  _ensureTimer: function(interval) {
-    if (!this._canEnsureTimer)
+  _ensureTimer: function (interval) {
+    if (!this._canEnsureTimer) {
       return;
+    }
     if (!this._timer) {
       this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
       this._timer.initWithCallback(this, interval,
                                    Ci.nsITimer.TYPE_REPEATING_SLACK);
       this.lastTimerReset = Date.now();
     } else if (Date.now() + interval < this.lastTimerReset + this._timer.delay) {
       this._timer.delay = Math.max(this.lastTimerReset + interval - Date.now(), 0);
     }
   },
 
   /**
    * Stops the timer, if it is running.
    */
-  _cancelTimer: function() {
+  _cancelTimer: function () {
     if (this._timer) {
       this._timer.cancel();
       this._timer = null;
     }
   },
 
   /**
    * See nsIUpdateTimerManager.idl
@@ -295,23 +299,25 @@ TimerManager.prototype = {
       LOG("TimerManager:registerTimer - Ignoring second registration for " + id);
       return;
     }
     let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, id);
     // Initialize the last update time to 0 when the preference isn't set so
     // the timer will be notified soon after a new profile's first use.
     let lastUpdateTime = getPref("getIntPref", prefLastUpdate, 0);
     let now = Math.round(Date.now() / 1000);
-    if (lastUpdateTime > now)
+    if (lastUpdateTime > now) {
       lastUpdateTime = 0;
-    if (lastUpdateTime == 0)
+    }
+    if (lastUpdateTime == 0) {
       Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime);
-    this._timers[id] = { callback       : callback,
-                         interval       : interval,
-                         lastUpdateTime : lastUpdateTime };
+    }
+    this._timers[id] = {callback: callback,
+                        interval: interval,
+                        lastUpdateTime: lastUpdateTime};
 
     this._ensureTimer(interval * 1000);
   },
 
   classID: Components.ID("{B322A5C0-A419-484E-96BA-D7182163899F}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateTimerManager,
                                          Ci.nsITimerCallback,
                                          Ci.nsIObserver])
--- a/toolkit/components/timermanager/tests/unit/consumerNotifications.js
+++ b/toolkit/components/timermanager/tests/unit/consumerNotifications.js
@@ -18,118 +18,273 @@ const PREF_APP_UPDATE_TIMERMINIMUMDELAY 
 const PREF_APP_UPDATE_TIMERFIRSTINTERVAL = "app.update.timerFirstInterval";
 const PREF_APP_UPDATE_LOG_ALL = "app.update.log.all";
 const PREF_BRANCH_LAST_UPDATE_TIME = "app.update.lastUpdateTime.";
 
 const MAIN_TIMER_INTERVAL = 1000;  // milliseconds
 const CONSUMER_TIMER_INTERVAL = 1; // seconds
 
 const TESTS = [ {
-  desc            : "Test Timer Callback 1",
-  timerID         : "test1-update-timer",
-  defaultInterval : "bogus",
-  prefInterval    : "test1.timer.interval",
-  contractID      : "@mozilla.org/test1/timercallback;1",
-  method          : "createInstance",
-  classID         : Components.ID("9c7ce81f-98bb-4729-adb4-4d0deb0f59e5"),
-  notified        : false
+  desc: "Test Timer Callback 1",
+  timerID: "test1-update-timer",
+  defaultInterval: "bogus",
+  prefInterval: "test1.timer.interval",
+  contractID: "@mozilla.org/test1/timercallback;1",
+  method: "createInstance",
+  classID: Components.ID("9c7ce81f-98bb-4729-adb4-4d0deb0f59e5"),
+  notified: false
 }, {
-  desc            : "Test Timer Callback 2",
-  timerID         : "test2-update-timer",
-  defaultInterval : 86400,
-  prefInterval    : "test2.timer.interval",
-  contractID      : "@mozilla.org/test2/timercallback;1",
-  method          : "createInstance",
-  classID         : Components.ID("512834f3-05bb-46be-84e0-81d881a140b7"),
-  notified        : false
+  desc: "Test Timer Callback 2",
+  timerID: "test2-update-timer",
+  defaultInterval: 86400,
+  prefInterval: "test2.timer.interval",
+  contractID: "@mozilla.org/test2/timercallback;1",
+  method: "createInstance",
+  classID: Components.ID("512834f3-05bb-46be-84e0-81d881a140b7"),
+  notified: false
 }, {
-  desc            : "Test Timer Callback 3",
-  timerID         : "test3-update-timer",
-  defaultInterval : CONSUMER_TIMER_INTERVAL,
-  prefInterval    : "test3.timer.interval",
-  contractID      : "@mozilla.org/test3/timercallback;1",
-  method          : "createInstance",
-  classID         : Components.ID("c8ac5027-8d11-4471-9d7c-fd692501b437"),
-  notified        : false
+  desc: "Test Timer Callback 3",
+  timerID: "test3-update-timer",
+  defaultInterval: CONSUMER_TIMER_INTERVAL,
+  prefInterval: "test3.timer.interval",
+  contractID: "@mozilla.org/test3/timercallback;1",
+  method: "createInstance",
+  classID: Components.ID("c8ac5027-8d11-4471-9d7c-fd692501b437"),
+  notified: false
 }, {
-  desc            : "Test Timer Callback 4",
-  timerID         : "test4-update-timer",
-  defaultInterval : CONSUMER_TIMER_INTERVAL,
-  prefInterval    : "test4.timer.interval",
-  contractID      : "@mozilla.org/test4/timercallback;1",
-  method          : "createInstance",
-  classID         : Components.ID("6b0e79f3-4ab8-414c-8f14-dde10e185727"),
-  notified        : false
+  desc: "Test Timer Callback 4",
+  timerID: "test4-update-timer",
+  defaultInterval: CONSUMER_TIMER_INTERVAL,
+  prefInterval: "test4.timer.interval",
+  contractID: "@mozilla.org/test4/timercallback;1",
+  method: "createInstance",
+  classID: Components.ID("6b0e79f3-4ab8-414c-8f14-dde10e185727"),
+  notified: false
 }, {
-  desc            : "Test Timer Callback 5",
-  timerID         : "test5-update-timer",
-  defaultInterval : CONSUMER_TIMER_INTERVAL,
-  prefInterval    : "test5.timer.interval",
-  contractID      : "@mozilla.org/test5/timercallback;1",
-  method          : "createInstance",
-  classID         : Components.ID("2f6b7b92-e40f-4874-bfbb-eeb2412c959d"),
-  notified        : false
+  desc: "Test Timer Callback 5",
+  timerID: "test5-update-timer",
+  defaultInterval: CONSUMER_TIMER_INTERVAL,
+  prefInterval: "test5.timer.interval",
+  contractID: "@mozilla.org/test5/timercallback;1",
+  method: "createInstance",
+  classID: Components.ID("2f6b7b92-e40f-4874-bfbb-eeb2412c959d"),
+  notified: false
 }, {
-  desc            : "Test Timer Callback 6",
-  timerID         : "test6-update-timer",
-  defaultInterval : 86400,
-  prefInterval    : "test6.timer.interval",
-  contractID      : "@mozilla.org/test6/timercallback;1",
-  method          : "createInstance",
-  classID         : Components.ID("8a95f611-b2ac-4c7e-8b73-9748c4839731"),
-  notified        : false
+  desc: "Test Timer Callback 6",
+  timerID: "test6-update-timer",
+  defaultInterval: 86400,
+  prefInterval: "test6.timer.interval",
+  contractID: "@mozilla.org/test6/timercallback;1",
+  method: "createInstance",
+  classID: Components.ID("8a95f611-b2ac-4c7e-8b73-9748c4839731"),
+  notified: false
 }, {
-  desc            : "Test Timer Callback 7",
-  timerID         : "test7-update-timer",
-  defaultInterval : CONSUMER_TIMER_INTERVAL,
-  prefInterval    : "test7.timer.interval",
-  contractID      : "@mozilla.org/test7/timercallback;1",
-  method          : "createInstance",
-  classID         : Components.ID("2d091020-e23c-11e2-a28f-0800200c9a66"),
-  notified        : false
+  desc: "Test Timer Callback 7",
+  timerID: "test7-update-timer",
+  defaultInterval: CONSUMER_TIMER_INTERVAL,
+  prefInterval: "test7.timer.interval",
+  contractID: "@mozilla.org/test7/timercallback;1",
+  method: "createInstance",
+  classID: Components.ID("2d091020-e23c-11e2-a28f-0800200c9a66"),
+  notified: false
 }, {
-  desc            : "Test Timer Callback 8",
-  timerID         : "test8-update-timer",
-  defaultInterval : CONSUMER_TIMER_INTERVAL,
-  contractID      : "@mozilla.org/test8/timercallback;1",
-  classID         : Components.ID("af878d4b-1d12-41f6-9a90-4e687367ecc1"),
-  notified        : false,
-  lastUpdateTime  : 0
+  desc: "Test Timer Callback 8",
+  timerID: "test8-update-timer",
+  defaultInterval: CONSUMER_TIMER_INTERVAL,
+  contractID: "@mozilla.org/test8/timercallback;1",
+  classID: Components.ID("af878d4b-1d12-41f6-9a90-4e687367ecc1"),
+  notified: false,
+  lastUpdateTime: 0
 }, {
-  desc            : "Test Timer Callback 9",
-  timerID         : "test9-update-timer",
-  defaultInterval : CONSUMER_TIMER_INTERVAL,
-  contractID      : "@mozilla.org/test9/timercallback;1",
-  classID         : Components.ID("5136b201-d64c-4328-8cf1-1a63491cc117"),
-  notified        : false,
-  lastUpdateTime  : 0
+  desc: "Test Timer Callback 9",
+  timerID: "test9-update-timer",
+  defaultInterval: CONSUMER_TIMER_INTERVAL,
+  contractID: "@mozilla.org/test9/timercallback;1",
+  classID: Components.ID("5136b201-d64c-4328-8cf1-1a63491cc117"),
+  notified: false,
+  lastUpdateTime: 0
 } ];
 
 const DEBUG_TEST = false;
 
 var gUTM;
 var gNextFunc;
 
 XPCOMUtils.defineLazyServiceGetter(this, "gPref",
                                    "@mozilla.org/preferences-service;1",
                                    "nsIPrefBranch");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gCatMan",
                                    "@mozilla.org/categorymanager;1",
                                    "nsICategoryManager");
 
-XPCOMUtils.defineLazyGetter(this, "gCompReg", function() {
+XPCOMUtils.defineLazyGetter(this, "gCompReg", function () {
   return Cm.QueryInterface(Ci.nsIComponentRegistrar);
 });
 
+const gTest1TimerCallback = {
+  notify: function T1CB_notify(aTimer) {
+    do_throw("gTest1TimerCallback notify method should not have been called");
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest1Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest1TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest2TimerCallback = {
+  notify: function T2CB_notify(aTimer) {
+    do_throw("gTest2TimerCallback notify method should not have been called");
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimer])
+};
+
+const gTest2Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest2TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest3TimerCallback = {
+  notify: function T3CB_notify(aTimer) {
+    do_throw("gTest3TimerCallback notify method should not have been called");
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest3Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest3TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest4TimerCallback = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest4Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest4TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest5TimerCallback = {
+  notify: function T5CB_notify(aTimer) {
+    gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, true);
+    TESTS[4].notified = true;
+    finished_test1thru7();
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest5Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest5TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest6TimerCallback = {
+  notify: function T6CB_notify(aTimer) {
+    gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, true);
+    TESTS[5].notified = true;
+    finished_test1thru7();
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest6Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest6TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest7TimerCallback = {
+  notify: function T7CB_notify(aTimer) {
+    gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, true);
+    TESTS[6].notified = true;
+    finished_test1thru7();
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest7Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest7TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest8TimerCallback = {
+  notify: function T8CB_notify(aTimer) {
+    TESTS[7].notified = true;
+    TESTS[7].notifyTime = Date.now();
+    do_execute_soon(function () {
+      check_test8(gTest8TimerCallback);
+    });
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest8Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest8TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
+const gTest9TimerCallback = {
+  notify: function T9CB_notify(aTimer) {
+    TESTS[8].notified = true;
+    TESTS[8].notifyTime = Date.now();
+    do_execute_soon(function () {
+      check_test8(gTest9TimerCallback);
+    });
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
+};
+
+const gTest9Factory = {
+  createInstance: function (aOuter, aIID) {
+    if (aOuter == null) {
+      return gTest9TimerCallback.QueryInterface(aIID);
+    }
+    throw Cr.NS_ERROR_NO_AGGREGATION;
+  }
+};
+
 function run_test() {
   do_test_pending();
 
   // Set the timer to fire every second
-  gPref.setIntPref(PREF_APP_UPDATE_TIMERMINIMUMDELAY, MAIN_TIMER_INTERVAL/1000);
+  gPref.setIntPref(PREF_APP_UPDATE_TIMERMINIMUMDELAY, MAIN_TIMER_INTERVAL / 1000);
   gPref.setIntPref(PREF_APP_UPDATE_TIMERFIRSTINTERVAL, MAIN_TIMER_INTERVAL);
   gPref.setBoolPref(PREF_APP_UPDATE_LOG_ALL, true);
 
   // Remove existing update timers to prevent them from being notified
   let entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
   while (entries.hasMoreElements()) {
     let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
     gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false);
@@ -303,194 +458,38 @@ function check_test8(aTestTimerCallback)
   debugDump("Testing: two registerTimer registered timers last update time " +
             "have been updated");
   for (let i = 0; i < 2; i++) {
     do_check_neq(gPref.getIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID), 1);
   }
   end_test();
 }
 
-const gTest1TimerCallback = {
-  notify: function T1CB_notify(aTimer) {
-    do_throw("gTest1TimerCallback notify method should not have been called");
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest1Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest1TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest2TimerCallback = {
-  notify: function T2CB_notify(aTimer) {
-    do_throw("gTest2TimerCallback notify method should not have been called");
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimer])
-};
-
-const gTest2Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest2TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest3TimerCallback = {
-  notify: function T3CB_notify(aTimer) {
-    do_throw("gTest3TimerCallback notify method should not have been called");
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest3Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest3TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest4TimerCallback = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest4Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest4TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest5TimerCallback = {
-  notify: function T5CB_notify(aTimer) {
-    gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, true);
-    TESTS[4].notified = true;
-    finished_test1thru7();
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest5Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest5TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest6TimerCallback = {
-  notify: function T6CB_notify(aTimer) {
-    gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, true);
-    TESTS[5].notified = true;
-    finished_test1thru7();
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest6Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest6TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest7TimerCallback = {
-  notify: function T7CB_notify(aTimer) {
-    gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, true);
-    TESTS[6].notified = true;
-    finished_test1thru7();
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest7Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest7TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest8TimerCallback = {
-  notify: function T8CB_notify(aTimer) {
-    TESTS[7].notified = true;
-    TESTS[7].notifyTime = Date.now();
-    do_execute_soon(function() {
-      check_test8(gTest8TimerCallback);
-    });
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest8Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest8TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
-const gTest9TimerCallback = {
-  notify: function T9CB_notify(aTimer) {
-    TESTS[8].notified = true;
-    TESTS[8].notifyTime = Date.now();
-    do_execute_soon(function() {
-      check_test8(gTest9TimerCallback);
-    });
-  },
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
-};
-
-const gTest9Factory = {
-  createInstance: function(aOuter, aIID) {
-    if (aOuter == null) {
-      return gTest9TimerCallback.QueryInterface(aIID);
-    }
-    throw Cr.NS_ERROR_NO_AGGREGATION;
-  }
-};
-
 /**
  * Logs TEST-INFO messages.
  *
  * @param  aText
  *         The text to log.
  * @param  aCaller (optional)
  *         An optional Components.stack.caller. If not specified
  *         Components.stack.caller will be used.
  */
 function logTestInfo(aText, aCaller) {
   let caller = aCaller ? aCaller : Components.stack.caller;
-  let now = new Date;
+  let now = new Date();
   let hh = now.getHours();
   let mm = now.getMinutes();
   let ss = now.getSeconds();
   let ms = now.getMilliseconds();
   let time = (hh < 10 ? "0" + hh : hh) + ":" +
              (mm < 10 ? "0" + mm : mm) + ":" +
              (ss < 10 ? "0" + ss : ss) + ":";
   if (ms < 10) {
     time += "00";
-  }
-  else if (ms < 100) {
+  } else if (ms < 100) {
     time += "0";
   }
   time += ms;
   let msg = time + " | TEST-INFO | " + caller.filename + " | [" + caller.name +
             " : " + caller.lineNumber + "] " + aText;
   do_print(msg);
 }
 
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -285,16 +285,34 @@ var snapshotFormatters = {
           $.new("td", String(val)),
         ]);
       });
       addRows("diagnostics", trs);
 
       delete data.info;
     }
 
+    if (AppConstants.NIGHTLY_BUILD) {
+      let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIDOMWindowUtils);
+      let gpuProcessPid = windowUtils.gpuProcessPid;
+
+      if (gpuProcessPid != -1) {
+        let gpuProcessKillButton = $.new("button");
+
+        gpuProcessKillButton.addEventListener("click", function() {
+          windowUtils.terminateGPUProcess();
+        });
+
+        gpuProcessKillButton.textContent = strings.GetStringFromName("gpuProcessKillButton");
+        addRow("diagnostics", "GPUProcessPid", gpuProcessPid);
+        addRow("diagnostics", "GPUProcess", [gpuProcessKillButton]);
+      }
+    }
+
     // graphics-failures-tbody tbody
     if ("failures" in data) {
       // If indices is there, it should be the same length as failures,
       // (see Troubleshoot.jsm) but we check anyway:
       if ("indices" in data && data.failures.length == data.indices.length) {
         let combined = [];
         for (let i = 0; i < data.failures.length; i++) {
           let assembled = assembleFromGraphicsFailure(i, data);
--- a/toolkit/content/widgets/datetimebox.xml
+++ b/toolkit/content/widgets/datetimebox.xml
@@ -202,17 +202,18 @@
       </method>
 
       <method name="setInputValueFromFields">
         <body>
         <![CDATA[
           if (this.isEmpty(this.mHourField.value) ||
               this.isEmpty(this.mMinuteField.value) ||
               (this.mDayPeriodField && this.isEmpty(this.mDayPeriodField.value)) ||
-              (this.mSecondField && this.isEmpty(this.mSecondField.value))) {
+              (this.mSecondField && this.isEmpty(this.mSecondField.value)) ||
+              (this.mMillisecField && this.isEmpty(this.mMillisecField.value))) {
             // We still need to notify picker in case any of the field has
             // changed. If we can set input element value, then notifyPicker
             // will be called in setFieldsFromInputValue().
             this.notifyPicker();
             return;
           }
 
           let hour = Number(this.mHourField.value);
@@ -323,17 +324,17 @@
 
             if (aTargetField == this.mHourField) {
               value = now.getHours() % this.mMaxHourInHour12 ||
                 this.mMaxHourInHour12;
             } else if (aTargetField == this.mMinuteField) {
               value = now.getMinutes();
             } else if (aTargetField == this.mSecondField) {
               value = now.getSeconds();
-            } else if (aTargetField == this.mMillisecondsField) {
+            } else if (aTargetField == this.mMillisecField) {
               value = now.getMilliseconds();
             } else {
               this.log("Field not supported in incrementFieldValue.");
               return;
             }
           } else {
             value = Number(aTargetField.value);
           }
--- a/toolkit/locales/en-US/chrome/global/aboutSupport.properties
+++ b/toolkit/locales/en-US/chrome/global/aboutSupport.properties
@@ -81,16 +81,17 @@ bugLink = bug %1$S
 # LOCALIZATION NOTE %1$S will be replaced with an arbitrary identifier
 # string that can be searched on DXR/MXR or grepped in the source tree.
 unknownFailure = Blocklisted; failure code %1$S
 d3d11layersCrashGuard = D3D11 Compositor
 d3d11videoCrashGuard = D3D11 Video Decoder
 d3d9videoCrashGuard = D3D9 Video Decoder
 glcontextCrashGuard = OpenGL
 resetOnNextRestart = Reset on Next Restart
+gpuProcessKillButton = Terminate GPU Process
 
 minLibVersions = Expected minimum version
 loadedLibVersions = Version in use
 
 hasSeccompBPF = Seccomp-BPF (System Call Filtering)
 hasSeccompTSync = Seccomp Thread Synchronization
 hasUserNamespaces = User Namespaces
 hasPrivilegedUserNamespaces = User Namespaces for privileged processes
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -1104,24 +1104,27 @@ PopupNotifications.prototype = {
     // Ensure we move focus into the panel because it's opened through user interaction:
     this.panel.removeAttribute("noautofocus", "true");
 
     this._reshowNotifications(anchor);
   },
 
   _reshowNotifications: function PopupNotifications_reshowNotifications(anchor, browser) {
     // Mark notifications anchored to this anchor as un-dismissed
-    let notifications = this._getNotificationsForBrowser(browser || this.tabbrowser.selectedBrowser);
+    browser = browser || this.tabbrowser.selectedBrowser;
+    let notifications = this._getNotificationsForBrowser(browser);
     notifications.forEach(function (n) {
       if (n.anchorElement == anchor)
         n.dismissed = false;
     });
 
-    // ...and then show them.
-    this._update(notifications, anchor);
+    if (this._isActiveBrowser(browser)) {
+      // ...and then show them.
+      this._update(notifications, anchor);
+    }
   },
 
   _swapBrowserNotifications: function PopupNotifications_swapBrowserNoficications(ourBrowser, otherBrowser) {
     // When swaping browser docshells (e.g. dragging tab to new window) we need
     // to update our notification map.
 
     let ourNotifications = this._getNotificationsForBrowser(ourBrowser);
     let other = otherBrowser.ownerDocument.defaultView.PopupNotifications;
--- a/toolkit/mozapps/downloads/DownloadUtils.jsm
+++ b/toolkit/mozapps/downloads/DownloadUtils.jsm
@@ -350,36 +350,47 @@ this.DownloadUtils = {
     }
 
     let dts = Cc["@mozilla.org/intl/scriptabledateformat;1"]
               .getService(Ci.nsIScriptableDateFormat);
 
     // Figure out when today begins
     let today = new Date(aNow.getFullYear(), aNow.getMonth(), aNow.getDate());
 
+    // Get locale to use for date/time formatting
+    // TODO: Remove Intl fallback when bug 1215247 is fixed.
+    const locale = typeof Intl === "undefined"
+                   ? undefined
+                   : Cc["@mozilla.org/chrome/chrome-registry;1"]
+                       .getService(Ci.nsIXULChromeRegistry)
+                       .getSelectedLocale("global", true);
+
     // Figure out if the time is from today, yesterday, this week, etc.
     let dateTimeCompact;
     if (aDate >= today) {
       // After today started, show the time
       dateTimeCompact = dts.FormatTime("",
                                        dts.timeFormatNoSeconds,
                                        aDate.getHours(),
                                        aDate.getMinutes(),
                                        0);
     } else if (today - aDate < (24 * 60 * 60 * 1000)) {
       // After yesterday started, show yesterday
       dateTimeCompact = gBundle.GetStringFromName(gStr.yesterday);
     } else if (today - aDate < (6 * 24 * 60 * 60 * 1000)) {
       // After last week started, show day of week
-      dateTimeCompact = aDate.toLocaleFormat("%A");
+      dateTimeCompact = typeof Intl === "undefined"
+                        ? aDate.toLocaleFormat("%A")
+                        : aDate.toLocaleDateString(locale, { weekday: "long" });
     } else {
       // Show month/day
-      let month = aDate.toLocaleFormat("%B");
-      // Remove leading 0 by converting the date string to a number
-      let date = Number(aDate.toLocaleFormat("%d"));
+      let month = typeof Intl === "undefined"
+                  ? aDate.toLocaleFormat("%B")
+                  : aDate.toLocaleDateString(locale, { month: "long" });
+      let date = aDate.getDate();
       dateTimeCompact = gBundle.formatStringFromName(gStr.monthDate, [month, date], 2);
     }
 
     let dateTimeFull = dts.FormatDateTime("",
                                           dts.dateFormatLong,
                                           dts.timeFormatNoSeconds,
                                           aDate.getFullYear(),
                                           aDate.getMonth() + 1,
--- a/toolkit/mozapps/downloads/tests/unit/test_DownloadUtils.js
+++ b/toolkit/mozapps/downloads/tests/unit/test_DownloadUtils.js
@@ -79,29 +79,45 @@ function testAllGetReadableDates()
   const today_11_30     = new Date(2000, 11, 31, 11, 30, 15);
   const today_12_30     = new Date(2000, 11, 31, 12, 30, 15);
   const yesterday_11_30 = new Date(2000, 11, 30, 11, 30, 15);
   const yesterday_12_30 = new Date(2000, 11, 30, 12, 30, 15);
   const twodaysago      = new Date(2000, 11, 29, 11, 30, 15);
   const sixdaysago      = new Date(2000, 11, 25, 11, 30, 15);
   const sevendaysago    = new Date(2000, 11, 24, 11, 30, 15);
 
+  // TODO: Remove Intl fallback when bug 1215247 is fixed.
+  const locale = typeof Intl === "undefined"
+                 ? undefined
+                 : Components.classes["@mozilla.org/chrome/chrome-registry;1"]
+                                     .getService(Components.interfaces.nsIXULChromeRegistry)
+                                     .getSelectedLocale("global", true);
+
   let dts = Components.classes["@mozilla.org/intl/scriptabledateformat;1"].
             getService(Components.interfaces.nsIScriptableDateFormat);
 
   testGetReadableDates(today_11_30, dts.FormatTime("", dts.timeFormatNoSeconds,
                                                    11, 30, 0));
   testGetReadableDates(today_12_30, dts.FormatTime("", dts.timeFormatNoSeconds,
                                                    12, 30, 0));
   testGetReadableDates(yesterday_11_30, "Yesterday");
   testGetReadableDates(yesterday_12_30, "Yesterday");
-  testGetReadableDates(twodaysago, twodaysago.toLocaleFormat("%A"));
-  testGetReadableDates(sixdaysago, sixdaysago.toLocaleFormat("%A"));
-  testGetReadableDates(sevendaysago, sevendaysago.toLocaleFormat("%B") + " " +
-                                     sevendaysago.toLocaleFormat("%d"));
+  testGetReadableDates(twodaysago,
+                       typeof Intl === "undefined"
+                       ? twodaysago.toLocaleFormat("%A")
+                       : twodaysago.toLocaleDateString(locale, { weekday: "long" }));
+  testGetReadableDates(sixdaysago,
+                       typeof Intl === "undefined"
+                       ? sixdaysago.toLocaleFormat("%A")
+                       : sixdaysago.toLocaleDateString(locale, { weekday: "long" }));
+  testGetReadableDates(sevendaysago,
+                       (typeof Intl === "undefined"
+                        ? sevendaysago.toLocaleFormat("%B")
+                        : sevendaysago.toLocaleDateString(locale, { month: "long" })) + " " +
+                       sevendaysago.getDate().toString().padStart(2, "0"));
 
   let [, dateTimeFull] = DownloadUtils.getReadableDates(today_11_30);
   do_check_eq(dateTimeFull, dts.FormatDateTime("", dts.dateFormatLong,
                                                    dts.timeFormatNoSeconds,
                                                    2000, 12, 31, 11, 30, 0));
 }
 
 function run_test()
--- a/tools/rewriting/ThirdPartyPaths.txt
+++ b/tools/rewriting/ThirdPartyPaths.txt
@@ -15,17 +15,17 @@ gfx/skia/
 gfx/ycbcr/
 intl/hyphenation/hyphen/
 intl/icu/
 ipc/chromium/
 js/src/ctypes/libffi/
 js/src/dtoa.c
 js/src/jit/arm64/vixl/
 media/gmp-clearkey/0.1/openaes/
-media/kiss_ftt/
+media/kiss_fft/
 media/libav/
 media/libcubeb/
 media/libjpeg/
 media/libmkv/
 media/libnestegg/
 media/libogg/
 media/libopus/
 media/libpng/