Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 19 Mar 2016 11:22:28 -0400
changeset 289468 720fb3d55e2859286fd438bfaee0773b91c334ac
parent 289328 b48549fbbe09ff6847997625cab2e7cf05b98391 (current diff)
parent 289467 bd8284e36c7c03dbf2309dc9417eb1b62eecf25a (diff)
child 289499 b3006e4e09af81825badbad69fa3e8c546c7507c
push id30102
push userryanvm@gmail.com
push dateSat, 19 Mar 2016 15:23:17 +0000
treeherdermozilla-central@720fb3d55e28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
dom/push/test/mochitest.ini
dom/workers/Navigator.cpp
dom/workers/Navigator.h
testing/mochitest/runtests.py
testing/web-platform/meta/XMLHttpRequest/responsexml-media-type.htm.ini
testing/web-platform/meta/html/semantics/embedded-content/media-elements/interfaces/TextTrack/oncuechange.html.ini
testing/web-platform/meta/html/semantics/forms/the-input-element/input-textselection-01.html.ini
testing/web-platform/meta/html/semantics/scripting-1/the-template-element/additions-to-parsing-xhtml-documents/node-document.html.ini
testing/web-platform/meta/mediacapture-streams/stream-api/mediastream/stream-ended.html.ini
testing/web-platform/meta/websockets/interfaces/WebSocket/close/close-multiple.html.ini
testing/web-platform/meta/webstorage/event_body_attribute.html.ini
testing/web-platform/tests/html/browsers/history/the-location-interface/non-automated/manual_click_replace_during_load.html
testing/web-platform/tests/html/semantics/forms/the-input-element/input-textselection-01.html
testing/web-platform/tests/mediacapture-streams/stream-api/mediastream/stream-ended.html
--- a/accessible/base/DocManager.cpp
+++ b/accessible/base/DocManager.cpp
@@ -494,17 +494,17 @@ DocManager::CreateDocOrRootAccessible(ns
     // Note: don't use AccReorderEvent to avoid coalsecense and special reorder
     // events processing.
     docAcc->FireDelayedEvent(nsIAccessibleEvent::EVENT_REORDER,
                              ApplicationAcc());
 
     if (IPCAccessibilityActive()) {
       nsIDocShell* docShell = aDocument->GetDocShell();
       if (docShell) {
-        nsCOMPtr<nsITabChild> tabChild = do_GetInterface(docShell);
+        nsCOMPtr<nsITabChild> tabChild = docShell->GetTabChild();
 
         // XXX We may need to handle the case that we don't have a tab child
         // differently.  It may be that this will cause us to fail to notify
         // the parent process about important accessible documents.
         if (tabChild) {
           DocAccessibleChild* ipcDoc = new DocAccessibleChild(docAcc);
           docAcc->SetIPCDoc(ipcDoc);
           static_cast<TabChild*>(tabChild.get())->
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -330,18 +330,23 @@ already_AddRefed<nsIEditor>
 DocAccessible::GetEditor() const
 {
   // Check if document is editable (designMode="on" case). Otherwise check if
   // the html:body (for HTML document case) or document element is editable.
   if (!mDocumentNode->HasFlag(NODE_IS_EDITABLE) &&
       (!mContent || !mContent->HasFlag(NODE_IS_EDITABLE)))
     return nullptr;
 
-  nsCOMPtr<nsISupports> container = mDocumentNode->GetContainer();
-  nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(container));
+  nsCOMPtr<nsIDocShell> docShell = mDocumentNode->GetDocShell();
+  if (!docShell) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIEditingSession> editingSession;
+  docShell->GetEditingSession(getter_AddRefs(editingSession));
   if (!editingSession)
     return nullptr; // No editing session interface
 
   nsCOMPtr<nsIEditor> editor;
   editingSession->GetEditorForWindow(mDocumentNode->GetWindow(), getter_AddRefs(editor));
   if (!editor)
     return nullptr;
 
@@ -1242,22 +1247,16 @@ DocAccessible::GetAccessibleOrContainer(
     // Fallback to just get parent node, in case there is no parent content
     // node. Or current node is not a content node.
     if (!parent)
       parent = currNode->GetParentNode();
 
     if (!(currNode = parent)) break;
   }
 
-  // HTML comboboxes have no-content list accessible as an intermediate
-  // containing all options.
-  if (accessible && accessible->IsHTMLCombobox()) {
-    return accessible->FirstChild();
-  }
-
   return accessible;
 }
 
 Accessible*
 DocAccessible::GetAccessibleOrDescendant(nsINode* aNode) const
 {
   Accessible* acc = GetAccessible(aNode);
   if (acc)
@@ -1696,16 +1695,22 @@ DocAccessible::ProcessContentInserted(Ac
       // If new root content has been inserted then update it.
       UpdateRootElIfNeeded();
 
       // Continue to update the tree even if we don't have root content.
       // For example, elements may be inserted under the document element while
       // there is no HTML body element.
     }
 
+    // HTML comboboxes have no-content list accessible as an intermediate
+    // containing all options.
+    if (container && container->IsHTMLCombobox()) {
+      container = container->FirstChild();
+    }
+
     // We have a DOM/layout change under the container accessible, and its tree
     // might need an update. Since DOM/layout change of the element may affect
     // on the accessibleness of adjacent elements (for example, insertion of
     // extra HTML:body make the old body accessible) then we have to recache
     // children of the container, and then fire show/hide events for a change.
     UpdateTreeOnInsertion(container);
     break;
   }
--- a/accessible/generic/HyperTextAccessible.cpp
+++ b/accessible/generic/HyperTextAccessible.cpp
@@ -1309,17 +1309,18 @@ HyperTextAccessible::GetEditor() const
 
       ancestor = ancestor->Parent();
     }
 
     return nullptr;
   }
 
   nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mContent);
-  nsCOMPtr<nsIEditingSession> editingSession(do_GetInterface(docShell));
+  nsCOMPtr<nsIEditingSession> editingSession;
+  docShell->GetEditingSession(getter_AddRefs(editingSession));
   if (!editingSession)
     return nullptr; // No editing session interface
 
   nsCOMPtr<nsIEditor> editor;
   nsIDocument* docNode = mDoc->DocumentNode();
   editingSession->GetEditorForWindow(docNode->GetWindow(),
                                      getter_AddRefs(editor));
   return editor.forget();
--- a/accessible/tests/mochitest/events/test_valuechange.html
+++ b/accessible/tests/mochitest/events/test_valuechange.html
@@ -127,17 +127,18 @@
       this.getID = function changeRangeValue_getID()
       {
         return prettyName(aID) + " range value changed";
       }
     }
 
     function changeSelectValue(aID, aKey, aValue)
     {
-      this.eventSeq = [new invokerChecker(EVENT_TEXT_VALUE_CHANGE, aID)];
+      this.eventSeq =
+        [ new invokerChecker(EVENT_TEXT_VALUE_CHANGE, getAccessible(aID)) ];
 
       this.invoke = function changeSelectValue_invoke()
       {
         getNode(aID).focus();
         synthesizeKey(aKey, {}, window);
       }
 
       this.finalCheck = function changeSelectValue_finalCheck()
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1602,21 +1602,19 @@ pref("browser.tabs.remote.autostart.2", 
 #endif
 
 // For the about:tabcrashed page
 pref("browser.tabs.crashReporting.sendReport", true);
 pref("browser.tabs.crashReporting.includeURL", false);
 pref("browser.tabs.crashReporting.emailMe", false);
 pref("browser.tabs.crashReporting.email", "");
 
-#ifndef RELEASE_BUILD
 #ifndef MOZ_MULET
 pref("layers.async-pan-zoom.enabled", true);
 #endif
-#endif
 
 // Enable e10s add-on interposition by default.
 pref("extensions.interposition.enabled", true);
 pref("extensions.interposition.prefetching", true);
 
 // Enable blocking of e10s for add-on users on beta/release.
 #ifdef RELEASE_BUILD
 pref("extensions.e10sBlocksEnabling", true);
--- a/browser/base/content/browser-tabsintitlebar.js
+++ b/browser/base/content/browser-tabsintitlebar.js
@@ -30,16 +30,18 @@ var TabsInTitlebar = {
         this._update(true);
     };
     this.onWidgetAdded = this.onWidgetRemoved = function(aWidgetId, aArea) {
       if (aArea == CustomizableUI.AREA_TABSTRIP || aArea == CustomizableUI.AREA_MENUBAR)
         this._update(true);
     };
     CustomizableUI.addListener(this);
 
+    addEventListener("resolutionchange", this, false);
+
     this._initialized = true;
   },
 
   allowedBy: function (condition, allow) {
     if (allow) {
       if (condition in this._disallowed) {
         delete this._disallowed[condition];
         this._update(true);
@@ -60,16 +62,22 @@ var TabsInTitlebar = {
     return document.documentElement.getAttribute("tabsintitlebar") == "true";
   },
 
   observe: function (subject, topic, data) {
     if (topic == "nsPref:changed")
       this._readPref();
   },
 
+  handleEvent: function (aEvent) {
+    if (aEvent.type == "resolutionchange" && aEvent.target == window) {
+      this._update(true);
+    }
+  },
+
   _onMenuMutate: function (aMutations) {
     for (let mutation of aMutations) {
       if (mutation.attributeName == "inactive" ||
           mutation.attributeName == "autohide") {
         TabsInTitlebar._update(true);
         return;
       }
     }
@@ -197,19 +205,20 @@ var TabsInTitlebar = {
           titlebarContent.style.marginBottom = extraMargin + "px";
         }
 
         titlebarContentHeight += extraMargin;
       } else {
         titlebarContent.style.removeProperty("margin-bottom");
       }
 
-      // Then we bring up the titlebar by the same amount, but we add any negative margin:
-      titlebar.style.marginBottom = "-" + titlebarContentHeight + "px";
-
+      // Then add a negative margin to the titlebar, so that the following elements
+      // will overlap it by the lesser of the titlebar height or the tabstrip+menu.
+      let minTitlebarOrTabsHeight = Math.min(titlebarContentHeight, tabAndMenuHeight);
+      titlebar.style.marginBottom = "-" + minTitlebarOrTabsHeight + "px";
 
       // Finally, size the placeholders:
       if (AppConstants.platform == "macosx") {
         this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
       }
       this._sizePlaceholder("caption-buttons", captionButtonsBoxWidth);
 
     } else {
@@ -236,16 +245,17 @@ var TabsInTitlebar = {
 
   _sizePlaceholder: function (type, width) {
     Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='"+ type +"']"),
                   function (node) { node.width = width; });
   },
 
   uninit: function () {
     this._initialized = false;
+    removeEventListener("resolutionchange", this);
     Services.prefs.removeObserver(this._prefName, this);
     this._menuObserver.disconnect();
     CustomizableUI.removeListener(this);
   }
 };
 
 function updateTitlebarDisplay() {
   if (AppConstants.platform == "macosx") {
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -740,16 +740,19 @@ BrowserGlue.prototype = {
 
     // apply distribution customizations
     // prefs are applied in _onAppDefaults()
     this._distributionCustomizer.applyCustomizations();
 
     // handle any UI migration
     this._migrateUI();
 
+    // Evaluate Webapps.jsm early to resolve ts_paint regression bug 1256667.
+    Cu.import("resource://gre/modules/Webapps.jsm", {});
+
     PageThumbs.init();
     webrtcUI.init();
     AboutHome.init();
 
     DirectoryLinksProvider.init();
     NewTabUtils.init();
     NewTabUtils.links.addProvider(DirectoryLinksProvider);
     AboutNewTab.init();
--- a/browser/components/uitour/test/browser.ini
+++ b/browser/components/uitour/test/browser.ini
@@ -4,49 +4,47 @@ support-files =
   image.png
   uitour.html
   ../UITour-lib.js
 
 [browser_backgroundTab.js]
 skip-if = e10s # Intermittent failures, bug 1244991
 [browser_closeTab.js]
 [browser_fxa.js]
-skip-if = e10s || debug || asan # Bug 1240747 - UITour tests not e10s friendly # updateAppMenuItem leaks
+skip-if = debug || asan # updateAppMenuItem leaks
 [browser_no_tabs.js]
 [browser_openPreferences.js]
 [browser_openSearchPanel.js]
 skip-if = true # Bug 1113038 - Intermittent "Popup was opened"
 [browser_trackingProtection.js]
 skip-if = os == "linux" # Intermittent NS_ERROR_NOT_AVAILABLE [nsIUrlClassifierDBService.beginUpdate]
 tag = trackingprotection
 [browser_trackingProtection_tour.js]
 tag = trackingprotection
 [browser_showMenu_controlCenter.js]
 tag = trackingprotection
 [browser_UITour.js]
-skip-if = os == "linux" || e10s # Intermittent failures, bug 951965
+skip-if = os == "linux" # Intermittent failures, bug 951965
 [browser_UITour2.js]
-skip-if = e10s # Bug 1240747 - UITour.jsm not e10s friendly
 [browser_UITour3.js]
-skip-if = os == "linux" || e10s # Linux: Bug 986760, Bug 989101. Bug 1240747 - UITour.jsm not e10s friendly
+skip-if = os == "linux" # Linux: Bug 986760, Bug 989101.
 [browser_UITour_availableTargets.js]
 [browser_UITour_annotation_size_attributes.js]
 [browser_UITour_defaultBrowser.js]
 [browser_UITour_detach_tab.js]
 skip-if = e10s # Bug 1240747 - UITour.jsm not e10s friendly
 [browser_UITour_forceReaderMode.js]
 [browser_UITour_heartbeat.js]
 skip-if = e10s # Bug 1240747 - UITour.jsm not e10s friendly.
 [browser_UITour_loop.js]
 skip-if = true # Bug 1225832 - New Loop architecture is not compatible with test.
 [browser_UITour_loop_panel.js]
 [browser_UITour_modalDialog.js]
 skip-if = os != "mac" # modal dialog disabling only working on OS X.
 [browser_UITour_observe.js]
-skip-if = e10s # Bug 1240747 - UITour.jsm not e10s friendly.
 [browser_UITour_panel_close_annotation.js]
 skip-if = true # Disabled due to frequent failures, bugs 1026310 and 1032137
 [browser_UITour_pocket.js]
-skip-if = os == "linux" || e10s || debug # Bug 1240747 - UITour.jsm not e10s friendly.
+skip-if = os == "linux" || debug
 [browser_UITour_registerPageID.js]
 [browser_UITour_resetProfile.js]
 [browser_UITour_sync.js]
 [browser_UITour_toggleReaderMode.js]
--- a/browser/components/uitour/test/browser_UITour.js
+++ b/browser/components/uitour/test/browser_UITour.js
@@ -279,17 +279,17 @@ var tests = [
     is(popup.popupBoxObject.anchorNode, document.getElementById("searchbar"), "Popup should be anchored to the searchbar");
     is(title.textContent, "search title", "Popup should have correct title");
     is(desc.textContent, "search text", "Popup should have correct description text");
   }),
   function test_getConfigurationVersion(done) {
     function callback(result) {
       let props = ["defaultUpdateChannel", "version"];
       for (let property of props) {
-        ok(typeof(result[property]) !== undefined, "Check " + property + " isn't undefined.");
+        ok(typeof(result[property]) !== "undefined", "Check " + property + " isn't undefined.");
         is(result[property], Services.appinfo[property], "Should have the same " + property + " property.");
       }
       done();
     }
 
     gContentAPI.getConfiguration("appinfo", callback);
   },
   function test_addToolbarButton(done) {
--- a/browser/components/uitour/test/head.js
+++ b/browser/components/uitour/test/head.js
@@ -267,24 +267,67 @@ function loadUITourTestPage(callback, ho
           };
         },
       };
       gContentWindow = new Proxy({}, contentWinHandler);
 
       let UITourHandler = {
         get(target, prop, receiver) {
           return (...args) => {
+            let browser = gTestTab.linkedBrowser;
+            const proxyFunctionName = "UITourHandler:proxiedfunction-";
+            // We need to proxy any callback functions using messages:
+            let callbackMap = new Map();
+            let fnIndices = [];
+            args = args.map((arg, index) => {
+              // Replace function arguments with "", and add them to the list of
+              // forwarded functions. We'll construct a function on the content-side
+              // that forwards all its arguments to a message, and we'll listen for
+              // those messages on our side and call the corresponding function with
+              // the arguments we got from the content side.
+              if (typeof arg == "function") {
+                callbackMap.set(index, arg);
+                fnIndices.push(index);
+                let handler = function(msg) {
+                  browser.messageManager.removeMessageListener(proxyFunctionName + index, handler);
+                  callbackMap.get(index).apply(null, msg.data);
+                };
+                browser.messageManager.addMessageListener(proxyFunctionName + index, handler);
+                return "";
+              }
+              return arg;
+            });
             let taskArgs = {
               methodName: prop,
               args,
+              fnIndices,
             };
-            return ContentTask.spawn(gTestTab.linkedBrowser, taskArgs, args => {
+            return ContentTask.spawn(browser, taskArgs, function*(args) {
               let contentWin = Components.utils.waiveXrays(content);
-              return contentWin.Mozilla.UITour[args.methodName].apply(contentWin.Mozilla.UITour,
-                                                                      args.args);
+              let callbacksCalled = 0;
+              let resolveCallbackPromise;
+              let allCallbacksCalledPromise = new Promise(resolve => resolveCallbackPromise = resolve);
+              let argumentsWithFunctions = args.args.map((arg, index) => {
+                if (arg === "" && args.fnIndices.includes(index)) {
+                  return function() {
+                    callbacksCalled++;
+                    sendAsyncMessage("UITourHandler:proxiedfunction-" + index, Array.from(arguments));
+                    if (callbacksCalled >= args.fnIndices.length) {
+                      resolveCallbackPromise();
+                    }
+                  };
+                }
+                return arg;
+              });
+              let rv = contentWin.Mozilla.UITour[args.methodName].apply(contentWin.Mozilla.UITour,
+                                                                        argumentsWithFunctions);
+              if (args.fnIndices.length) {
+                yield allCallbacksCalledPromise;
+              }
+              return rv;
             });
           };
         },
       };
       gContentAPI = new Proxy({}, UITourHandler);
     } else {
       gContentWindow = Components.utils.waiveXrays(gTestTab.linkedBrowser.contentDocument.defaultView);
       gContentAPI = gContentWindow.Mozilla.UITour;
--- a/browser/extensions/loop/chrome/content/modules/MozLoopPushHandler.jsm
+++ b/browser/extensions/loop/chrome/content/modules/MozLoopPushHandler.jsm
@@ -61,17 +61,17 @@ PushSocket.prototype = {
     this._onClose = onClose;
 
     if (!this._websocket) {
       this._websocket = Cc["@mozilla.org/network/protocol;1?name=wss"]
                           .createInstance(Ci.nsIWebSocketChannel);
       this._websocket.initLoadInfo(null, // aLoadingNode
                                    Services.scriptSecurityManager.getSystemPrincipal(),
                                    null, // aTriggeringPrincipal
-                                   Ci.nsILoadInfo.SEC_NORMAL,
+                                   Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
                                    Ci.nsIContentPolicy.TYPE_WEBSOCKET);
     }
 
     let uri = Services.io.newURI(pushUri, null, null);
     this._websocket.protocol = "push-notification";
     this._websocket.asyncOpen(uri, pushUri, 0, this, null);
   },
 
--- a/browser/themes/linux/devedition.css
+++ b/browser/themes/linux/devedition.css
@@ -3,16 +3,27 @@
 % file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 %include ../shared/devedition.inc.css
 
 :root {
   --forwardbutton-width: 29px;
 }
 
+:root[devtoolstheme="light"] {
+  --urlbar-dropmarker-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
+  --urlbar-dropmarker-region: rect(0px, 11px, 14px, 0px);
+  --urlbar-dropmarker-hover-region: rect(0, 22px, 14px, 11px);
+  --urlbar-dropmarker-active-region: rect(0px, 33px, 14px, 22px);
+  --urlbar-dropmarker-2x-url: url("chrome://browser/skin/devedition/urlbar-history-dropmarker.svg");
+  --urlbar-dropmarker-2x-region: rect(0px, 11px, 14px, 0px);
+  --urlbar-dropmarker-hover-2x-region: rect(0, 22px, 14px, 11px);
+  --urlbar-dropmarker-active-2x-region: rect(0px, 33px, 14px, 22px);
+}
+
 :root[devtoolstheme="dark"] .findbar-closebutton:not(:hover),
 :root[devtoolstheme="dark"] #sidebar-header > .close-icon:not(:hover),
 .tab-close-button[visuallyselected]:not(:hover) {
   background-image: -moz-image-rect(url("chrome://global/skin/icons/close.svg"), 0, 80, 16, 64);
 }
 
 /* The menubar and tabs toolbar should match the devedition theme */
 #TabsToolbar,
--- a/build/moz.configure/checks.configure
+++ b/build/moz.configure/checks.configure
@@ -47,16 +47,18 @@ def checking(what):
 # will look for 'a' or 'b' in $PATH, and set_config PROG to the one
 # it can find. If PROG is already set from the environment or command line,
 # use that value instead.
 @template
 def check_prog(var, progs, allow_missing=False):
     option(env=var, nargs=1, help='Path to the %s program' % var.lower())
 
     not_found = 'not found'
+    if not (isinstance(progs, tuple) or isinstance(progs, list)):
+        configure_error('progs should be a list or tuple!')
     progs = list(progs)
 
     @depends(var)
     @checking('for %s' % var.lower())
     def check(value):
         if value:
             progs[:] = value
         for prog in progs:
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -275,18 +275,18 @@ def wanted_mozconfig_variables(help):
          'UNZIP',
          'USE_FC_FREETYPE',
          'WITHOUT_X',
          'XARGS',
          'ZIP',
      ])
 
 
-@depends(mozconfig, wanted_mozconfig_variables)
-def mozconfig_options(mozconfig, wanted_mozconfig_variables):
+@depends(mozconfig, wanted_mozconfig_variables, '--help')
+def mozconfig_options(mozconfig, wanted_mozconfig_variables, help):
     if mozconfig['path']:
         helper = command_line_helper()
         warn('Adding configure options from %s' % mozconfig['path'])
         for arg in mozconfig['configure_args']:
             warn('  %s' % arg)
             # We could be using imply_option() here, but it has other
             # contraints that don't really apply to the command-line
             # emulation that mozconfig provides.
@@ -558,16 +558,49 @@ def include_project_configure(project, e
 @depends(include_project_configure, check_build_environment, '--help')
 def build_project(include_project_configure, build_env, help):
     ret = os.path.dirname(os.path.relpath(include_project_configure,
                                           build_env['TOPSRCDIR']))
     add_old_configure_assignment('MOZ_BUILD_APP', ret)
     return ret
 
 
+# set RELEASE_BUILD and NIGHTLY_BUILD variables depending on the cycle we're in
+# The logic works like this:
+# - if we have "a1" in GRE_MILESTONE, we're building Nightly (define NIGHTLY_BUILD)
+# - otherwise, if we have "a" in GRE_MILESTONE, we're building Nightly or Aurora
+# - otherwise, we're building Release/Beta (define RELEASE_BUILD)
+@depends(check_build_environment)
+@advanced
+def milestone(build_env):
+    milestone_path = os.path.join(build_env['TOPSRCDIR'],
+                                  'config',
+                                  'milestone.txt')
+    with open(milestone_path, 'r') as fh:
+        milestone = fh.read().splitlines()[-1]
+
+    set_config('GRE_MILESTONE', milestone)
+
+    is_nightly = is_release = False
+
+    if 'a1' in milestone:
+        set_config('NIGHTLY_BUILD', '1')
+        set_define('NIGHTLY_BUILD', '1')
+        add_old_configure_assignment('NIGHTLY_BUILD', '1')
+        is_nightly = True
+    elif 'a' not in milestone:
+        set_config('RELEASE_BUILD', '1')
+        set_define('RELEASE_BUILD', '1')
+        add_old_configure_assignment('RELEASE_BUILD', '1')
+        is_release = True
+
+    return namespace(version=milestone,
+                     is_nightly=is_nightly,
+                     is_release=is_release)
+
 # This is temporary until js/src/configure and configure are merged.
 # Use instead of option() in js/moz.configure
 @template
 def js_option(*args, **kwargs):
     opt = option(*args, **kwargs)
 
     @depends(opt.option, build_project)
     def js_option(value, build_project):
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -2,32 +2,44 @@
 # vim: set filetype=python:
 # 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/.
 
 @template
 @advanced
 def warn(*args):
+    'Print a warning.'
     import sys
     print(*args, file=sys.stderr)
     sys.stderr.flush()
 
 
 @template
 @advanced
 def error(*args):
+    'Print an error and terminate configure.'
     import sys
     print(*args, file=sys.stderr)
     sys.stderr.flush()
     sys.exit(1)
 
 
 @template
 @advanced
+def configure_error(message):
+    '''Raise a programming error and terminate configure.
+    Primarily for use in moz.configure templates to sanity check
+    their inputs from moz.configure usage.'''
+    from mozbuild.configure import ConfigureError
+    raise ConfigureError(message)
+
+
+@template
+@advanced
 def is_absolute_or_relative(path):
     import os
     if os.altsep and os.altsep in path:
         return True
     return os.sep in path
 
 
 @template
@@ -72,16 +84,22 @@ del _defines
 @template
 def unique_list(l):
     result = []
     for i in l:
         if l not in result:
             result.append(i)
     return result
 
+@template
+@advanced
+def Version(v):
+    'A version number that can be compared usefully.'
+    from mozbuild.configure.util import Version as _Version
+    return _Version(v)
 
 # Denotes a deprecated option. Combines option() and @depends:
 # @deprecated_option('--option')
 # def option(value):
 #     ...
 # @deprecated_option() takes the same arguments as option(), except `help`.
 # The function may handle the option like a typical @depends function would,
 # but it is recommended it emits a deprecation error message suggesting an
--- a/devtools/client/webconsole/test/browser.ini
+++ b/devtools/client/webconsole/test/browser.ini
@@ -139,17 +139,16 @@ support-files =
   test_bug1045902_console_csp_ignore_reflected_xss_message.html
   test_bug1092055_shouldwarn.js^headers^
   test_bug1092055_shouldwarn.js
   test_bug1092055_shouldwarn.html
 
 [browser_bug1045902_console_csp_ignore_reflected_xss_message.js]
 skip-if = (e10s && debug) || (e10s && os == 'win') # Bug 1221499 enabled these on windows
 [browser_bug664688_sandbox_update_after_navigation.js]
-skip-if = e10s # Bug 1042253 - webconsole e10s tests (intermittent Linux debug)
 [browser_bug_638949_copy_link_location.js]
 [browser_bug_862916_console_dir_and_filter_off.js]
 skip-if = (e10s && (os == 'win' || os == 'mac')) # Bug 1243976
 [browser_bug_865288_repeat_different_objects.js]
 [browser_bug_865871_variables_view_close_on_esc_key.js]
 [browser_bug_869003_inspect_cross_domain_object.js]
 [browser_bug_871156_ctrlw_close_tab.js]
 skip-if = e10s # Bug 1042253 - webconsole e10s tests (intermittent Linux debug)
new file mode 100644
--- /dev/null
+++ b/docshell/base/crashtests/1257730-1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<!--
+user_pref("browser.send_pings", true);
+-->
+<script>
+
+function boom() {
+  var aLink = document.createElement('a');
+  document.body.appendChild(aLink);
+  aLink.ping = "ping";
+  aLink.href = "href";
+  aLink.click();
+
+  var baseElement = document.createElement('base');
+  baseElement.setAttribute("href", "javascript:void 0");
+  document.head.appendChild(baseElement);
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
--- a/docshell/base/crashtests/crashtests.list
+++ b/docshell/base/crashtests/crashtests.list
@@ -7,8 +7,9 @@ load 432114-1.html
 load 432114-2.html
 load 436900-1.html
 asserts(0-1) load 436900-2.html # bug 566159
 load 500328-1.html
 load 514779-1.xhtml
 load 614499-1.html
 load 678872-1.html
 skip-if(Android||B2G) pref(dom.disable_open_during_load,false) load 914521.html
+pref(browser.send_pings,true) load 1257730-1.html
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -370,17 +370,20 @@ ForEachPing(nsIContent* aContent, ForEac
 
   nsWhitespaceTokenizer tokenizer(value);
 
   while (tokenizer.hasMoreTokens()) {
     nsCOMPtr<nsIURI> uri, baseURI = aContent->GetBaseURI();
     ios->NewURI(NS_ConvertUTF16toUTF8(tokenizer.nextToken()),
                 doc->GetDocumentCharacterSet().get(),
                 baseURI, getter_AddRefs(uri));
-
+    // if we can't generate a valid URI, then there is nothing to do
+    if (!uri) {
+      continue;
+    }
     // Explicitly not allow loading data: URIs
     bool isDataScheme =
       (NS_SUCCEEDED(uri->SchemeIs("data", &isDataScheme)) && isDataScheme);
 
     if (!isDataScheme) {
       aCallback(aClosure, aContent, uri, ios);
     }
   }
@@ -1020,26 +1023,21 @@ nsDocShell::GetInterface(const nsIID& aI
     nsresult rv = EnsureFind();
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     *aSink = mFind;
     NS_ADDREF((nsISupports*)*aSink);
     return NS_OK;
-  } else if (aIID.Equals(NS_GET_IID(nsIEditingSession)) &&
-             NS_SUCCEEDED(EnsureEditorData())) {
-    nsCOMPtr<nsIEditingSession> editingSession;
-    mEditorData->GetEditingSession(getter_AddRefs(editingSession));
-    if (editingSession) {
-      editingSession.forget(aSink);
-      return NS_OK;
-    }
-
-    return NS_NOINTERFACE;
+  } else if (aIID.Equals(NS_GET_IID(nsIEditingSession))) {
+    nsCOMPtr<nsIEditingSession> es;
+    GetEditingSession(getter_AddRefs(es));
+    es.forget(aSink);
+    return *aSink ? NS_OK : NS_NOINTERFACE;
   } else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) &&
              NS_SUCCEEDED(EnsureTransferableHookData())) {
     *aSink = mTransferableHookData;
     NS_ADDREF((nsISupports*)*aSink);
     return NS_OK;
   } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
     nsIPresShell* shell = GetPresShell();
     if (shell) {
@@ -1047,24 +1045,18 @@ nsDocShell::GetInterface(const nsIID& aI
     }
   } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
     nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
     if (NS_SUCCEEDED(rv) && treeOwner) {
       return treeOwner->QueryInterface(aIID, aSink);
     }
   } else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
-    nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
-    nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
-    if (NS_SUCCEEDED(rv) && treeOwner) {
-      nsCOMPtr<nsIInterfaceRequestor> ir = do_QueryInterface(treeOwner);
-      if (ir) {
-        return ir->GetInterface(aIID, aSink);
-      }
-    }
+    *aSink = GetTabChild().take();
+    return *aSink ? NS_OK : NS_ERROR_FAILURE;
   } else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) {
     nsCOMPtr<nsITabChild> tabChild =
       do_GetInterface(static_cast<nsIDocShell*>(this));
     nsCOMPtr<nsIContentFrameMessageManager> mm;
     if (tabChild) {
       tabChild->GetMessageManager(getter_AddRefs(mm));
     } else {
       if (nsPIDOMWindowOuter* win = GetWindow()) {
@@ -14353,8 +14345,34 @@ nsDocShell::IssueWarning(uint32_t aWarni
   if (mContentViewer) {
     nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
     if (doc) {
       doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError);
     }
   }
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsDocShell::GetEditingSession(nsIEditingSession** aEditSession)
+{
+  if (!NS_SUCCEEDED(EnsureEditorData())) {
+    return NS_ERROR_FAILURE;
+  }
+
+  mEditorData->GetEditingSession(aEditSession);
+  return *aEditSession ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild)
+{
+  *aTabChild = GetTabChild().take();
+  return *aTabChild ? NS_OK : NS_ERROR_FAILURE;
+}
+
+already_AddRefed<nsITabChild>
+nsDocShell::GetTabChild()
+{
+  nsCOMPtr<nsIDocShellTreeOwner> owner(mTreeOwner);
+  nsCOMPtr<nsITabChild> tc = do_GetInterface(owner);
+  return tc.forget();
+}
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -21,30 +21,33 @@ class nsIPresShell;
 [ptr] native nsIPresShell(nsIPresShell);
 
 interface nsIURI;
 interface nsIChannel;
 interface nsIContentViewer;
 interface nsIDOMEventTarget;
 interface nsIDocShellLoadInfo;
 interface nsIEditor;
+interface nsIEditingSession;
 interface nsISimpleEnumerator;
 interface nsIInputStream;
 interface nsIRequest;
 interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIScriptGlobalObject;
 interface nsIDOMStorage;
 interface nsIPrincipal;
 interface nsIWebBrowserPrint;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
+interface nsITabChild;
+native TabChildRef(already_AddRefed<nsITabChild>);
 
 typedef unsigned long nsLoadFlags;
 
 [scriptable, builtinclass, uuid(049234fe-da10-478b-bc5d-bc6f9a1ba63d)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
@@ -1086,9 +1089,20 @@ interface nsIDocShell : nsIDocShellTreeI
   /**
    * Setter and getter for the origin attributes living on this docshell.
    */
   [implicit_jscontext]
   jsval getOriginAttributes();
 
   [implicit_jscontext]
   void setOriginAttributes(in jsval aAttrs);
+
+  /**
+   * The editing session for this docshell.
+   */
+  readonly attribute nsIEditingSession editingSession;
+
+  /**
+   * The tab child for this docshell.
+   */
+  [binaryname(ScriptableTabChild)] readonly attribute nsITabChild tabChild;
+  [noscript,notxpcom,nostdcall] TabChildRef GetTabChild();
 };
--- a/dom/base/BarProps.cpp
+++ b/dom/base/BarProps.cpp
@@ -282,33 +282,17 @@ ScrollbarsProp::SetVisible(bool aVisible
 
   /* Scrollbars, unlike the other barprops, implement visibility directly
      rather than handing off to the superclass (and from there to the
      chrome window) because scrollbar visibility uniquely applies only
      to the window making the change (arguably. it does now, anyway.)
      and because embedding apps have no interface for implementing this
      themselves, and therefore the implementation must be internal. */
 
-  nsCOMPtr<nsIScrollable> scroller =
-    do_QueryInterface(mDOMWindow->GetDocShell());
-
-  if (scroller) {
-    int32_t prefValue;
-
-    if (aVisible) {
-      prefValue = nsIScrollable::Scrollbar_Auto;
-    } else {
-      prefValue = nsIScrollable::Scrollbar_Never;
-    }
-
-    scroller->SetDefaultScrollbarPreferences(
-                nsIScrollable::ScrollOrientation_Y, prefValue);
-    scroller->SetDefaultScrollbarPreferences(
-                nsIScrollable::ScrollOrientation_X, prefValue);
-  }
+  nsContentUtils::SetScrollbarsVisibility(mDOMWindow->GetDocShell(), aVisible);
 
   /* Notably absent is the part where we notify the chrome window using
      GetBrowserChrome()->SetChromeFlags(). Given the possibility of multiple
      DOM windows (multiple top-level windows, even) within a single
      chrome window, the historical concept of a single "has scrollbars"
      flag in the chrome is inapplicable, and we can't tell at this level
      whether we represent the particular DOM window that makes this decision
      for the chrome.
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -1328,22 +1328,24 @@ Console::ProcessCallData(ConsoleCallData
   AssertIsOnMainThread();
   MOZ_ASSERT(aData);
 
   ConsoleStackEntry frame;
   if (aData->mTopStackFrame) {
     frame = *aData->mTopStackFrame;
   }
 
-  AutoSafeJSContext cx;
+  AutoJSAPI jsapi;
+  if (!jsapi.Init(aGlobal)) {
+    return;
+  }
+  JSContext* cx = jsapi.cx();
   ClearException ce(cx);
   RootedDictionary<ConsoleEvent> event(cx);
 
-  JSAutoCompartment ac(cx, aGlobal);
-
   event.mID.Construct();
   event.mInnerID.Construct();
 
   MOZ_ASSERT(aData->mIDType != ConsoleCallData::eUnknown);
   if (aData->mIDType == ConsoleCallData::eString) {
     event.mID.Value().SetAsString() = aData->mOuterIDString;
     event.mInnerID.Value().SetAsString() = aData->mInnerIDString;
   } else {
--- a/dom/base/DirectionalityUtils.cpp
+++ b/dom/base/DirectionalityUtils.cpp
@@ -565,21 +565,22 @@ public:
   static uint32_t UpdateTextNodeDirection(nsINode* aTextNode,
                                           Directionality aDir)
   {
     MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(),
                "Map missing in UpdateTextNodeDirection");
     return GetDirectionalityMap(aTextNode)->UpdateAutoDirection(aDir);
   }
 
-  static void ResetTextNodeDirection(nsINode* aTextNode)
+  static void ResetTextNodeDirection(nsINode* aTextNode,
+                                     nsINode* aChangedTextNode)
   {
     MOZ_ASSERT(aTextNode->HasTextNodeDirectionalityMap(),
                "Map missing in ResetTextNodeDirection");
-    GetDirectionalityMap(aTextNode)->ResetAutoDirection(aTextNode);
+    GetDirectionalityMap(aTextNode)->ResetAutoDirection(aChangedTextNode);
   }
 
   static void EnsureMapIsClearFor(nsINode* aTextNode)
   {
     if (aTextNode->HasTextNodeDirectionalityMap()) {
       GetDirectionalityMap(aTextNode)->EnsureMapIsClear(aTextNode);
     }
   }
@@ -676,17 +677,17 @@ WalkDescendantsResetAutoDirection(Elemen
   nsIContent* child = aElement->GetFirstChild();
   while (child) {
     if (child->HasDirAuto()) {
       child = child->GetNextNonChildNode(aElement);
       continue;
     }
 
     if (child->HasTextNodeDirectionalityMap()) {
-      nsTextNodeDirectionalityMap::ResetTextNodeDirection(child);
+      nsTextNodeDirectionalityMap::ResetTextNodeDirection(child, nullptr);
       nsTextNodeDirectionalityMap::EnsureMapIsClearFor(child);
     }
     child = child->GetNextNode(aElement);
   }
 }
 
 void
 WalkDescendantsSetDirAuto(Element* aElement, bool aNotify)
@@ -836,17 +837,17 @@ TextNodeChangedDirection(nsIContent* aTe
 {
   Directionality newDir = GetDirectionFromText(aTextNode->GetText());
   if (newDir == eDir_NotSet) {
     if (aOldDir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
       // This node used to have a strong directional character but no
       // longer does. ResetTextNodeDirection() will re-resolve the
       // directionality of any elements whose directionality was
       // determined by this node.
-      nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode);
+      nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
     }
   } else {
     // This node has a strong directional character. If it has a
     // TextNodeDirectionalityMap property, it already determines the
     // directionality of some element(s), so call UpdateTextNodeDirection to
     // reresolve their directionality. If it has no map, or if
     // UpdateTextNodeDirection returns zero, indicating that the map is
     // empty, call SetAncestorDirectionIfAuto to find ancestor elements
@@ -883,17 +884,17 @@ ResetDirectionSetByTextNode(nsTextNode* 
 {
   if (!NodeAffectsDirAutoAncestor(aTextNode)) {
     nsTextNodeDirectionalityMap::EnsureMapIsClearFor(aTextNode);
     return;
   }
 
   Directionality dir = GetDirectionFromText(aTextNode->GetText());
   if (dir != eDir_NotSet && aTextNode->HasTextNodeDirectionalityMap()) {
-    nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode);
+    nsTextNodeDirectionalityMap::ResetTextNodeDirection(aTextNode, aTextNode);
   }
 }
 
 void
 SetDirectionalityFromValue(Element* aElement, const nsAString& value,
                            bool aNotify)
 {
   Directionality dir = GetDirectionFromText(PromiseFlatString(value).get(),
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -43,16 +43,17 @@
 #include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/Presentation.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
 #include "mozilla/dom/TCPSocket.h"
 #include "mozilla/dom/Telephony.h"
 #include "mozilla/dom/Voicemail.h"
 #include "mozilla/dom/TVManager.h"
 #include "mozilla/dom/VRDevice.h"
+#include "mozilla/dom/workers/RuntimeService.h"
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsGlobalWindow.h"
 #ifdef MOZ_B2G
@@ -745,16 +746,27 @@ Navigator::JavaEnabled(ErrorResult& aRv)
 
   RefreshMIMEArray();
 
   nsMimeType *mimeType = mMimeTypes->NamedItem(javaMIME);
 
   return mimeType && mimeType->GetEnabledPlugin();
 }
 
+uint64_t
+Navigator::HardwareConcurrency()
+{
+  workers::RuntimeService* rts = workers::RuntimeService::GetOrCreateService();
+  if (!rts) {
+    return 1;
+  }
+
+  return rts->ClampedHardwareConcurrency();
+}
+
 void
 Navigator::RefreshMIMEArray()
 {
   if (mMimeTypes) {
     mMimeTypes->Refresh();
   }
 }
 
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -147,16 +147,20 @@ public:
    */
   void OnNavigation();
 
   // Helper to initialize mMessagesManager.
   nsresult EnsureMessagesManager();
 
   // The XPCOM GetProduct is OK
   // The XPCOM GetLanguage is OK
+  void GetUserAgent(nsString& aUserAgent, ErrorResult& /* unused */)
+  {
+    GetUserAgent(aUserAgent);
+  }
   bool OnLine();
   void RegisterProtocolHandler(const nsAString& aScheme, const nsAString& aURL,
                                const nsAString& aTitle, ErrorResult& aRv);
   void RegisterContentHandler(const nsAString& aMIMEType, const nsAString& aURL,
                               const nsAString& aTitle, ErrorResult& aRv);
   nsMimeTypeArray* GetMimeTypes(ErrorResult& aRv);
   nsPluginArray* GetPlugins(ErrorResult& aRv);
   Permissions* GetPermissions(ErrorResult& aRv);
@@ -214,16 +218,17 @@ public:
   // The XPCOM GetProductSub is OK
   bool CookieEnabled();
   void GetBuildID(nsString& aBuildID, ErrorResult& aRv)
   {
     aRv = GetBuildID(aBuildID);
   }
   PowerManager* GetMozPower(ErrorResult& aRv);
   bool JavaEnabled(ErrorResult& aRv);
+  uint64_t HardwareConcurrency();
   bool TaintEnabled()
   {
     return false;
   }
   void AddIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
   void RemoveIdleObserver(MozIdleObserver& aObserver, ErrorResult& aRv);
   already_AddRefed<WakeLock> RequestWakeLock(const nsAString &aTopic,
                                              ErrorResult& aRv);
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -216,32 +216,44 @@ public:
   // accessing the JSContext through cx().
   AutoJSAPI();
 
   ~AutoJSAPI();
 
   // This uses the SafeJSContext (or worker equivalent), and enters a null
   // compartment, so that the consumer is forced to select a compartment to
   // enter before manipulating objects.
+  //
+  // This variant will ensure that any errors reported by this AutoJSAPI as it
+  // comes off the stack will not fire error events or be associated with any
+  // particular web-visible global.
   void Init();
 
   // This uses the SafeJSContext (or worker equivalent), and enters the
   // compartment of aGlobalObject.
   // If aGlobalObject or its associated JS global are null then it returns
   // false and use of cx() will cause an assertion.
+  //
+  // If aGlobalObject represents a web-visible global, errors reported by this
+  // AutoJSAPI as it comes off the stack will fire the relevant error events and
+  // show up in the corresponding web console.
   bool Init(nsIGlobalObject* aGlobalObject);
 
   // This is a helper that grabs the native global associated with aObject and
   // invokes the above Init() with that.
   bool Init(JSObject* aObject);
 
   // Unsurprisingly, this uses aCx and enters the compartment of aGlobalObject.
   // If aGlobalObject or its associated JS global are null then it returns
   // false and use of cx() will cause an assertion.
   // If aCx is null it will cause an assertion.
+  //
+  // If aGlobalObject represents a web-visible global, errors reported by this
+  // AutoJSAPI as it comes off the stack will fire the relevant error events and
+  // show up in the corresponding web console.
   bool Init(nsIGlobalObject* aGlobalObject, JSContext* aCx);
 
   // Convenience functions to take an nsPIDOMWindow* or nsGlobalWindow*,
   // when it is more easily available than an nsIGlobalObject.
   bool Init(nsPIDOMWindowInner* aWindow);
   bool Init(nsPIDOMWindowInner* aWindow, JSContext* aCx);
 
   bool Init(nsGlobalWindow* aWindow);
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -298,17 +298,18 @@ MarkWindowList(nsISimpleEnumerator* aWin
   nsCOMPtr<nsISupports> iter;
   while (NS_SUCCEEDED(aWindowList->GetNext(getter_AddRefs(iter))) &&
          iter) {
     if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(iter)) {
       nsCOMPtr<nsIDocShell> rootDocShell = window->GetDocShell();
 
       MarkDocShell(rootDocShell, aCleanupJS, aPrepareForCC);
 
-      nsCOMPtr<nsITabChild> tabChild = do_GetInterface(rootDocShell);
+      nsCOMPtr<nsITabChild> tabChild =
+        rootDocShell ? rootDocShell->GetTabChild() : nullptr;
       if (tabChild) {
         nsCOMPtr<nsIContentFrameMessageManager> mm;
         tabChild->GetMessageManager(getter_AddRefs(mm));
         if (mm) {
           mm->MarkForCC();
         }
       }
     }
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -151,16 +151,17 @@
 #include "nsIPluginHost.h"
 #include "nsIRequest.h"
 #include "nsIRunnable.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptError.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
+#include "nsIScrollable.h"
 #include "nsIStreamConverterService.h"
 #include "nsIStringBundle.h"
 #include "nsIURI.h"
 #include "nsIURIWithPrincipal.h"
 #include "nsIURL.h"
 #include "nsIWebNavigation.h"
 #include "nsIWindowMediator.h"
 #include "nsIWordBreaker.h"
@@ -8991,8 +8992,29 @@ nsContentUtils::IsSpecificAboutPage(JSOb
     return false;
   }
 
   // Now check the spec itself
   nsAutoCString spec;
   uri->GetSpec(spec);
   return spec.EqualsASCII(aUri);
 }
+
+/* static */ void
+nsContentUtils::SetScrollbarsVisibility(nsIDocShell* aDocShell, bool aVisible)
+{
+  nsCOMPtr<nsIScrollable> scroller = do_QueryInterface(aDocShell);
+
+  if (scroller) {
+    int32_t prefValue;
+
+    if (aVisible) {
+      prefValue = nsIScrollable::Scrollbar_Auto;
+    } else {
+      prefValue = nsIScrollable::Scrollbar_Never;
+    }
+
+    scroller->SetDefaultScrollbarPreferences(
+                nsIScrollable::ScrollOrientation_Y, prefValue);
+    scroller->SetDefaultScrollbarPreferences(
+                nsIScrollable::ScrollOrientation_X, prefValue);
+  }
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2577,16 +2577,18 @@ public:
   /*
    * Returns true iff the provided JSObject is a global, and its URI matches
    * the provided about: URI.
    * @param aGlobal the JSObject whose URI to check, if it is a global.
    * @param aUri the URI to match, e.g. "about:feeds"
    */
   static bool IsSpecificAboutPage(JSObject* aGlobal, const char* aUri);
 
+  static void SetScrollbarsVisibility(nsIDocShell* aDocShell, bool aVisible);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -320,19 +320,23 @@ SetParentToWindow(nsGlobalWindow *win, J
 
 nsISupports *
 nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj)
 {
   return wrapper ? wrapper->Native() : static_cast<nsISupports*>(js::GetObjectPrivate(obj));
 }
 
 nsresult
-nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
+nsDOMClassInfo::DefineStaticJSVals()
 {
-#define SET_JSID_TO_STRING(_id, _cx, _str)                                    \
+  AutoJSAPI jsapi;
+  jsapi.Init(xpc::UnprivilegedJunkScope());
+  JSContext* cx = jsapi.cx();
+
+#define SET_JSID_TO_STRING(_id, _cx, _str)                              \
   if (JSString *str = ::JS_AtomizeAndPinString(_cx, _str))                             \
       _id = INTERNED_STRING_TO_JSID(_cx, str);                                \
   else                                                                        \
       return NS_ERROR_OUT_OF_MEMORY;
 
   SET_JSID_TO_STRING(sConstructor_id,     cx, "constructor");
   SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
 
@@ -495,18 +499,16 @@ nsDOMClassInfo::Init()
   nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
   NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
 
   NS_ADDREF(sXPConnect = nsContentUtils::XPConnect());
 
   nsCOMPtr<nsIXPCFunctionThisTranslator> elt = new nsEventListenerThisTranslator();
   sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsIDOMEventListener), elt);
 
-  AutoSafeJSContext cx;
-
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(DOMPrototype, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(DOMConstructor, nsIDOMDOMConstructor)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMConstructor)
   DOM_CLASSINFO_MAP_END
 
@@ -660,17 +662,17 @@ nsDOMClassInfo::Init()
     if (!sClassInfoData[i].mInterfaces) {
       MOZ_CRASH("Class info data without an interface list! Fix this, "
                 "mozilla will not work without this fixed!");
      }
    }
 #endif
 
   // Initialize static JSString's
-  DefineStaticJSVals(cx);
+  DefineStaticJSVals();
 
   int32_t i;
 
   for (i = 0; i < eDOMClassInfoIDCount; ++i) {
     if (i == eDOMClassInfo_DOMPrototype_id) {
       continue;
     }
 
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -105,17 +105,17 @@ protected:
   {
   }
 
   static nsresult RegisterClassProtos(int32_t aDOMClassInfoID);
 
   static nsIXPConnect *sXPConnect;
 
   // nsIXPCScriptable code
-  static nsresult DefineStaticJSVals(JSContext *cx);
+  static nsresult DefineStaticJSVals();
 
   static bool sIsInitialized;
 
 public:
   static jsid sConstructor_id;
   static jsid sWrappedJSObject_id;
 };
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -864,19 +864,21 @@ nsFocusManager::WindowShown(mozIDOMWindo
       doc = mFocusedWindow->GetExtantDoc();
       if (doc && doc->GetDocumentURI()) {
         doc->GetDocumentURI()->GetSpec(spec);
         LOGFOCUS((" Focused Window: %s", spec.get()));
       }
     }
   }
 
-  if (nsCOMPtr<nsITabChild> child = do_GetInterface(window->GetDocShell())) {
-    bool active = static_cast<TabChild*>(child.get())->ParentIsActive();
-    ActivateOrDeactivate(window, active);
+  if (nsIDocShell* docShell = window->GetDocShell()) {
+    if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
+      bool active = static_cast<TabChild*>(child.get())->ParentIsActive();
+      ActivateOrDeactivate(window, active);
+    }
   }
 
   if (mFocusedWindow != window)
     return NS_OK;
 
   if (aNeedsFocus) {
     nsCOMPtr<nsPIDOMWindowOuter> currentWindow;
     nsCOMPtr<nsIContent> currentFocus =
@@ -1627,17 +1629,17 @@ nsFocusManager::Blur(nsPIDOMWindowOuter*
     // But don't do this if we are blurring due to the window being lowered,
     // otherwise, the parent window can get raised again.
     if (mActiveWindow) {
       nsIFrame* contentFrame = content->GetPrimaryFrame();
       nsIObjectFrame* objectFrame = do_QueryFrame(contentFrame);
       if (aAdjustWidgets && objectFrame && !sTestMode) {
         if (XRE_IsContentProcess()) {
           // set focus to the top level window via the chrome process.
-          nsCOMPtr<nsITabChild> tabChild = do_GetInterface(docShell);
+          nsCOMPtr<nsITabChild> tabChild = docShell->GetTabChild();
           if (tabChild) {
             static_cast<TabChild*>(tabChild.get())->SendDispatchFocusToTopLevelWindow();
           }
         } else {
           // note that the presshell's widget is being retrieved here, not the one
           // for the object frame.
           nsViewManager* vm = presShell->GetViewManager();
           if (vm) {
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -1641,17 +1641,16 @@ nsMessageManagerScriptExecutor::DidCreat
   }
 }
 
 // static
 void
 nsMessageManagerScriptExecutor::Shutdown()
 {
   if (sCachedScripts) {
-    AutoSafeJSContext cx;
     NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
     for (auto iter = sCachedScripts->Iter(); !iter.Done(); iter.Next()) {
       delete iter.Data();
       iter.Remove();
     }
 
     delete sCachedScripts;
     sCachedScripts = nullptr;
@@ -1756,22 +1755,23 @@ nsMessageManagerScriptExecutor::TryCache
                                    EmptyString(), nullptr,
                                    dataStringBuf, dataStringLength);
   }
 
   JS::SourceBufferHolder srcBuf(dataStringBuf, dataStringLength,
                                 JS::SourceBufferHolder::GiveOwnership);
 
   if (dataStringBuf && dataStringLength > 0) {
-    AutoSafeJSContext cx;
     // Compile the script in the compilation scope instead of the current global
     // to avoid keeping the current compartment alive.
-    JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
-
-    JSAutoCompartment ac(cx, global);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+      return;
+    }
+    JSContext* cx = jsapi.cx();
     JS::CompileOptions options(cx, JSVERSION_LATEST);
     options.setFileAndLine(url.get(), 1);
     options.setNoScriptRval(true);
     JS::Rooted<JSScript*> script(cx);
 
     if (aRunInGlobalScope) {
       if (!JS::Compile(cx, options, srcBuf, &script)) {
         return;
@@ -1796,18 +1796,17 @@ nsMessageManagerScriptExecutor::TryCache
   }
 }
 
 void
 nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
   const nsAString& aURL,
   bool aRunInGlobalScope)
 {
-  AutoSafeJSContext cx;
-  JS::Rooted<JSScript*> script(cx);
+  JS::Rooted<JSScript*> script(nsContentUtils::RootingCx());
   TryCacheLoadAndCompileScript(aURL, aRunInGlobalScope, true, &script);
 }
 
 void
 nsMessageManagerScriptExecutor::Trace(const TraceCallbacks& aCallbacks, void* aClosure)
 {
   for (size_t i = 0, length = mAnonymousGlobalScopes.Length(); i < length; ++i) {
     aCallbacks.Trace(&mAnonymousGlobalScopes[i], "mAnonymousGlobalScopes[i]", aClosure);
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1219,16 +1219,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 
         // Watch for dom-storage2-changed so we can fire storage
         // events. Use a strong reference.
         os->AddObserver(mObserver, "dom-storage2-changed", false);
       }
 
       Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
     }
+
+    InitializeShowFocusRings();
   } else {
     // |this| is an outer window. Outer windows start out frozen and
     // remain frozen until they get an inner window, so freeze this
     // outer window here.
     Freeze();
   }
 
   // We could have failed the first time through trying
@@ -4007,17 +4009,19 @@ MozSelfSupport*
 nsGlobalWindow::GetMozSelfSupport(ErrorResult& aError)
 {
   MOZ_ASSERT(IsInnerWindow());
 
   if (mMozSelfSupport) {
     return mMozSelfSupport;
   }
 
-  AutoSafeJSContext cx;
+  // We're called from JS and want to use out existing JSContext (and,
+  // importantly, its compartment!) here.
+  AutoJSContext cx;
   GlobalObject global(cx, FastGetGlobalJSObject());
   mMozSelfSupport = MozSelfSupport::Constructor(global, cx, aError);
   return mMozSelfSupport;
 }
 
 nsresult
 nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
 {
@@ -5695,18 +5699,23 @@ nsGlobalWindow::DispatchResizeEvent(cons
 
   ErrorResult res;
   RefPtr<Event> domEvent =
     mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"), res);
   if (res.Failed()) {
     return false;
   }
 
-  AutoSafeJSContext cx;
+  // We don't init the AutoJSAPI with ourselves because we don't want it
+  // reporting errors to our onerror handlers.
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
   JSAutoCompartment ac(cx, GetWrapperPreserveColor());
+
   DOMWindowResizeEventDetail detail;
   detail.mWidth = aSize.width;
   detail.mHeight = aSize.height;
   JS::Rooted<JS::Value> detailValue(cx);
   if (!ToJSValue(cx, detail, &detailValue)) {
     return false;
   }
 
@@ -8667,18 +8676,17 @@ nsGlobalWindow::NotifyDOMWindowThawed(ns
                         DOM_WINDOW_THAWED_TOPIC, nullptr);
     }
   }
 }
 
 JSObject*
 nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
 {
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> handler(cx);
+  JS::Rooted<JSObject*> handler(nsContentUtils::RootingCx());
   if (mCachedXBLPrototypeHandlers) {
     mCachedXBLPrototypeHandlers->Get(aKey, handler.address());
   }
   return handler;
 }
 
 void
 nsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
@@ -9048,19 +9056,22 @@ public:
   nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher;
   nsString                             mAction;
 };
 
 nsresult
 nsGlobalWindow::UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason)
 {
   // If this is a child process, redirect to the parent process.
-  if (nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell())) {
-    nsContentUtils::AddScriptRunner(new ChildCommandDispatcher(this, child, anAction));
-    return NS_OK;
+  if (nsIDocShell* docShell = GetDocShell()) {
+    if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
+      nsContentUtils::AddScriptRunner(new ChildCommandDispatcher(this, child,
+                                                                 anAction));
+      return NS_OK;
+    }
   }
 
   nsPIDOMWindowOuter *rootWindow = nsGlobalWindow::GetPrivateRoot();
   if (!rootWindow)
     return NS_OK;
 
   nsCOMPtr<nsIDOMXULDocument> xulDoc =
     do_QueryInterface(rootWindow->GetExtantDoc());
@@ -9688,16 +9699,27 @@ nsGlobalWindow::SetFocusedNode(nsIConten
 uint32_t
 nsGlobalWindow::GetFocusMethod()
 {
   FORWARD_TO_INNER(GetFocusMethod, (), 0);
 
   return mFocusMethod;
 }
 
+void
+nsGlobalWindow::InitializeShowFocusRings()
+{
+  nsPIDOMWindowOuter* root = GetPrivateRoot();
+  if (root) {
+    bool showAccelerators = false, showFocusRings = false;
+    root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
+    mShowFocusRings = showFocusRings;
+  }
+}
+
 bool
 nsGlobalWindow::ShouldShowFocusRing()
 {
   FORWARD_TO_INNER(ShouldShowFocusRing, (), false);
 
   return mShowFocusRings || mShowFocusRingForContent || mFocusByKeyOccurred;
 }
 
@@ -9791,24 +9813,16 @@ nsGlobalWindow::TakeFocus(bool aFocus, u
 void
 nsGlobalWindow::SetReadyForFocus()
 {
   FORWARD_TO_INNER_VOID(SetReadyForFocus, ());
 
   bool oldNeedsFocus = mNeedsFocus;
   mNeedsFocus = false;
 
-  // update whether focus rings need to be shown using the state from the
-  // root window
-  if (nsPIDOMWindowOuter* root = GetPrivateRoot()) {
-    bool showAccelerators, showFocusRings;
-    root->GetKeyboardIndicators(&showAccelerators, &showFocusRings);
-    mShowFocusRings = showFocusRings;
-  }
-
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     fm->WindowShown(GetOuterWindow(), oldNeedsFocus);
   }
 }
 
 void
 nsGlobalWindow::PageHidden()
@@ -10669,17 +10683,18 @@ nsGlobalWindow::ShowSlowScriptDialog()
     Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT, 1);
   }
   mHasHadSlowScript = true;
 
   if (XRE_IsContentProcess() &&
       ProcessHangMonitor::Get()) {
     ProcessHangMonitor::SlowScriptAction action;
     RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
-    nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell());
+    nsIDocShell* docShell = GetDocShell();
+    nsCOMPtr<nsITabChild> child = docShell ? docShell->GetTabChild() : nullptr;
     action = monitor->NotifySlowScript(child,
                                        filename.get(),
                                        lineno);
     if (action == ProcessHangMonitor::Terminate) {
       return KillSlowScript;
     }
 
     if (action == ProcessHangMonitor::StartDebugger) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1588,16 +1588,18 @@ protected:
   static void NotifyDOMWindowThawed(nsGlobalWindow* aWindow);
 
   void ClearStatus();
 
   virtual void UpdateParentTarget() override;
 
   inline int32_t DOMMinTimeoutValue() const;
 
+  void InitializeShowFocusRings();
+
   // Clear the document-dependent slots on our JS wrapper.  Inner windows only.
   void ClearDocumentDependentSlots(JSContext* aCx);
 
   // Inner windows only.
   already_AddRefed<mozilla::dom::StorageEvent>
   CloneStorageEvent(const nsAString& aType,
                     const RefPtr<mozilla::dom::StorageEvent>& aEvent,
                     mozilla::ErrorResult& aRv);
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -3715,21 +3715,25 @@ nsObjectLoadingContent::GetPluginJSObjec
 }
 
 void
 nsObjectLoadingContent::TeardownProtoChain()
 {
   nsCOMPtr<nsIContent> thisContent =
     do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
 
-  // Use the safe JSContext here as we're not always able to find the
-  // JSContext associated with the NPP any more.
-  AutoSafeJSContext cx;
+  NS_ENSURE_TRUE_VOID(thisContent->GetWrapper());
+
+  // We don't init the AutoJSAPI with our wrapper because we don't want it
+  // reporting errors to our window's onerror listeners.
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
-  NS_ENSURE_TRUE(obj, /* void */);
+  MOZ_ASSERT(obj);
 
   JS::Rooted<JSObject*> proto(cx);
   JSAutoCompartment ac(cx, obj);
 
   // Loop over the DOM element's JS object prototype chain and remove
   // all JS objects of the class sNPObjectJSWrapperClass
   DebugOnly<bool> removed = false;
   while (obj) {
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -684,17 +684,17 @@ nsXMLHttpRequest::GetResponseText(nsStri
                "Unexpected mResponseBodyDecodedPos");
   aRv = AppendToResponseText(mResponseBody.get() + mResponseBodyDecodedPos,
                              mResponseBody.Length() - mResponseBodyDecodedPos);
   if (aRv.Failed()) {
     return;
   }
 
   mResponseBodyDecodedPos = mResponseBody.Length();
-  
+
   if (mState & XML_HTTP_REQUEST_DONE) {
     // Free memory buffer which we no longer need
     mResponseBody.Truncate();
     mResponseBodyDecodedPos = 0;
   }
 
   aResponseText = mResponseText;
 }
@@ -1209,17 +1209,17 @@ nsXMLHttpRequest::IsSafeHeader(const nsA
   // Make sure we don't leak header information from denied cross-site
   // requests.
   if (mChannel) {
     nsresult status;
     mChannel->GetStatus(&status);
     if (NS_FAILED(status)) {
       return false;
     }
-  }  
+  }
   const char* kCrossOriginSafeHeaders[] = {
     "cache-control", "content-language", "content-type", "expires",
     "last-modified", "pragma"
   };
   for (uint32_t i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) {
     if (header.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
       return true;
     }
@@ -1365,17 +1365,17 @@ nsXMLHttpRequest::GetResponseHeader(cons
     _retval.SetIsVoid(true);
     aRv.SuppressException();
   }
 }
 
 already_AddRefed<nsILoadGroup>
 nsXMLHttpRequest::GetLoadGroup() const
 {
-  if (mState & XML_HTTP_REQUEST_BACKGROUND) {                 
+  if (mState & XML_HTTP_REQUEST_BACKGROUND) {
     return nullptr;
   }
 
   if (mLoadGroup) {
     nsCOMPtr<nsILoadGroup> ref = mLoadGroup;
     return ref.forget();
   }
 
@@ -1438,17 +1438,17 @@ nsXMLHttpRequest::DispatchProgressEvent(
 
   aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 
   if (dispatchLoadend) {
     DispatchProgressEvent(aTarget, NS_LITERAL_STRING(LOADEND_STR),
                           aLengthComputable, aLoaded, aTotal);
   }
 }
-                                          
+
 already_AddRefed<nsIHttpChannel>
 nsXMLHttpRequest::GetCurrentHttpChannel()
 {
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
   return httpChannel.forget();
 }
 
 already_AddRefed<nsIJARChannel>
@@ -1551,17 +1551,17 @@ nsXMLHttpRequest::Open(const nsACString&
   } else {
     mState &= ~XML_HTTP_REQUEST_ASYNC;
   }
 
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIDocument> doc =
     nsContentUtils::GetDocumentFromScriptContext(sc);
-  
+
   nsCOMPtr<nsIURI> baseURI;
   if (mBaseURI) {
     baseURI = mBaseURI;
   }
   else if (doc) {
     baseURI = doc->GetBaseURI();
   }
 
@@ -1825,17 +1825,17 @@ nsXMLHttpRequest::OnDataAvailable(nsIReq
 
     ChangeState(XML_HTTP_REQUEST_LOADING);
     return request->Cancel(NS_OK);
   }
 
   mDataAvailable += totalRead;
 
   ChangeState(XML_HTTP_REQUEST_LOADING);
-  
+
   MaybeDispatchProgressEvents(false);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
 {
@@ -1985,17 +1985,22 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ
       if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
         // We don't make cool new features available in the bad synchronous
         // mode. The synchronous mode is for legacy only.
         mWarnAboutSyncHtml = true;
         mState &= ~XML_HTTP_REQUEST_PARSEBODY;
       } else {
         mIsHtml = true;
       }
-    } else if (type.Find("xml") == kNotFound) {
+    } else if (!(type.EqualsLiteral("text/xml") ||
+                 type.EqualsLiteral("application/xml") ||
+                 type.RFind("+xml", true, -1, 4) != kNotFound)) {
+      // Follow https://xhr.spec.whatwg.org/
+      // If final MIME type is not null, text/html, text/xml, application/xml,
+      // or does not end in +xml, return null.
       mState &= ~XML_HTTP_REQUEST_PARSEBODY;
     }
   } else {
     // The request failed, so we shouldn't be parsing anyway
     mState &= ~XML_HTTP_REQUEST_PARSEBODY;
   }
 
   if (mState & XML_HTTP_REQUEST_PARSEBODY) {
@@ -2402,23 +2407,23 @@ GetRequestBody(nsIVariant* aBody, nsIInp
 
     // nsIXHRSendable?
     nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
     if (sendable) {
       return GetRequestBody(sendable, aResult, aContentLength, aContentType, aCharset);
     }
 
     // ArrayBuffer?
-    AutoSafeJSContext cx;
-    JS::Rooted<JS::Value> realVal(cx);
+    JSContext* rootingCx = nsContentUtils::RootingCx();
+    JS::Rooted<JS::Value> realVal(rootingCx);
 
     nsresult rv = aBody->GetAsJSVal(&realVal);
     if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) {
-      JS::Rooted<JSObject*> obj(cx, realVal.toObjectOrNull());
-      ArrayBuffer buf;
+      JS::Rooted<JSObject*> obj(rootingCx, realVal.toObjectOrNull());
+      RootedTypedArray<ArrayBuffer> buf(rootingCx);
       if (buf.Init(obj)) {
           buf.ComputeLengthAndData();
           return GetRequestBody(buf.Data(), buf.Length(), aResult,
                                 aContentLength, aContentType, aCharset);
       }
     }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
@@ -2682,17 +2687,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
         }
       }
 
       // If necessary, wrap the stream in a buffered stream so as to guarantee
       // support for our upload when calling ExplicitSetUploadStream.
       if (!NS_InputStreamIsBuffered(postDataStream)) {
         nsCOMPtr<nsIInputStream> bufferedStream;
         rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
-                                       postDataStream, 
+                                       postDataStream,
                                        4096);
         NS_ENSURE_SUCCESS(rv, rv);
 
         postDataStream = bufferedStream;
       }
 
       mUploadComplete = false;
 
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -321,16 +321,17 @@ skip-if = buildapp == 'mulet' || buildap
 [test_getFeature_without_perm.html]
 [test_hasFeature.html]
 [test_history_document_open.html]
 [test_history_state_null.html]
 [test_Image_constructor.html]
 [test_innersize_scrollport.html]
 [test_messagemanager_targetchain.html]
 [test_named_frames.html]
+[test_navigator_hardwareConcurrency.html]
 [test_navigator_resolve_identity.html]
 [test_navigator_language.html]
 [test_noAudioNotification.html]
 tags = audiochannel
 [test_noAudioNotificationOnMutedElement.html]
 tags = audiochannel
 [test_noAudioNotificationOnMutedOrVolume0Element.html]
 tags = audiochannel
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_navigator_hardwareConcurrency.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Navigator.hardwareConcurrency</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  var x = navigator.hardwareConcurrency;
+  is(typeof x, "number", "hardwareConcurrency should be a number.");
+  ok(x > 0, "hardwareConcurrency should be greater than 0.");
+
+  </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1607,18 +1607,16 @@ DOMInterfaces = {
     # with the same name
     'binaryNames': {
         'console': 'getConsole',
         'performance': 'getPerformance',
     },
 },
 
 'WorkerNavigator': {
-    'headerFile': 'mozilla/dom/workers/bindings/Navigator.h',
-    'workers': True,
     'implicitJSContext': ['getDataStores'],
 },
 
 'XMLHttpRequest': [
 {
     'nativeType': 'nsXMLHttpRequest',
     'implicitJSContext': [ 'send'],
 },
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -320,17 +320,21 @@ already_AddRefed<nsISupports>
 CallbackObjectHolderBase::ToXPCOMCallback(CallbackObject* aCallback,
                                           const nsIID& aIID) const
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!aCallback) {
     return nullptr;
   }
 
-  AutoSafeJSContext cx;
+  // We don't init the AutoJSAPI with our callback because we don't want it
+  // reporting errors to its global's onerror handlers.
+  AutoJSAPI jsapi;
+  jsapi.Init();
+  JSContext* cx = jsapi.cx();
 
   JS::Rooted<JSObject*> callback(cx, aCallback->Callback());
 
   JSAutoCompartment ac(cx, callback);
   RefPtr<nsXPCWrappedJS> wrappedJS;
   nsresult rv =
     nsXPCWrappedJS::GetNewOrUsed(callback, aIID, getter_AddRefs(wrappedJS));
   if (NS_FAILED(rv) || !wrappedJS) {
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -255,45 +255,16 @@ bool
 BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx,
                                                   JS::Handle<JSObject*> proxy,
                                                   JS::AutoIdVector& props) const
 {
   return ownPropNames(cx, proxy, JSITER_OWNONLY, props);
 }
 
 bool
-DOMProxyHandler::has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) const
-{
-  if (!hasOwn(cx, proxy, id, bp)) {
-    return false;
-  }
-
-  if (*bp) {
-    // We have the property ourselves; no need to worry about our prototype
-    // chain.
-    return true;
-  }
-
-  // OK, now we have to look at the proto
-  JS::Rooted<JSObject*> proto(cx);
-  if (!js::GetObjectProto(cx, proxy, &proto)) {
-    return false;
-  }
-  if (!proto) {
-    return true;
-  }
-  bool protoHasProp;
-  bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
-  if (ok) {
-    *bp = protoHasProp;
-  }
-  return ok;
-}
-
-bool
 DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                            JS::Handle<JS::Value> v, bool *done) const
 {
   *done = false;
   return true;
 }
 
 //static
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -109,18 +109,16 @@ public:
                               JS::Handle<JS::PropertyDescriptor> desc,
                               JS::ObjectOpResult &result, bool *defined) const;
   bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                JS::ObjectOpResult &result) const override;
   bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
                          JS::ObjectOpResult& result) const override;
   bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
                     const override;
-  bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-           bool* bp) const override;
   bool set(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
            JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver, JS::ObjectOpResult &result)
            const override;
 
   /*
    * If assigning to proxy[id] hits a named setter with OverrideBuiltins or
    * an indexed setter, call it and set *done to true on success. Otherwise, set
    * *done to false.
--- a/dom/bluetooth/common/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/common/BluetoothReplyRunnable.cpp
@@ -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/. */
 
 #include "base/basictypes.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothUtils.h"
 #include "DOMRequest.h"
+#include "nsContentUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/dom/Promise.h"
 #include "nsServiceManagerUtils.h"
 
 using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
@@ -87,18 +88,17 @@ BluetoothReplyRunnable::FireErrorString(
 }
 
 NS_IMETHODIMP
 BluetoothReplyRunnable::Run()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mReply);
 
-  AutoSafeJSContext cx;
-  JS::Rooted<JS::Value> v(cx, JS::UndefinedValue());
+  JS::Rooted<JS::Value> v(nsContentUtils::RootingCx(), JS::UndefinedValue());
 
   nsresult rv;
   if (mReply->type() != BluetoothReply::TBluetoothReplySuccess) {
     ParseErrorStatus();
     rv = FireErrorString();
   } else if (!ParseSuccessfulReply(&v)) {
     rv = FireErrorString();
   } else {
--- a/dom/crypto/CryptoKey.cpp
+++ b/dom/crypto/CryptoKey.cpp
@@ -741,17 +741,17 @@ CryptoKey::PrivateKeyFromJwk(const JsonW
       { CKA_CLASS,            &privateKeyValue,     sizeof(privateKeyValue) },
       { CKA_KEY_TYPE,         &ecValue,             sizeof(ecValue) },
       { CKA_TOKEN,            &falseValue,          sizeof(falseValue) },
       { CKA_SENSITIVE,        &falseValue,          sizeof(falseValue) },
       { CKA_PRIVATE,          &falseValue,          sizeof(falseValue) },
       { CKA_ID,               objID->data,          objID->len },
       { CKA_EC_PARAMS,        params->data,         params->len },
       { CKA_EC_POINT,         ecPoint->data,        ecPoint->len },
-      { CKA_VALUE,            (void*) d.Elements(), d.Length() },
+      { CKA_VALUE,            (void*) d.Elements(), (CK_ULONG) d.Length() },
     };
 
     return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
                                             PR_ARRAY_SIZE(keyTemplate));
   }
 
   if (aJwk.mKty.EqualsLiteral(JWK_TYPE_RSA)) {
     // Verify that all of the required parameters are present
@@ -788,24 +788,24 @@ CryptoKey::PrivateKeyFromJwk(const JsonW
     CK_KEY_TYPE rsaValue = CKK_RSA;
     CK_ATTRIBUTE keyTemplate[14] = {
       { CKA_CLASS,            &privateKeyValue,      sizeof(privateKeyValue) },
       { CKA_KEY_TYPE,         &rsaValue,             sizeof(rsaValue) },
       { CKA_TOKEN,            &falseValue,           sizeof(falseValue) },
       { CKA_SENSITIVE,        &falseValue,           sizeof(falseValue) },
       { CKA_PRIVATE,          &falseValue,           sizeof(falseValue) },
       { CKA_ID,               objID->data,           objID->len },
-      { CKA_MODULUS,          (void*) n.Elements(),  n.Length() },
-      { CKA_PUBLIC_EXPONENT,  (void*) e.Elements(),  e.Length() },
-      { CKA_PRIVATE_EXPONENT, (void*) d.Elements(),  d.Length() },
-      { CKA_PRIME_1,          (void*) p.Elements(),  p.Length() },
-      { CKA_PRIME_2,          (void*) q.Elements(),  q.Length() },
-      { CKA_EXPONENT_1,       (void*) dp.Elements(), dp.Length() },
-      { CKA_EXPONENT_2,       (void*) dq.Elements(), dq.Length() },
-      { CKA_COEFFICIENT,      (void*) qi.Elements(), qi.Length() },
+      { CKA_MODULUS,          (void*) n.Elements(),  (CK_ULONG) n.Length() },
+      { CKA_PUBLIC_EXPONENT,  (void*) e.Elements(),  (CK_ULONG) e.Length() },
+      { CKA_PRIVATE_EXPONENT, (void*) d.Elements(),  (CK_ULONG) d.Length() },
+      { CKA_PRIME_1,          (void*) p.Elements(),  (CK_ULONG) p.Length() },
+      { CKA_PRIME_2,          (void*) q.Elements(),  (CK_ULONG) q.Length() },
+      { CKA_EXPONENT_1,       (void*) dp.Elements(), (CK_ULONG) dp.Length() },
+      { CKA_EXPONENT_2,       (void*) dq.Elements(), (CK_ULONG) dq.Length() },
+      { CKA_COEFFICIENT,      (void*) qi.Elements(), (CK_ULONG) qi.Length() },
     };
 
     return PrivateKeyFromPrivateKeyTemplate(objID, keyTemplate,
                                             PR_ARRAY_SIZE(keyTemplate));
   }
 
   return nullptr;
 }
--- a/dom/datastore/DataStoreDB.cpp
+++ b/dom/datastore/DataStoreDB.cpp
@@ -107,17 +107,19 @@ DataStoreDB::CreateFactoryIfNeeded()
     nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::Create();
     if (!principal) {
       return NS_ERROR_FAILURE;
     }
 
     nsIXPConnect* xpc = nsContentUtils::XPConnect();
     MOZ_ASSERT(xpc);
 
-    AutoSafeJSContext cx;
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    JSContext* cx = jsapi.cx();
     JS::Rooted<JSObject*> global(cx);
     rv = xpc->CreateSandbox(cx, principal, global.address());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     // The CreateSandbox call returns a proxy to the actual sandbox object. We
     // don't need a proxy here.
@@ -217,20 +219,18 @@ DataStoreDB::UpgradeSchema(nsIDOMEvent* 
   nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
   MOZ_ASSERT(event);
 
   Nullable<uint64_t> version = event->GetNewVersion();
   MOZ_ASSERT(!version.IsNull());
   MOZ_ASSERT(version.Value() == DATASTOREDB_VERSION);
 #endif
 
-  AutoSafeJSContext cx;
-
   ErrorResult error;
-  JS::Rooted<JS::Value> result(cx);
+  JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
   mRequest->GetResult(&result, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   MOZ_ASSERT(result.isObject());
 
   IDBDatabase* database = nullptr;
@@ -279,20 +279,18 @@ DataStoreDB::UpgradeSchema(nsIDOMEvent* 
   return NS_OK;
 }
 
 nsresult
 DataStoreDB::DatabaseOpened()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  AutoSafeJSContext cx;
-
   ErrorResult error;
-  JS::Rooted<JS::Value> result(cx);
+  JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
   mRequest->GetResult(&result, error);
   if (NS_WARN_IF(error.Failed())) {
     return error.StealNSResult();
   }
 
   MOZ_ASSERT(result.isObject());
 
   nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), mDatabase);
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -976,17 +976,19 @@ EventStateManager::ExecuteAccessKey(nsTA
             fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
             focusChanged = true;
           }
         }
 
         if (focusChanged && aIsTrustedEvent) {
           // If this is a child process, inform the parent that we want the focus, but
           // pass false since we don't want to change the window order.
-          nsCOMPtr<nsITabChild> child = do_GetInterface(mPresContext->GetDocShell());
+          nsIDocShell* docShell = mPresContext->GetDocShell();
+          nsCOMPtr<nsITabChild> child =
+            docShell ? docShell->GetTabChild() : nullptr;
           if (child) {
             child->SendRequestFocus(false);
           }
         }
 
         return true;
       }
     }
@@ -1291,17 +1293,18 @@ EventStateManager::HandleCrossProcessEve
   // Collect the remote event targets we're going to forward this
   // event to.
   //
   // NB: the elements of |targets| must be unique, for correctness.
   AutoTArray<nsCOMPtr<nsIContent>, 1> targets;
   if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
     // If this event only has one target, and it's remote, add it to
     // the array.
-    nsIFrame* frame = GetEventTarget();
+    nsIFrame* frame =
+      aEvent->mMessage == eDragExit ? sLastDragOverFrame.GetFrame() : GetEventTarget();
     nsIContent* target = frame ? frame->GetContent() : nullptr;
     if (IsRemoteTarget(target)) {
       targets.AppendElement(target);
     }
   } else {
     // This is a touch event with possibly multiple touch points.
     // Each touch point may have its own target.  So iterate through
     // all of them and collect the unique set of targets for event
--- a/dom/events/test/mochitest.ini
+++ b/dom/events/test/mochitest.ini
@@ -152,17 +152,17 @@ skip-if = toolkit == 'android' #CRASH_DU
 skip-if = buildapp == 'b2g' || e10s # b2g(5535 passed, 108 failed - more tests running than desktop) b2g-debug(5535 passed, 108 failed - more tests running than desktop) b2g-desktop(5535 passed, 108 failed - more tests running than desktop)
 [test_dblclick_explicit_original_target.html]
 [test_dom_keyboard_event.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_dom_mouse_event.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_dom_storage_event.html]
 [test_dom_wheel_event.html]
-skip-if = buildapp == 'b2g' || e10s # b2g(456 failed out of 19873, mousewheel test) b2g-debug(456 failed out of 19873, mousewheel test) b2g-desktop(456 failed out of 19873, mousewheel test)
+skip-if = buildapp == 'b2g' # b2g(456 failed out of 19873, mousewheel test) b2g-debug(456 failed out of 19873, mousewheel test) b2g-desktop(456 failed out of 19873, mousewheel test)
 [test_draggableprop.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
 [test_dragstart.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' # b2g(drag event, also fails on Android) b2g-debug(drag event, also fails on Android) b2g-desktop(drag event, also fails on Android)
 [test_error_events.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_eventctors.html]
 skip-if = toolkit == 'android' #CRASH_DUMP, RANDOM
--- a/dom/events/test/test_dom_wheel_event.html
+++ b/dom/events/test/test_dom_wheel_event.html
@@ -1,14 +1,15 @@
 <!DOCTYPE HTML>
 <html style="font-size: 32px;">
 <head>
   <title>Test for D3E WheelEvent</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <p id="display"></p>
 <div id="scrollable" style="font-family: monospace; font-size: 16px; line-height: 1; overflow: auto; width: 200px; height: 200px;">
   <div id="scrolled" style="font-size: 64px; width: 5000px; height: 5000px;">
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
     Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text. Tere is a lot of text.<br>
@@ -50,53 +51,57 @@ SimpleTest.waitForFocus(runTest, window)
 var gScrollableElement = document.getElementById("scrollable");
 var gScrolledElement = document.getElementById("scrolled");
 
 var gLineHeight = 0;
 var gHorizontalLine = 0;
 var gPageHeight = 0;
 var gPageWidth  = 0;
 
+function sendWheelAndWait(aX, aY, aEvent)
+{
+  sendWheelAndPaint(gScrollableElement, aX, aY, aEvent, continueTest);
+}
+
 function* prepareScrollUnits()
 {
   var result = -1;
   function handler(aEvent)
   {
     result = aEvent.detail;
     aEvent.preventDefault();
-    setTimeout(continueTest, 0);
   }
   window.addEventListener("MozMousePixelScroll", handler, true);
 
-  yield synthesizeWheel(gScrollableElement, 10, 10,
-                        { deltaMode: WheelEvent.DOM_DELTA_LINE,
-                          deltaY: 1.0, lineOrPageDeltaY: 1 });
+  yield sendWheelAndWait(10, 10,
+                         { deltaMode: WheelEvent.DOM_DELTA_LINE,
+                           deltaY: 1.0, lineOrPageDeltaY: 1 });
   gLineHeight = result;
   ok(gLineHeight > 10 && gLineHeight < 25, "prepareScrollUnits: gLineHeight may be illegal value, got " + gLineHeight);
 
   result = -1;
-  yield synthesizeWheel(gScrollableElement, 10, 10,
-                        { deltaMode: WheelEvent.DOM_DELTA_LINE,
-                          deltaX: 1.0, lineOrPageDeltaX: 1 });
+  yield sendWheelAndWait(10, 10,
+                         { deltaMode: WheelEvent.DOM_DELTA_LINE,
+                           deltaX: 1.0, lineOrPageDeltaX: 1 });
   gHorizontalLine = result;
   ok(gHorizontalLine > 5 && gHorizontalLine < 16, "prepareScrollUnits: gHorizontalLine may be illegal value, got " + gHorizontalLine);
 
   result = -1;
-  yield synthesizeWheel(gScrollableElement, 10, 10,
-                        { deltaMode: WheelEvent.DOM_DELTA_PAGE,
-                          deltaY: 1.0, lineOrPageDeltaY: 1 });
+  yield sendWheelAndWait(10, 10,
+                         { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+                           deltaY: 1.0, lineOrPageDeltaY: 1 });
   gPageHeight = result;
   // XXX Cannot we know the actual scroll port size?
   ok(gPageHeight >= 150 && gPageHeight <= 200,
      "prepareScrollUnits: gPageHeight is strange value, got " + gPageHeight);
 
   result = -1;
-  yield synthesizeWheel(gScrollableElement, 10, 10,
-                        { deltaMode: WheelEvent.DOM_DELTA_PAGE,
-                          deltaX: 1.0, lineOrPageDeltaX: 1 });
+  yield sendWheelAndWait(10, 10,
+                         { deltaMode: WheelEvent.DOM_DELTA_PAGE,
+                           deltaX: 1.0, lineOrPageDeltaX: 1 });
   gPageWidth = result;
   ok(gPageWidth >= 150 && gPageWidth <= 200,
      "prepareScrollUnits: gPageWidth is strange value, got " + gPageWidth);
 
   window.removeEventListener("MozMousePixelScroll", handler, true);
 }
 
 function testMakingUntrustedEvent()
@@ -186,17 +191,17 @@ function* testDeltaMultiplierPrefs()
     "delta_multiplier_x", "delta_multiplier_y", "delta_multiplier_z"
   ];
 
   const kPrefValues = [
     200, 50, 0, -50, -150
   ];
 
   var currentTest, currentModifiers, currentEvent, currentPref, currentMultiplier, testingExpected;
-  var expectedHandlerCalls;
+  var expectedAsyncHandlerCalls;
   var description;
   var calledHandlers = { wheel: false,
                          DOMMouseScroll: { horizontal: false, vertical: false },
                          MozMousePixelScroll: { horizontal: false, vertical: false } };
 
   function wheelEventHandler(aEvent) {
     calledHandlers.wheel = true;
 
@@ -216,17 +221,17 @@ function* testDeltaMultiplierPrefs()
           expectedDeltaZ *= currentMultiplier;
           break;
       }
     }
     is(aEvent.deltaX, expectedDeltaX, description + "deltaX (" + currentEvent.deltaX + ") was invalid");
     is(aEvent.deltaY, expectedDeltaY, description + "deltaY (" + currentEvent.deltaY + ") was invalid");
     is(aEvent.deltaZ, expectedDeltaZ, description + "deltaZ (" + currentEvent.deltaZ + ") was invalid");
 
-    if (--expectedHandlerCalls == 0) {
+    if (expectedAsyncHandlerCalls > 0 && --expectedAsyncHandlerCalls == 0) {
       setTimeout(continueTest, 0);
     }
   }
 
   function legacyEventHandler(aEvent) {
     var isHorizontal = (aEvent.axis == MouseScrollEvent.HORIZONTAL_AXIS);
     var isScrollEvent = (aEvent.type == "DOMMouseScroll");
     if (isScrollEvent) {
@@ -278,17 +283,17 @@ function* testDeltaMultiplierPrefs()
           expectedDetail = expectedDetail < 0 ? Math.ceil(expectedDetail) : Math.floor(expectedDetail);
         }
       }
     }
     is(aEvent.detail, expectedDetail, description + eventName + "detail was invalid");
 
     aEvent.preventDefault();
 
-    if (--expectedHandlerCalls == 0) {
+    if (expectedAsyncHandlerCalls > 0 && --expectedAsyncHandlerCalls == 0) {
       setTimeout(continueTest, 0);
     }
   }
 
   window.addEventListener("wheel", wheelEventHandler, true);
   window.addEventListener("DOMMouseScroll", legacyEventHandler, true);
   window.addEventListener("MozMousePixelScroll", legacyEventHandler, true);
 
@@ -338,22 +343,22 @@ function* testDeltaMultiplierPrefs()
           };
 
           var expectedWheel = expectedProps.deltaX != 0 || expectedProps.deltaY != 0 || expectedProps.deltaZ != 0;
           var expectedDOMMouseX = expectedProps.lineOrPageDeltaX >= 1 || expectedProps.lineOrPageDeltaX <= -1;
           var expectedDOMMouseY = expectedProps.lineOrPageDeltaY >= 1 || expectedProps.lineOrPageDeltaY <= -1;
           var expectedMozMouseX = expectedProps.deltaX >= 1 || expectedProps.deltaX <= -1;
           var expectedMozMouseY = expectedProps.deltaY >= 1 || expectedProps.deltaY <= -1;
 
-          expectedHandlerCalls = 0;
-          if (expectedWheel) ++expectedHandlerCalls;
-          if (expectedDOMMouseX) ++expectedHandlerCalls;
-          if (expectedDOMMouseY) ++expectedHandlerCalls;
-          if (expectedMozMouseX) ++expectedHandlerCalls;
-          if (expectedMozMouseY) ++expectedHandlerCalls;
+          expectedAsyncHandlerCalls = 0;
+          if (expectedWheel) ++expectedAsyncHandlerCalls;
+          if (expectedDOMMouseX) ++expectedAsyncHandlerCalls;
+          if (expectedDOMMouseY) ++expectedAsyncHandlerCalls;
+          if (expectedMozMouseX) ++expectedAsyncHandlerCalls;
+          if (expectedMozMouseY) ++expectedAsyncHandlerCalls;
 
           description = "testDeltaMultiplierPrefs, pref: " + currentPref + "=" + kPrefValues[j] +
             ", deltaMode: " + currentEvent.deltaMode + ", modifiers: \"" + modifierList + "\", (trusted event): ";
           yield synthesizeWheel(gScrollableElement, 10, 10, currentEvent);
 
           is(calledHandlers.wheel,
              expectedWheel,
              description + "wheel event was (not) fired");
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -2668,18 +2668,18 @@ nsHTMLDocument::TurnEditingOff()
   nsPIDOMWindowOuter *window = GetWindow();
   if (!window)
     return NS_ERROR_FAILURE;
 
   nsIDocShell *docshell = window->GetDocShell();
   if (!docshell)
     return NS_ERROR_FAILURE;
 
-  nsresult rv;
-  nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv);
+  nsCOMPtr<nsIEditingSession> editSession;
+  nsresult rv = docshell->GetEditingSession(getter_AddRefs(editSession));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // turn editing off
   rv = editSession->TearDownEditorOnWindow(window);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mEditingState = eOff;
 
@@ -2739,18 +2739,18 @@ nsHTMLDocument::EditingStateChanged()
   nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
   if (!window)
     return NS_ERROR_FAILURE;
 
   nsIDocShell *docshell = window->GetDocShell();
   if (!docshell)
     return NS_ERROR_FAILURE;
 
-  nsresult rv;
-  nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv);
+  nsCOMPtr<nsIEditingSession> editSession;
+  nsresult rv = docshell->GetEditingSession(getter_AddRefs(editSession));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIEditor> existingEditor;
   editSession->GetEditorForWindow(window, getter_AddRefs(existingEditor));
   if (existingEditor) {
     // We might already have an editor if it was set up for mail, let's see
     // if this is actually the case.
     nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryInterface(existingEditor);
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -546,17 +546,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 [test_bug259332.html]
 [test_bug311681.html]
 [test_bug311681.xhtml]
 [test_bug324378.html]
 [test_bug332848.xhtml]
 [test_bug340017.xhtml]
 [test_bug359657.html]
 [test_bug369370.html]
-skip-if = buildapp == "mulet" || buildapp == "b2g" || toolkit == "android" || toolkit == "windows" || e10s # disabled on Windows because of bug 1234520
+skip-if = buildapp == "mulet" || buildapp == "b2g" || toolkit == "android" || toolkit == "windows" # disabled on Windows because of bug 1234520
 [test_bug380383.html]
 [test_bug391777.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(showmodaldialog) b2g-debug(showmodaldialog) b2g-desktop(showmodaldialog)
 [test_bug402680.html]
 [test_bug403868.html]
 [test_bug403868.xhtml]
 [test_bug435128.html]
 skip-if = true # Disabled for timeouts.
--- a/dom/html/test/test_fullscreen-api.html
+++ b/dom/html/test/test_fullscreen-api.html
@@ -58,17 +58,17 @@ function nextTest() {
     testWindow.close();
   }
   SimpleTest.executeSoon(runNextTest);
 }
 
 function runNextTest() {
   if (gTestIndex < gTestWindows.length) {
     info("Run test " + gTestWindows[gTestIndex]);
-    testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500");
+    testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500,scrollbars=yes");
     // We'll wait for the window to load, then make sure our window is refocused
     // before starting the test, which will get kicked off on "focus".
     // This ensures that we're essentially back on the primary "desktop" on
     // OS X Lion before we run the test.
     testWindow.addEventListener("load", function onload() {
       testWindow.removeEventListener("load", onload, false);
       SimpleTest.waitForFocus(function() {
         SimpleTest.waitForFocus(testWindow.begin, testWindow);
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- Mode: C++; tab-width: 2; 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 "ActorsParent.h"
 
 #include <algorithm>
@@ -4987,17 +4987,17 @@ public:
 
     return CheckpointInternal(CheckpointMode::Full);
   }
 
   void
   DoIdleProcessing(bool aNeedsCheckpoint);
 
   void
-  Close();
+  Close(uintptr_t aCallsite = 0);
 
   nsresult
   DisableQuotaChecks();
 
   void
   EnableQuotaChecks();
 
 private:
@@ -5355,17 +5355,17 @@ private:
 
   bool
   MaybeFireCallback(DatabasesCompleteCallback* aCallback);
 
   void
   PerformIdleDatabaseMaintenance(DatabaseInfo* aDatabaseInfo);
 
   void
-  CloseDatabase(DatabaseInfo* aDatabaseInfo);
+  CloseDatabase(DatabaseInfo* aDatabaseInfo, uintptr_t aCallsite);
 
   bool
   CloseDatabaseWhenIdleInternal(const nsACString& aDatabaseId);
 };
 
 class ConnectionPool::ConnectionRunnable
   : public nsRunnable
 {
@@ -5401,27 +5401,31 @@ private:
   NS_DECL_NSIRUNNABLE
 };
 
 class ConnectionPool::CloseConnectionRunnable final
   : public ConnectionRunnable
 {
 public:
   explicit
-  CloseConnectionRunnable(DatabaseInfo* aDatabaseInfo)
-    : ConnectionRunnable(aDatabaseInfo)
+  CloseConnectionRunnable(DatabaseInfo* aDatabaseInfo,
+                          uintptr_t aCallsite)
+    : ConnectionRunnable(aDatabaseInfo),
+      mCallsite(aCallsite)
   { }
 
   NS_DECL_ISUPPORTS_INHERITED
 
 private:
   ~CloseConnectionRunnable()
   { }
 
   NS_DECL_NSIRUNNABLE
+
+  uintptr_t mCallsite;
 };
 
 struct ConnectionPool::ThreadInfo
 {
   nsCOMPtr<nsIThread> mThread;
   RefPtr<ThreadRunnable> mRunnable;
 
   ThreadInfo();
@@ -10447,22 +10451,26 @@ DatabaseConnection::GetFreelistCount(Cac
 
   MOZ_ASSERT(freelistCount >= 0);
 
   *aFreelistCount = uint32_t(freelistCount);
   return NS_OK;
 }
 
 void
-DatabaseConnection::Close()
+DatabaseConnection::Close(uintptr_t aCallsite)
 {
   AssertIsOnConnectionThread();
   MOZ_ASSERT(mStorageConnection);
   MOZ_ASSERT(!mDEBUGSavepointCount);
-  MOZ_RELEASE_ASSERT(!mInWriteTransaction);
+  if (mInWriteTransaction) {
+    uint32_t* crashPtr = (uint32_t*)aCallsite;
+    *crashPtr = 42;
+    MOZ_RELEASE_ASSERT(!mInWriteTransaction);
+  }
 
   PROFILER_LABEL("IndexedDB",
                  "DatabaseConnection::Close",
                  js::ProfileEntry::Category::STORAGE);
 
   if (mUpdateRefcountFunction) {
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
       mStorageConnection->RemoveFunction(
@@ -11360,17 +11368,17 @@ ConnectionPool::IdleTimerCallback(nsITim
 
   for (uint32_t count = self->mIdleDatabases.Length(); index < count; index++) {
     IdleDatabaseInfo& info = self->mIdleDatabases[index];
 
     if (now >= info.mIdleTime) {
       if (info.mDatabaseInfo->mIdle) {
         self->PerformIdleDatabaseMaintenance(info.mDatabaseInfo);
       } else {
-        self->CloseDatabase(info.mDatabaseInfo);
+        self->CloseDatabase(info.mDatabaseInfo, 1);
       }
     } else {
       break;
     }
   }
 
   if (index) {
     self->mIdleDatabases.RemoveElementsAt(0, index);
@@ -11838,25 +11846,25 @@ ConnectionPool::CloseIdleDatabases()
   MOZ_ASSERT(mShutdownRequested);
 
   PROFILER_LABEL("IndexedDB",
                  "ConnectionPool::CloseIdleDatabases",
                  js::ProfileEntry::Category::STORAGE);
 
   if (!mIdleDatabases.IsEmpty()) {
     for (IdleDatabaseInfo& idleInfo : mIdleDatabases) {
-      CloseDatabase(idleInfo.mDatabaseInfo);
+      CloseDatabase(idleInfo.mDatabaseInfo, 2);
     }
     mIdleDatabases.Clear();
   }
 
   if (!mDatabasesPerformingIdleMaintenance.IsEmpty()) {
     for (DatabaseInfo* dbInfo : mDatabasesPerformingIdleMaintenance) {
       MOZ_ASSERT(dbInfo);
-      CloseDatabase(dbInfo);
+      CloseDatabase(dbInfo, 3);
     }
     mDatabasesPerformingIdleMaintenance.Clear();
   }
 }
 
 void
 ConnectionPool::ShutdownIdleThreads()
 {
@@ -12152,17 +12160,17 @@ ConnectionPool::NoteIdleDatabase(Databas
 
   const bool otherDatabasesWaiting = !mQueuedTransactions.IsEmpty();
 
   if (mShutdownRequested ||
       otherDatabasesWaiting ||
       aDatabaseInfo->mCloseOnIdle) {
     // Make sure we close the connection if we're shutting down or giving the
     // thread to another database.
-    CloseDatabase(aDatabaseInfo);
+    CloseDatabase(aDatabaseInfo, 4);
 
     if (otherDatabasesWaiting) {
       // Let another database use this thread.
       ScheduleQueuedTransactions(aDatabaseInfo->mThreadInfo);
     } else if (mShutdownRequested) {
       // If there are no other databases that need to run then we can shut this
       // thread down immediately instead of going through the idle thread
       // mechanism.
@@ -12333,30 +12341,32 @@ ConnectionPool::PerformIdleDatabaseMaint
   mDatabasesPerformingIdleMaintenance.AppendElement(aDatabaseInfo);
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     aDatabaseInfo->mThreadInfo.mThread->Dispatch(runnable,
                                                  NS_DISPATCH_NORMAL)));
 }
 
 void
-ConnectionPool::CloseDatabase(DatabaseInfo* aDatabaseInfo)
+ConnectionPool::CloseDatabase(DatabaseInfo* aDatabaseInfo,
+                              uintptr_t aCallsite)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aDatabaseInfo);
   MOZ_ASSERT(!aDatabaseInfo->TotalTransactionCount());
   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mThread);
   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mRunnable);
   MOZ_ASSERT(!aDatabaseInfo->mClosing);
 
   aDatabaseInfo->mIdle = false;
   aDatabaseInfo->mNeedsCheckpoint = false;
   aDatabaseInfo->mClosing = true;
 
-  nsCOMPtr<nsIRunnable> runnable = new CloseConnectionRunnable(aDatabaseInfo);
+  nsCOMPtr<nsIRunnable> runnable = new CloseConnectionRunnable(aDatabaseInfo,
+                                                               aCallsite);
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     aDatabaseInfo->mThreadInfo.mThread->Dispatch(runnable,
                                                  NS_DISPATCH_NORMAL)));
 }
 
 bool
 ConnectionPool::CloseDatabaseWhenIdleInternal(const nsACString& aDatabaseId)
@@ -12366,17 +12376,17 @@ ConnectionPool::CloseDatabaseWhenIdleInt
 
   PROFILER_LABEL("IndexedDB",
                  "ConnectionPool::CloseDatabaseWhenIdleInternal",
                  js::ProfileEntry::Category::STORAGE);
 
   if (DatabaseInfo* dbInfo = mDatabases.Get(aDatabaseId)) {
     if (mIdleDatabases.RemoveElement(dbInfo) ||
         mDatabasesPerformingIdleMaintenance.RemoveElement(dbInfo)) {
-      CloseDatabase(dbInfo);
+      CloseDatabase(dbInfo, 5);
       AdjustIdleTimer();
     } else {
       dbInfo->mCloseOnIdle = true;
     }
 
     return true;
   }
 
@@ -12454,17 +12464,17 @@ CloseConnectionRunnable::Run()
     MOZ_ASSERT(mDatabaseInfo->mClosing);
 
     nsCOMPtr<nsIEventTarget> owningThread;
     mOwningThread.swap(owningThread);
 
     if (mDatabaseInfo->mConnection) {
       mDatabaseInfo->AssertIsOnConnectionThread();
 
-      mDatabaseInfo->mConnection->Close();
+      mDatabaseInfo->mConnection->Close(mCallsite);
 
       IDB_DEBUG_LOG(("ConnectionPool closed connection 0x%p",
                      mDatabaseInfo->mConnection.get()));
 
       mDatabaseInfo->mConnection = nullptr;
 
 #ifdef DEBUG
       mDatabaseInfo->mDEBUGConnectionThread = nullptr;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -264,16 +264,19 @@ using namespace mozilla::system;
 #endif
 
 #ifdef XP_WIN
 #include "mozilla/widget/AudioSession.h"
 #endif
 
 #include "VRManagerParent.h"            // for VRManagerParent
 
+// For VP9Benchmark::sBenchmarkFpsPref
+#include "Benchmark.h"
+
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 
 #if defined(XP_WIN)
 // e10s forced enable pref, defined in nsAppRunner.cpp
 extern const char* kForceEnableE10sPref;
 #endif
 
 using base::ChildPrivileges;
@@ -5706,16 +5709,27 @@ ContentParent::RecvGetAndroidSystemInfo(
   nsSystemInfo::GetAndroidSystemInfo(aInfo);
   return true;
 #else
   MOZ_CRASH("wrong platform!");
   return false;
 #endif
 }
 
+bool
+ContentParent::RecvNotifyBenchmarkResult(const nsString& aCodecName,
+                                         const uint32_t& aDecodeFPS)
+
+{
+  if (aCodecName.EqualsLiteral("VP9")) {
+    Preferences::SetUint(VP9Benchmark::sBenchmarkFpsPref, aDecodeFPS);
+  }
+  return true;
+}
+
 void
 ContentParent::StartProfiler(nsIProfilerStartParams* aParams)
 {
 #ifdef MOZ_ENABLE_PROFILER_SPS
   if (NS_WARN_IF(!aParams)) {
     return;
   }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1087,16 +1087,19 @@ private:
 
   virtual bool RecvGetDeviceStorageLocation(const nsString& aType,
                                             nsString* aPath) override;
 
   virtual bool RecvGetDeviceStorageLocations(DeviceStorageLocationInfo* info) override;
 
   virtual bool RecvGetAndroidSystemInfo(AndroidSystemInfo* aInfo) override;
 
+  virtual bool RecvNotifyBenchmarkResult(const nsString& aCodecName,
+                                         const uint32_t& aDecodeFPS) override;
+
   // If you add strong pointers to cycle collected objects here, be sure to
   // release these objects in ShutDownProcess.  See the comment there for more
   // details.
 
   GeckoChildProcessHost* mSubprocess;
   ContentParent* mOpener;
 
   ContentParentId mChildID;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1192,15 +1192,22 @@ parent:
      * Tells the parent to ungrab the pointer on the default display.
      *
      * This is for GTK platforms where we have to ensure the pointer ungrab happens in the
      * chrome process as that's the process that receives the pointer event.
      */
     sync UngrabPointer(uint32_t time);
 
     sync RemovePermission(Principal principal, nsCString permissionType) returns (nsresult rv);
+
+    /**
+     * Tell the parent that a decoder's' benchmark has been completed.
+     * The result can then be stored in permanent storage.
+     */
+    async NotifyBenchmarkResult(nsString aCodecName, uint32_t aDecodeFPS);
+
 both:
      async AsyncMessage(nsString aMessage, ClonedMessageData aData,
                         CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -837,16 +837,19 @@ TabChild::Init()
   // XXX: ideally, we would set a chrome event handler earlier,
   // and all windows, even the root one, will use the docshell one.
   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(WebNavigation());
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   nsCOMPtr<EventTarget> chromeHandler =
     do_QueryInterface(window->GetChromeEventHandler());
   docShell->SetChromeEventHandler(chromeHandler);
 
+  nsContentUtils::SetScrollbarsVisibility(window->GetDocShell(),
+    !!(mChromeFlags & nsIWebBrowserChrome::CHROME_SCROLLBARS));
+
   nsWeakPtr weakPtrThis = do_GetWeakReference(static_cast<nsITabChild*>(this));  // for capture by the lambda
   ContentReceivedInputBlockCallback callback(
       [weakPtrThis](const ScrollableLayerGuid& aGuid,
                     uint64_t aInputBlockId,
                     bool aPreventDefault)
       {
         if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
           static_cast<TabChild*>(tabChild.get())->ContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -507,17 +507,21 @@ public:
 
   bool GetUpdateHitRegion() const { return mUpdateHitRegion; }
 
   void UpdateHitRegion(const nsRegion& aRegion);
 
   static inline TabChild*
   GetFrom(nsIDocShell* aDocShell)
   {
-    nsCOMPtr<nsITabChild> tc = do_GetInterface(aDocShell);
+    if (!aDocShell) {
+      return nullptr;
+    }
+
+    nsCOMPtr<nsITabChild> tc = aDocShell->GetTabChild();
     return static_cast<TabChild*>(tc.get());
   }
 
   static inline TabChild*
   GetFrom(mozIDOMWindow* aWindow)
   {
     nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
@@ -530,16 +534,18 @@ public:
     nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
     nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
     return GetFrom(docShell);
   }
 
   static TabChild* GetFrom(nsIPresShell* aPresShell);
   static TabChild* GetFrom(uint64_t aLayersId);
 
+  uint64_t LayersId() { return mLayersId; }
+
   void DidComposite(uint64_t aTransactionId,
                     const TimeStamp& aCompositeStart,
                     const TimeStamp& aCompositeEnd);
 
   void DidRequestComposite(const TimeStamp& aCompositeReqStart,
                            const TimeStamp& aCompositeReqEnd);
 
   void ClearCachedResources();
--- a/dom/media/Benchmark.cpp
+++ b/dom/media/Benchmark.cpp
@@ -7,16 +7,17 @@
 #include "Benchmark.h"
 #include "BufferMediaResource.h"
 #include "MediaData.h"
 #include "PDMFactory.h"
 #include "WebMDemuxer.h"
 #include "WebMSample.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/dom/ContentChild.h"
 
 namespace mozilla {
 
 const char* VP9Benchmark::sBenchmarkFpsPref = "media.benchmark.vp9.fps";
 bool VP9Benchmark::sHasRunTest = false;
 
 bool
 VP9Benchmark::IsVP9DecodeFast()
@@ -40,17 +41,25 @@ VP9Benchmark::IsVP9DecodeFast()
                       1, // start benchmarking after decoding this frame.
                       8, // loop after decoding that many frames.
                       TimeDuration::FromMilliseconds(
                         Preferences::GetUint("media.benchmark.timeout", 1000))
                     });
     estimiser->Run()->Then(
       AbstractThread::MainThread(), __func__,
       [](uint32_t aDecodeFps) {
-        Preferences::SetUint(sBenchmarkFpsPref, aDecodeFps);
+        if (XRE_IsContentProcess()) {
+          dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
+          if (contentChild) {
+            contentChild->SendNotifyBenchmarkResult(NS_LITERAL_STRING("VP9"),
+                                                    aDecodeFps);
+          }
+        } else {
+          Preferences::SetUint(sBenchmarkFpsPref, aDecodeFps);
+        }
         Telemetry::Accumulate(Telemetry::ID::VIDEO_VP9_BENCHMARK_FPS, aDecodeFps);
       },
       []() { });
   }
 
   if (!hasPref) {
     return false;
   }
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -20,16 +20,23 @@
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/MediaStreamError.h"
 #include "mozilla/dom/Promise.h"
 #include "MediaStreamGraph.h"
 #include "AudioStreamTrack.h"
 #include "VideoStreamTrack.h"
 #include "Layers.h"
 
+// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
+// GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing
+// currentTime getter.
+#ifdef GetCurrentTime
+#undef GetCurrentTime
+#endif
+
 #ifdef LOG
 #undef LOG
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -209,17 +209,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mVideoFrameContainer(aDecoder->GetVideoFrameContainer()),
   mAudioChannel(aDecoder->GetAudioChannel()),
   mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
                            /* aSupportsTailDispatch = */ true)),
   mWatchManager(this, mTaskQueue),
   mRealTime(aRealTime),
   mDispatchedStateMachine(false),
   mDelayedScheduler(mTaskQueue),
-  mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"),
+  mState(DECODER_STATE_DECODING_METADATA, "MediaDecoderStateMachine::mState"),
   mCurrentFrameID(0),
   mObservedDuration(TimeUnit(), "MediaDecoderStateMachine::mObservedDuration"),
   mFragmentEndTime(-1),
   mReader(aReader),
   mDecodedAudioEndTime(0),
   mDecodedVideoEndTime(0),
   mPlaybackRate(1.0),
   mLowAudioThresholdUsecs(detail::LOW_AUDIO_USECS),
@@ -1061,17 +1061,21 @@ bool MediaDecoderStateMachine::IsPlaying
   return mMediaSink->IsPlaying();
 }
 
 nsresult MediaDecoderStateMachine::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
   nsresult rv = mReader->Init();
   NS_ENSURE_SUCCESS(rv, rv);
-  ScheduleStateMachineCrossThread();
+
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(
+    this, &MediaDecoderStateMachine::ReadMetadata);
+  OwnerThread()->Dispatch(r.forget());
+
   return NS_OK;
 }
 
 void MediaDecoderStateMachine::StopPlayback()
 {
   MOZ_ASSERT(OnTaskQueue());
   DECODER_LOG("StopPlayback()");
 
@@ -1166,17 +1170,16 @@ void MediaDecoderStateMachine::UpdatePla
   mMetadataManager.DispatchMetadataIfNeeded(TimeUnit::FromMicroseconds(aTime));
 
   if (fragmentEnded) {
     StopPlayback();
   }
 }
 
 static const char* const gMachineStateStr[] = {
-  "NONE",
   "DECODING_METADATA",
   "WAIT_FOR_CDM",
   "DORMANT",
   "DECODING",
   "SEEKING",
   "BUFFERING",
   "COMPLETED",
   "SHUTDOWN",
@@ -1306,19 +1309,19 @@ MediaDecoderStateMachine::SetDormant(boo
     // queuing the ReleaseMediaResources task - instead, we disconnect promises,
     // reset state, and put a ResetDecode in the decode task queue. Any tasks
     // that run after ResetDecode are supposed to run with a clean slate. We rely
     // on that in other places (i.e. seeking), so it seems reasonable to rely on
     // it here as well.
     nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources);
     DecodeTaskQueue()->Dispatch(r.forget());
   } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
-    ScheduleStateMachine();
     mDecodingFirstFrame = true;
-    SetState(DECODER_STATE_DECODING_NONE);
+    SetState(DECODER_STATE_DECODING_METADATA);
+    ReadMetadata();
   }
 }
 
 RefPtr<ShutdownPromise>
 MediaDecoderStateMachine::Shutdown()
 {
   MOZ_ASSERT(OnTaskQueue());
 
@@ -1469,16 +1472,34 @@ void MediaDecoderStateMachine::BufferedR
     bool exists;
     media::TimeUnit end{mBuffered.Ref().GetEnd(&exists)};
     if (exists) {
       mObservedDuration = std::max(mObservedDuration.Ref(), end);
     }
   }
 }
 
+void
+MediaDecoderStateMachine::ReadMetadata()
+{
+  MOZ_ASSERT(OnTaskQueue());
+  MOZ_ASSERT(!IsShutdown());
+  MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
+  MOZ_ASSERT(!mMetadataRequest.Exists());
+
+  DECODER_LOG("Dispatching AsyncReadMetadata");
+  // Set mode to METADATA since we are about to read metadata.
+  mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
+  mMetadataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
+                                     &MediaDecoderReader::AsyncReadMetadata)
+    ->Then(OwnerThread(), __func__, this,
+           &MediaDecoderStateMachine::OnMetadataRead,
+           &MediaDecoderStateMachine::OnMetadataNotRead));
+}
+
 RefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::Seek(SeekTarget aTarget)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (IsShutdown()) {
     return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
   }
@@ -2228,38 +2249,18 @@ nsresult MediaDecoderStateMachine::RunSt
   MediaResource* resource = mResource;
   NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER);
 
   switch (mState) {
     case DECODER_STATE_ERROR:
     case DECODER_STATE_SHUTDOWN:
     case DECODER_STATE_DORMANT:
     case DECODER_STATE_WAIT_FOR_CDM:
-      return NS_OK;
-
-    case DECODER_STATE_DECODING_NONE: {
-      SetState(DECODER_STATE_DECODING_METADATA);
-      ScheduleStateMachine();
+    case DECODER_STATE_DECODING_METADATA:
       return NS_OK;
-    }
-
-    case DECODER_STATE_DECODING_METADATA: {
-      if (!mMetadataRequest.Exists()) {
-        DECODER_LOG("Dispatching AsyncReadMetadata");
-        // Set mode to METADATA since we are about to read metadata.
-        mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
-        mMetadataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
-                                           &MediaDecoderReader::AsyncReadMetadata)
-          ->Then(OwnerThread(), __func__, this,
-                 &MediaDecoderStateMachine::OnMetadataRead,
-                 &MediaDecoderStateMachine::OnMetadataNotRead));
-
-      }
-      return NS_OK;
-    }
 
     case DECODER_STATE_DECODING: {
       if (IsDecodingFirstFrame()) {
         // We haven't completed decoding our first frames, we can't start
         // playback yet.
         return NS_OK;
       }
       if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying())
@@ -2382,18 +2383,17 @@ MediaDecoderStateMachine::Reset()
   DECODER_LOG("MediaDecoderStateMachine::Reset");
 
   // We should be resetting because we're seeking, shutting down, or entering
   // dormant state. We could also be in the process of going dormant, and have
   // just switched to exiting dormant before we finished entering dormant,
   // hence the DECODING_NONE case below.
   MOZ_ASSERT(IsShutdown() ||
              mState == DECODER_STATE_SEEKING ||
-             mState == DECODER_STATE_DORMANT ||
-             mState == DECODER_STATE_DECODING_NONE);
+             mState == DECODER_STATE_DORMANT);
 
   // Stop the audio thread. Otherwise, MediaSink might be accessing AudioQueue
   // outside of the decoder monitor while we are clearing the queue and causes
   // crash for no samples to be popped.
   StopMediaSink();
 
   mDecodedVideoEndTime = 0;
   mDecodedAudioEndTime = 0;
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -141,17 +141,16 @@ public:
   MediaDecoderStateMachine(MediaDecoder* aDecoder,
                            MediaDecoderReader* aReader,
                            bool aRealTime = false);
 
   nsresult Init();
 
   // Enumeration for the valid decoding states
   enum State {
-    DECODER_STATE_DECODING_NONE,
     DECODER_STATE_DECODING_METADATA,
     DECODER_STATE_WAIT_FOR_CDM,
     DECODER_STATE_DORMANT,
     DECODER_STATE_DECODING,
     DECODER_STATE_SEEKING,
     DECODER_STATE_BUFFERING,
     DECODER_STATE_COMPLETED,
     DECODER_STATE_SHUTDOWN,
@@ -262,16 +261,18 @@ private:
   // task that gets run on the task queue, and is dispatched from the MDSM
   // constructor immediately after the task queue is created.
   void InitializationTask(MediaDecoder* aDecoder);
 
   void SetDormant(bool aDormant);
 
   void SetAudioCaptured(bool aCaptured);
 
+  void ReadMetadata();
+
   RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget);
 
   RefPtr<ShutdownPromise> Shutdown();
 
   RefPtr<ShutdownPromise> FinishShutdown();
 
   // Update the playback position. This can result in a timeupdate event
   // and an invalidate of the frame being dispatched asynchronously if
@@ -317,27 +318,17 @@ private:
     MOZ_ASSERT(OnTaskQueue());
     return mState == DECODER_STATE_SEEKING;
   }
 
   // Returns the state machine task queue.
   TaskQueue* OwnerThread() const { return mTaskQueue; }
 
   // Schedules the shared state machine thread to run the state machine.
-  //
-  // The first variant coalesces multiple calls into a single state machine
-  // cycle, the second variant does not. The second variant must be used when
-  // not already on the state machine task queue.
   void ScheduleStateMachine();
-  void ScheduleStateMachineCrossThread()
-  {
-    nsCOMPtr<nsIRunnable> task =
-      NS_NewRunnableMethod(this, &MediaDecoderStateMachine::RunStateMachine);
-    OwnerThread()->Dispatch(task.forget());
-  }
 
   // Invokes ScheduleStateMachine to run in |aMicroseconds| microseconds,
   // unless it's already scheduled to run earlier, in which case the
   // request is discarded.
   void ScheduleStateMachineIn(int64_t aMicroseconds);
 
   void OnDelayedSchedule()
   {
--- a/dom/media/MediaPermissionGonk.cpp
+++ b/dom/media/MediaPermissionGonk.cpp
@@ -238,19 +238,22 @@ NS_IMETHODIMP
 MediaPermissionRequest::Allow(JS::HandleValue aChoices)
 {
   // check if JS object
   if (!aChoices.isObject()) {
     MOZ_ASSERT(false, "Not a correct format of PermissionChoice");
     return NS_ERROR_INVALID_ARG;
   }
   // iterate through audio-capture and video-capture
-  AutoSafeJSContext cx;
+  AutoJSAPI jsapi;
+  if (!jsapi.init(&aChoices.toObject())) {
+    return NS_ERROR_UNEXPECTED;
+  }
+  JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
-  JSAutoCompartment ac(cx, obj);
   JS::Rooted<JS::Value> v(cx);
 
   // get selected audio device name
   nsString audioDevice;
   if (mAudio) {
     if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) {
       return NS_ERROR_FAILURE;
     }
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -370,25 +370,24 @@ RTCPeerConnection.prototype = {
 
     if (!rtcConfig.iceServers ||
         !Services.prefs.getBoolPref("media.peerconnection.use_document_iceservers")) {
       try {
          rtcConfig.iceServers =
            JSON.parse(Services.prefs.getCharPref("media.peerconnection.default_iceservers") || "[]");
       } catch (e) {
         this.logWarning(
-            "Ignoring invalid media.peerconnection.default_iceservers in about:config",
-             null, 0);
+            "Ignoring invalid media.peerconnection.default_iceservers in about:config");
         rtcConfig.iceServers = [];
       }
       try {
         this._mustValidateRTCConfiguration(rtcConfig,
             "Ignoring invalid media.peerconnection.default_iceservers in about:config");
       } catch (e) {
-        this.logWarning(e.message, null, 0);
+        this.logWarning(e.message);
         rtcConfig.iceServers = [];
       }
     } else {
       // This gets executed in the typical case when iceServers
       // are passed in through the web page.
       this._mustValidateRTCConfiguration(rtcConfig,
         "RTCPeerConnection constructor passed invalid RTCConfiguration");
     }
@@ -557,17 +556,17 @@ RTCPeerConnection.prototype = {
 
     // Normalize iceServers input
     rtcConfig.iceServers.forEach(server => {
       if (typeof server.urls === "string") {
         server.urls = [server.urls];
       } else if (!server.urls && server.url) {
         // TODO: Remove support for legacy iceServer.url eventually (Bug 1116766)
         server.urls = [server.url];
-        this.logWarning("RTCIceServer.url is deprecated! Use urls instead.", null, 0);
+        this.logWarning("RTCIceServer.url is deprecated! Use urls instead.");
       }
     });
 
     let ios = Cc['@mozilla.org/network/io-service;1'].getService(Ci.nsIIOService);
 
     let nicerNewURI = uriStr => {
       try {
         return ios.newURI(uriStr, null, null);
@@ -591,26 +590,25 @@ RTCPeerConnection.prototype = {
           if (!server.credential) {
             throw new this._win.DOMException(msg + " - missing credential: " + urlStr,
                                              "InvalidAccessError");
           }
           if (server.credentialType != "password") {
             this.logWarning("RTCConfiguration TURN credentialType \""+
                             server.credentialType +
                             "\" is not yet implemented. Treating as password."+
-                            " https://bugzil.la/1247616",
-                            null, 0);
+                            " https://bugzil.la/1247616");
           }
         }
         else if (!(url.scheme in { stun:1, stuns:1 })) {
           throw new this._win.DOMException(msg + " - improper scheme: " + url.scheme,
                                            "SyntaxError");
         }
         if (url.scheme in { stuns:1, turns:1 }) {
-          this.logWarning(url.scheme.toUpperCase() + " is not yet supported.", null, 0);
+          this.logWarning(url.scheme.toUpperCase() + " is not yet supported.");
         }
       });
     });
   },
 
   // Ideally, this should be of the form _checkState(state),
   // where the state is taken from an enumeration containing
   // the valid peer connection states defined in the WebRTC
@@ -637,27 +635,32 @@ RTCPeerConnection.prototype = {
     // Safely call onerror directly if present (necessary for testing)
     try {
       if (typeof this._win.onerror === "function") {
         this._win.onerror(e.message, e.fileName, e.lineNumber);
       }
     } catch(e) {
       // If onerror itself throws, service it.
       try {
-        this.logError(e.message, e.fileName, e.lineNumber);
+        this.logMsg(e.message, e.fileName, e.lineNumber, Ci.nsIScriptError.errorFlag);
       } catch(e) {}
     }
   },
 
-  logError: function(msg, file, line) {
-    this.logMsg(msg, file, line, Ci.nsIScriptError.errorFlag);
+  logError: function(msg) {
+    this.logStackMsg(msg, Ci.nsIScriptError.errorFlag);
   },
 
-  logWarning: function(msg, file, line) {
-    this.logMsg(msg, file, line, Ci.nsIScriptError.warningFlag);
+  logWarning: function(msg) {
+    this.logStackMsg(msg, Ci.nsIScriptError.warningFlag);
+  },
+
+  logStackMsg: function(msg, flag) {
+    let err = this._win.Error();
+    this.logMsg(msg, err.fileName, err.lineNumber, flag);
   },
 
   logMsg: function(msg, file, line, flag) {
     let scriptErrorClass = Cc["@mozilla.org/scripterror;1"];
     let scriptError = scriptErrorClass.createInstance(Ci.nsIScriptError);
     scriptError.initWithWindowID(msg, file, null, line, 0, flag,
                                  "content javascript", this._winID);
     let console = Cc["@mozilla.org/consoleservice;1"].
@@ -681,18 +684,17 @@ RTCPeerConnection.prototype = {
                           });
   },
 
   makeLegacyGetterSetterEH: function(name, msg) {
     Object.defineProperty(this, name,
                           {
                             get:function()  { return this.getEH(name); },
                             set:function(h) {
-                              this.logWarning(name + " is deprecated! " + msg,
-                                              null, 0);
+                              this.logWarning(name + " is deprecated! " + msg);
                               return this.setEH(name, h);
                             }
                           });
   },
 
   _addIdentityAssertion: function(sdpPromise, origin) {
     if (!this._localIdp.enabled) {
       return sdpPromise;
@@ -748,18 +750,17 @@ RTCPeerConnection.prototype = {
           }
         });
         return true;
       }
 
       if (options && convertLegacyOptions(options)) {
         this.logError(
           "Mandatory/optional in createOffer options no longer works! Use " +
-            JSON.stringify(options) + " instead (note the case difference)!",
-          null, 0);
+            JSON.stringify(options) + " instead (note the case difference)!");
         options = {};
       }
 
       let origin = Cu.getWebIDLCallerPrincipal().origin;
       return this._chain(() => {
         let p = Promise.all([this.getPermission(), this._certificateReady])
           .then(() => new this._win.Promise((resolve, reject) => {
             this._onCreateOfferSuccess = resolve;
@@ -1230,31 +1231,31 @@ RTCPeerConnection.prototype = {
 
   createDataChannel: function(label, dict) {
     this._checkClosed();
     if (dict == undefined) {
       dict = {};
     }
     if (dict.maxRetransmitNum != undefined) {
       dict.maxRetransmits = dict.maxRetransmitNum;
-      this.logWarning("Deprecated RTCDataChannelInit dictionary entry maxRetransmitNum used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry maxRetransmitNum used!");
     }
     if (dict.outOfOrderAllowed != undefined) {
       dict.ordered = !dict.outOfOrderAllowed; // the meaning is swapped with
                                               // the name change
-      this.logWarning("Deprecated RTCDataChannelInit dictionary entry outOfOrderAllowed used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry outOfOrderAllowed used!");
     }
 
     if (dict.preset != undefined) {
       dict.negotiated = dict.preset;
-      this.logWarning("Deprecated RTCDataChannelInit dictionary entry preset used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry preset used!");
     }
     if (dict.stream != undefined) {
       dict.id = dict.stream;
-      this.logWarning("Deprecated RTCDataChannelInit dictionary entry stream used!", null, 0);
+      this.logWarning("Deprecated RTCDataChannelInit dictionary entry stream used!");
     }
 
     if (dict.maxRetransmitTime !== null && dict.maxRetransmits !== null) {
       throw new this._win.DOMException(
           "Both maxRetransmitTime and maxRetransmits cannot be provided",
           "InvalidParameterError");
     }
     let protocol;
@@ -1434,17 +1435,17 @@ PeerConnectionObserver.prototype = {
           iceConnectionState === 'connected') {
         success_histogram.add(true);
       } else if (iceConnectionState === 'failed') {
         success_histogram.add(false);
       }
     }
 
     if (iceConnectionState === 'failed') {
-      pc.logError("ICE failed, see about:webrtc for more details", null, 0);
+      pc.logError("ICE failed, see about:webrtc for more details");
     }
 
     pc.changeIceConnectionState(iceConnectionState);
   },
 
   // This method is responsible for updating iceGatheringState. This
   // state is defined in the WebRTC specification as follows:
   //
@@ -1486,17 +1487,17 @@ PeerConnectionObserver.prototype = {
         // No-op
         break;
 
       case "SipccState":
         // No-op
         break;
 
       default:
-        this._dompc.logWarning("Unhandled state type: " + state, null, 0);
+        this._dompc.logWarning("Unhandled state type: " + state);
         break;
     }
   },
 
   onGetStatsSuccess: function(dict) {
     let pc = this._dompc;
     let chromeobj = new RTCStatsReport(pc._win, dict);
     let webidlobj = pc._win.RTCStatsReport._create(pc._win, chromeobj);
--- a/dom/media/tests/mochitest/test_peerConnection_bug825703.html
+++ b/dom/media/tests/mochitest/test_peerConnection_bug825703.html
@@ -6,16 +6,22 @@
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "825703",
     title: "RTCConfiguration valid/invalid permutations"
   });
 
+// ^^^ Don't insert data above this line without adjusting line number below!
+var lineNumberAndFunction = {
+// <--- 16 is the line this must be.
+  line: 17, func: () => new RTCPeerConnection().onaddstream = () => {}
+};
+
 var makePC = (config, expected_error) => {
   var exception;
   try {
     new RTCPeerConnection(config).close();
   } catch (e) {
     exception = e;
   }
   is((exception? exception.name : "success"), expected_error || "success",
@@ -92,28 +98,63 @@ runNetworkTest(() => {
       { urls: ["turn:[::1]:3478"], username:"p", credential:"p", credentialType:"token" },
     ],
   };
   var pc = new RTCPeerConnection(config);
   is(JSON.stringify(toComparable(pc.getConfiguration())),
      JSON.stringify(toComparable(config)), "getConfiguration");
   pc.close();
 
-  // Below tests are setting the about:config User preferences for default
-  // ice servers and checking the outputs when RTCPeerConnection() is
-  // invoked. See Bug 1167922 for more information.
-  // Note - We use promises here since the SpecialPowers API will be
-  // performed asynchronously.
   var push = prefs => new Promise(resolve =>
       SpecialPowers.pushPrefEnv(prefs, resolve));
 
-  push({ set: [['media.peerconnection.default_iceservers', ""]] })
-      .then(() => makePC())
-      .then(() => push({ set: [['media.peerconnection.default_iceservers', "k"]] }))
-      .then(() => makePC())
-      .then(() => push({ set: [['media.peerconnection.default_iceservers', "[{\"urls\": [\"stun:stun.services.mozilla.com\"]}]"]] }))
-      .then(() => makePC())
-      .then(networkTestFinished);
+  Promise.resolve()
+  // This set of tests are setting the about:config User preferences for default
+  // ice servers and checking the outputs when RTCPeerConnection() is
+  // invoked. See Bug 1167922 for more information.
+  .then(() => push({ set: [['media.peerconnection.default_iceservers', ""]] })
+    .then(() => makePC())
+    .then(() => push({ set: [['media.peerconnection.default_iceservers', "k"]] }))
+    .then(() => makePC())
+    .then(() => push({ set: [['media.peerconnection.default_iceservers', "[{\"urls\": [\"stun:stun.services.mozilla.com\"]}]"]] }))
+    .then(() => makePC()))
+  // This set of tests check that warnings work. See Bug 1254839 for more.
+  .then(() => {
+    var consoleService = SpecialPowers.Cc["@mozilla.org/consoleservice;1"]
+                         .getService(SpecialPowers.Ci.nsIConsoleService);
+    var warning = "";
+    var listener = SpecialPowers.wrapCallbackObject({
+      QueryInterface(iid) {
+        if (![SpecialPowers.Ci.nsIConsoleListener,
+              SpecialPowers.Ci.nsISupports].some(i => iid.equals(i))) {
+          throw SpecialPowers.Cr.NS_NOINTERFACE;
+        }
+        return this;
+      },
+
+      observe(msg) {
+        if (msg.message.includes("JavaScript Warning")) {
+          warning = msg.message;
+        }
+      }
+    });
+    consoleService.registerListener(listener);
+    lineNumberAndFunction.func();
+    // Console output is asynchronous, so we must queue a task.
+    return wait(0).then(() => {
+      is(warning.split('"')[1],
+         "onaddstream is deprecated! Use peerConnection.ontrack instead.",
+         "warning logged");
+      var remainder = warning.split('"').slice(2).join('"');
+      info(remainder);
+      ok(remainder.includes('file: "' + window.location + '"'),
+         "warning has this file");
+      ok(remainder.includes('line: ' + lineNumberAndFunction.line),
+         "warning has correct line number");
+      consoleService.unregisterListener(listener);
+    });
+  })
+  .then(networkTestFinished);
 });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/plugins/base/npapi.h
+++ b/dom/plugins/base/npapi.h
@@ -407,16 +407,18 @@ typedef enum {
   NPNVSupportsWindowless = 17,
 
   NPNVprivateModeBool = 18,
 
   NPNVsupportsAdvancedKeyHandling = 21,
 
   NPNVdocumentOrigin = 22,
 
+  NPNVCSSZoomFactor = 23,
+
   NPNVpluginDrawingModel = 1000 /* Get the current drawing model (NPDrawingModel) */
 #if defined(XP_MACOSX)
   , NPNVcontentsScaleFactor = 1001
 #ifndef NP_NO_QUICKDRAW
   , NPNVsupportsQuickDrawBool = 2000
 #endif
   , NPNVsupportsCoreGraphicsBool = 2001
   , NPNVsupportsOpenGLBool = 2002
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2026,16 +2026,24 @@ NPError
     nsNPAPIPluginInstance *inst =
       (nsNPAPIPluginInstance *) (npp ? npp->ndata : nullptr);
     double scaleFactor = inst ? inst->GetContentsScaleFactor() : 1.0;
     *(double*)result = scaleFactor;
     return NPERR_NO_ERROR;
   }
 #endif
 
+  case NPNVCSSZoomFactor: {
+    nsNPAPIPluginInstance *inst =
+      (nsNPAPIPluginInstance *) (npp ? npp->ndata : nullptr);
+    double scaleFactor = inst ? inst->GetCSSZoomFactor() : 1.0;
+    *(double*)result = scaleFactor;
+    return NPERR_NO_ERROR;
+  }
+
 #ifdef MOZ_WIDGET_ANDROID
     case kLogInterfaceV0_ANPGetValue: {
       LOG("get log interface");
       ANPLogInterfaceV0 *i = (ANPLogInterfaceV0 *) result;
       InitLogInterface(i);
       return NPERR_NO_ERROR;
     }
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -996,17 +996,18 @@ nsresult nsNPAPIPluginInstance::IsRemote
       return NS_ERROR_FAILURE;
 
   return library->IsRemoteDrawingCoreAnimation(&mNPP, aDrawing);
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
-nsresult nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor)
+nsresult
+nsNPAPIPluginInstance::ContentsScaleFactorChanged(double aContentsScaleFactor)
 {
 #ifdef XP_MACOSX
   if (!mPlugin)
       return NS_ERROR_FAILURE;
 
   PluginLibrary* library = mPlugin->GetLibrary();
   if (!library)
       return NS_ERROR_FAILURE;
@@ -1017,16 +1018,41 @@ nsresult nsNPAPIPluginInstance::Contents
 
   return library->ContentsScaleFactorChanged(&mNPP, aContentsScaleFactor);
 #else
   return NS_ERROR_FAILURE;
 #endif
 }
 
 nsresult
+nsNPAPIPluginInstance::CSSZoomFactorChanged(float aCSSZoomFactor)
+{
+  if (RUNNING != mRunning)
+    return NS_OK;
+
+  PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of CSS Zoom Factor change this=%p\n",this));
+
+  if (!mPlugin || !mPlugin->GetLibrary())
+    return NS_ERROR_FAILURE;
+
+  NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs();
+
+  if (!pluginFunctions->setvalue)
+    return NS_ERROR_FAILURE;
+
+  PluginDestructionGuard guard(this);
+
+  NPError error;
+  double value = static_cast<double>(aCSSZoomFactor);
+  NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVCSSZoomFactor, &value), this,
+                          NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
+  return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
 nsNPAPIPluginInstance::GetJSObject(JSContext *cx, JSObject** outObject)
 {
   if (mHaveJavaC2PJSObjectQuirk) {
     return NS_ERROR_FAILURE;
   }
 
   NPObject *npobj = nullptr;
   nsresult rv = GetValueFromPlugin(NPPVpluginScriptableNPObject, &npobj);
@@ -1734,16 +1760,26 @@ nsNPAPIPluginInstance::GetContentsScaleF
 {
   double scaleFactor = 1.0;
   if (mOwner) {
     mOwner->GetContentsScaleFactor(&scaleFactor);
   }
   return scaleFactor;
 }
 
+float
+nsNPAPIPluginInstance::GetCSSZoomFactor()
+{
+  float zoomFactor = 1.0;
+  if (mOwner) {
+    mOwner->GetCSSZoomFactor(&zoomFactor);
+  }
+  return zoomFactor;
+}
+
 nsresult
 nsNPAPIPluginInstance::GetRunID(uint32_t* aRunID)
 {
   if (NS_WARN_IF(!aRunID)) {
     return NS_ERROR_INVALID_POINTER;
   }
 
   if (NS_WARN_IF(!mPlugin)) {
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -95,16 +95,17 @@ public:
   nsresult NewStreamFromPlugin(const char* type, const char* target, nsIOutputStream* *result);
   nsresult Print(NPPrint* platformPrint);
   nsresult HandleEvent(void* event, int16_t* result,
                        NSPluginCallReentry aSafeToReenterGecko = NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO);
   nsresult GetValueFromPlugin(NPPVariable variable, void* value);
   nsresult GetDrawingModel(int32_t* aModel);
   nsresult IsRemoteDrawingCoreAnimation(bool* aDrawing);
   nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
+  nsresult CSSZoomFactorChanged(float aCSSZoomFactor);
   nsresult GetJSObject(JSContext *cx, JSObject** outObject);
   bool ShouldCache();
   nsresult IsWindowless(bool* isWindowless);
   nsresult AsyncSetWindow(NPWindow* window);
   nsresult GetImageContainer(mozilla::layers::ImageContainer **aContainer);
   nsresult GetImageSize(nsIntSize* aSize);
   nsresult NotifyPainted(void);
   nsresult GetIsOOP(bool* aIsOOP);
@@ -301,16 +302,19 @@ public:
 
   // Called when the instance fails to instantiate beceause the Carbon
   // event model is not supported.
   void CarbonNPAPIFailure();
 
   // Returns the contents scale factor of the screen the plugin is drawn on.
   double GetContentsScaleFactor();
 
+  // Returns the css zoom factor of the document the plugin is drawn on.
+  float GetCSSZoomFactor();
+
   nsresult GetRunID(uint32_t *aRunID);
 
   static bool InPluginCallUnsafeForReentry() { return gInUnsafePluginCalls > 0; }
   static void BeginPluginCall(NSPluginCallReentry aReentryState)
   {
     if (aReentryState == NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO) {
       ++gInUnsafePluginCalls;
     }
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -356,16 +356,17 @@ nsPluginInstanceOwner::nsPluginInstanceO
   mWidgetCreationComplete = false;
 #ifdef XP_MACOSX
   mSentInitialTopLevelWindowEvent = false;
   mLastWindowIsActive = false;
   mLastContentFocused = false;
   mLastScaleFactor = 1.0;
   mShouldBlurOnActivate = false;
 #endif
+  mLastCSSZoomFactor = 1.0;
   mContentFocused = false;
   mWidgetVisible = true;
   mPluginWindowVisible = false;
   mPluginDocumentActiveState = true;
   mLastMouseDownButtonType = -1;
 
 #ifdef XP_MACOSX
 #ifndef NP_NO_CARBON
@@ -3531,27 +3532,16 @@ nsPluginInstanceOwner::SendWindowFocusCh
   cocoaEvent.type = NPCocoaEventWindowFocusChanged;
   cocoaEvent.data.focus.hasFocus = aIsActive;
   mInstance->HandleEvent(&cocoaEvent,
                          nullptr,
                          NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
 }
 
 void
-nsPluginInstanceOwner::ResolutionMayHaveChanged()
-{
-  double scaleFactor = 1.0;
-  GetContentsScaleFactor(&scaleFactor);
-  if (scaleFactor != mLastScaleFactor) {
-    ContentsScaleFactorChanged(scaleFactor);
-    mLastScaleFactor = scaleFactor;
-   }
-}
-
-void
 nsPluginInstanceOwner::HidePluginWindow()
 {
   if (!mPluginWindow || !mInstance) {
     return;
   }
 
   mPluginWindow->clipRect.bottom = mPluginWindow->clipRect.top;
   mPluginWindow->clipRect.right  = mPluginWindow->clipRect.left;
@@ -3612,16 +3602,38 @@ void
 nsPluginInstanceOwner::UpdateWindowVisibility(bool aVisible)
 {
   mPluginWindowVisible = aVisible;
   UpdateWindowPositionAndClipRect(true);
 }
 #endif // XP_MACOSX
 
 void
+nsPluginInstanceOwner::ResolutionMayHaveChanged()
+{
+#ifdef XP_MACOSX
+  double scaleFactor = 1.0;
+  GetContentsScaleFactor(&scaleFactor);
+  if (scaleFactor != mLastScaleFactor) {
+    ContentsScaleFactorChanged(scaleFactor);
+    mLastScaleFactor = scaleFactor;
+  }
+#endif
+  float zoomFactor = 1.0;
+  GetCSSZoomFactor(&zoomFactor);
+  if (zoomFactor != mLastCSSZoomFactor) {
+    if (mInstance) {
+      mInstance->CSSZoomFactorChanged(zoomFactor);
+    }
+    mLastCSSZoomFactor = zoomFactor;
+  }
+
+}
+
+void
 nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive)
 {
   PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
 
   mPluginDocumentActiveState = aIsActive;
 #ifndef XP_MACOSX
   UpdateWindowPositionAndClipRect(true);
 
@@ -3690,16 +3702,28 @@ nsPluginInstanceOwner::GetContentsScaleF
     scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
       presShell->GetPresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
   }
 #endif
   *result = scaleFactor;
   return NS_OK;
 }
 
+void
+nsPluginInstanceOwner::GetCSSZoomFactor(float *result)
+{
+  nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
+  nsIPresShell* presShell = nsContentUtils::FindPresShellForDocument(content->OwnerDoc());
+  if (presShell) {
+    *result = presShell->GetPresContext()->DeviceContext()->GetFullZoom();
+  } else {
+    *result = 1.0;
+  }
+}
+
 void nsPluginInstanceOwner::SetFrame(nsPluginFrame *aFrame)
 {
   // Don't do anything if the frame situation hasn't changed.
   if (mPluginFrame == aFrame) {
     return;
   }
 
   nsCOMPtr<nsIContent> content = do_QueryReferent(mContent);
--- a/dom/plugins/base/nsPluginInstanceOwner.h
+++ b/dom/plugins/base/nsPluginInstanceOwner.h
@@ -133,17 +133,16 @@ public:
   void SetWidgetWindowAsParent(HWND aWindowToAdopt);
   nsresult SetNetscapeWindowAsParent(HWND aWindowToAdopt);
 #endif
   
 #ifdef XP_MACOSX
   enum { ePluginPaintEnable, ePluginPaintDisable };
 
   void WindowFocusMayHaveChanged();
-  void ResolutionMayHaveChanged();
 
   bool WindowIsActive();
   void SendWindowFocusChanged(bool aIsActive);
   NPDrawingModel GetDrawingModel();
   bool IsRemoteDrawingCoreAnimation();
   nsresult ContentsScaleFactorChanged(double aContentsScaleFactor);
   NPEventModel GetEventModel();
   static void CARefresh(nsITimer *aTimer, void *aClosure);
@@ -155,16 +154,17 @@ public:
   // Set plugin port info in the plugin (in the 'window' member of the
   // NPWindow structure passed to the plugin by SetWindow()).
   void SetPluginPort();
 #else // XP_MACOSX
   void UpdateWindowPositionAndClipRect(bool aSetWindow);
   void UpdateWindowVisibility(bool aVisible);
 #endif // XP_MACOSX
 
+  void ResolutionMayHaveChanged();
   void UpdateDocumentActiveState(bool aIsActive);
 
   void SetFrame(nsPluginFrame *aFrame);
   nsPluginFrame* GetFrame();
 
   uint32_t GetLastEventloopNestingLevel() const {
     return mLastEventloopNestingLevel; 
   }
@@ -273,16 +273,17 @@ public:
   void NotifyDestroyPending();
 
   bool GetCompositionString(uint32_t aIndex, nsTArray<uint8_t>* aString,
                             int32_t* aLength);
   bool SetCandidateWindow(
            const mozilla::widget::CandidateWindowPosition& aPosition);
   bool RequestCommitOrCancel(bool aCommitted);
 
+  void GetCSSZoomFactor(float *result);
 private:
   virtual ~nsPluginInstanceOwner();
 
   // return FALSE if LayerSurface dirty (newly created and don't have valid plugin content yet)
   bool IsUpToDate()
   {
     nsIntSize size;
     return NS_SUCCEEDED(mInstance->GetImageSize(&size)) &&
@@ -323,17 +324,17 @@ private:
   static nsTArray<nsPluginInstanceOwner*>  *sCARefreshListeners;
   bool                                      mSentInitialTopLevelWindowEvent;
   bool                                      mLastWindowIsActive;
   bool                                      mLastContentFocused;
   double                                    mLastScaleFactor;
   // True if, the next time the window is activated, we should blur ourselves.
   bool                                      mShouldBlurOnActivate;
 #endif
-
+  double                                    mLastCSSZoomFactor;
   // Initially, the event loop nesting level we were created on, it's updated
   // if we detect the appshell is on a lower level as long as we're not stopped.
   // We delay DoStopPlugin() until the appshell reaches this level or lower.
   uint32_t                    mLastEventloopNestingLevel;
   bool                        mContentFocused;
   bool                        mWidgetVisible;    // used on Mac to store our widget's visible state
 #ifdef MOZ_X11
   // Used with windowless plugins only, initialized in CreateWidget().
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -92,16 +92,18 @@ child:
 
   intr NPP_GetValue_NPPVpluginScriptableNPObject()
     returns (nullable PPluginScriptableObject value, NPError result);
 
   intr NPP_SetValue_NPNVprivateModeBool(bool value) returns (NPError result);
   intr NPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId()
     returns (nsCString plug_id, NPError result);
 
+  intr NPP_SetValue_NPNVCSSZoomFactor(double value) returns (NPError result);
+
   intr NPP_SetValue_NPNVmuteAudioBool(bool muted) returns (NPError result);
 
   intr NPP_HandleEvent(NPRemoteEvent event)
     returns (int16_t handled);
   // special cases where we need to a shared memory buffer
   intr NPP_HandleEvent_Shmem(NPRemoteEvent event, Shmem buffer)
     returns (int16_t handled, Shmem rtnbuffer);
   // special cases where we need an iosurface
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -538,16 +538,20 @@ PluginInstanceChild::NPN_GetValue(NPNVar
 #endif /* NP_NO_QUICKDRAW */
 
     case NPNVcontentsScaleFactor: {
         *static_cast<double*>(aValue) = mContentsScaleFactor;
         return NPERR_NO_ERROR;
     }
 #endif /* XP_MACOSX */
 
+    case NPNVCSSZoomFactor: {
+        *static_cast<double*>(aValue) = mCSSZoomFactor;
+        return NPERR_NO_ERROR;
+    }
 #ifdef DEBUG
     case NPNVjavascriptEnabledBool:
     case NPNVasdEnabledBool:
     case NPNVisOfflineBool:
     case NPNVSupportsXEmbedBool:
     case NPNVSupportsWindowless:
         NS_NOTREACHED("NPNVariable should be handled in PluginModuleChild.");
         MOZ_FALLTHROUGH;
@@ -813,16 +817,31 @@ PluginInstanceChild::AnswerNPP_SetValue_
     }
 
     NPBool v = value;
     *result = mPluginIface->setvalue(GetNPP(), NPNVprivateModeBool, &v);
     return true;
 }
 
 bool
+PluginInstanceChild::AnswerNPP_SetValue_NPNVCSSZoomFactor(const double& value,
+                                                          NPError* result)
+{
+    if (!mPluginIface->setvalue) {
+        *result = NPERR_GENERIC_ERROR;
+        return true;
+    }
+
+    mCSSZoomFactor = value;
+    double v = value;
+    *result = mPluginIface->setvalue(GetNPP(), NPNVCSSZoomFactor, &v);
+    return true;
+}
+
+bool
 PluginInstanceChild::AnswerNPP_SetValue_NPNVmuteAudioBool(const bool& value,
                                                           NPError* result)
 {
     if (!mPluginIface->setvalue) {
         *result = NPERR_GENERIC_ERROR;
         return true;
     }
 
--- a/dom/plugins/ipc/PluginInstanceChild.h
+++ b/dom/plugins/ipc/PluginInstanceChild.h
@@ -84,16 +84,18 @@ protected:
                                                     NPError* result) override;
     virtual bool
     AnswerNPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId(nsCString* aPlugId,
                                                            NPError* aResult) override;
     virtual bool
     AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value, NPError* result) override;
     virtual bool
     AnswerNPP_SetValue_NPNVmuteAudioBool(const bool& value, NPError* result) override;
+    virtual bool
+    AnswerNPP_SetValue_NPNVCSSZoomFactor(const double& value, NPError* result) override;
 
     virtual bool
     AnswerNPP_HandleEvent(const NPRemoteEvent& event, int16_t* handled) override;
     virtual bool
     AnswerNPP_HandleEvent_Shmem(const NPRemoteEvent& event,
                                 Shmem&& mem,
                                 int16_t* handled,
                                 Shmem* rtnmem) override;
@@ -398,16 +400,17 @@ private:
     uint16_t                    mMode;
     InfallibleTArray<nsCString> mNames;
     InfallibleTArray<nsCString> mValues;
     NPP_t mData;
     NPWindow mWindow;
 #if defined(XP_DARWIN)
     double mContentsScaleFactor;
 #endif
+    double mCSSZoomFactor;
     int16_t               mDrawingModel;
 
     NPAsyncSurface* mCurrentDirectSurface;
 
     // The surface hashtables below serve a few purposes. They let us verify
     // and retain extra information about plugin surfaces, and they let us
     // free shared memory that the plugin might forget to release.
     struct DirectBitmap {
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -1730,16 +1730,23 @@ PluginInstanceParent::NPP_SetValue(NPNVa
 
     case NPNVmuteAudioBool:
         if (!CallNPP_SetValue_NPNVmuteAudioBool(*static_cast<NPBool*>(value),
                                                 &result))
             return NPERR_GENERIC_ERROR;
 
         return result;
 
+    case NPNVCSSZoomFactor:
+        if (!CallNPP_SetValue_NPNVCSSZoomFactor(*static_cast<double*>(value),
+                                                &result))
+            return NPERR_GENERIC_ERROR;
+
+        return result;
+
     default:
         NS_ERROR("Unhandled NPNVariable in NPP_SetValue");
         MOZ_LOG(GetPluginLog(), LogLevel::Warning,
                ("In PluginInstanceParent::NPP_SetValue: Unhandled NPNVariable %i (%s)",
                 (int) variable, NPNVariableToString(variable)));
         return NPERR_GENERIC_ERROR;
     }
 }
--- a/dom/plugins/test/mochitest/mochitest.ini
+++ b/dom/plugins/test/mochitest/mochitest.ini
@@ -112,16 +112,17 @@ support-files =
 [test_pluginstream_seek.html]
 [test_pluginstream_seek_close.html]
 [test_pluginstream_src.html]
 [test_pluginstream_src_dynamic.html]
 [test_pluginstream_src_referer.html]
 [test_positioning.html]
 skip-if = true # disabled due to oddness, perhaps scrolling of the mochitest window?
 [test_propertyAndMethod.html]
+[test_queryCSSZoomFactor.html]
 [test_queryContentsScaleFactor.html]
 skip-if = toolkit != "cocoa"
 [test_redirect_handling.html]
 [test_secondPlugin.html]
 [test_src_url_change.html]
 [test_streamNotify.html]
 [test_stringHandling.html]
 [test_streamatclose.html]
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_queryCSSZoomFactor.html
@@ -0,0 +1,48 @@
+<html>
+  <head>
+    <title>NPAPI NPNVcontentsScaleFactor Test</title>
+    <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+    <script type="application/javascript" src="plugin-utils.js"></script>
+  </head>
+
+  <body onload="runTests()">
+    <script class="testbody" type="application/javascript">
+     SimpleTest.waitForExplicitFinish();
+     setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
+
+     function checkZoomFactor(zoomFactor, expectedValue) {
+       // Done as if/ok instead of is() so we don't spam test results
+       if (isNaN(zoomFactor)) {
+         ok(false, "Return should be valid when getting CSS zoom factor");
+       }
+       return (expectedValue - zoomFactor) < 0.00001;
+     }
+
+     function testZoom() {
+       var pluginElement = document.getElementById("plugin");
+       // setTimeout loop on value checks, as zoom value updates can take some
+       // time and we don't have a good event to listen for.
+       if (!checkZoomFactor(pluginElement.queryCSSZoomFactorGetValue(), 2.0) ||
+           !checkZoomFactor(pluginElement.queryCSSZoomFactorSetValue(), 2.0)) {
+         setTimeout(testZoom, 0);
+         return;
+       }
+       ok(true, "Zoom values set to 2.0 as expected");
+       // set back to 1 when we're done otherwise later tests can fail
+       SpecialPowers.setFullZoom(window, 1.0);
+       SimpleTest.finish();
+     }
+
+     function runTests() {
+       var pluginElement = document.getElementById("plugin");
+       // Don't check SetValue yet, needs to happen after zoom has been explicitly set.
+       ok(checkZoomFactor(pluginElement.queryCSSZoomFactorGetValue(), 1.0), "Zoom values set to 1.0 as expected");
+       SpecialPowers.setFullZoom(window, 2.0);
+       // Check for new zoom value sometime after we've spun event loop to repaint.
+       setTimeout(testZoom, 0);
+     }
+    </script>
+
+    <embed id="plugin" type="application/x-test" width="400" height="400"></embed>
+  </body>
+</html>
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -163,16 +163,18 @@ static bool isVisible(NPObject* npobj, c
 static bool getWindowPosition(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool constructObject(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setSitesWithData(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setSitesWithDataCapabilities(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getNPNVdocumentOrigin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getMouseUpEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool queryContentsScaleFactor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool queryCSSZoomFactorGetValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool queryCSSZoomFactorSetValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool echoString(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool startAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool stopAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getAudioMuted(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool nativeWidgetIsVisible(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getLastCompositionText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 
 static const NPUTF8* sPluginMethodIdentifierNames[] = {
@@ -235,16 +237,18 @@ static const NPUTF8* sPluginMethodIdenti
   "getWindowPosition",
   "constructObject",
   "setSitesWithData",
   "setSitesWithDataCapabilities",
   "getLastKeyText",
   "getNPNVdocumentOrigin",
   "getMouseUpEventCount",
   "queryContentsScaleFactor",
+  "queryCSSZoomFactorSetValue",
+  "queryCSSZoomFactorGetValue",
   "echoString",
   "startAudioPlayback",
   "stopAudioPlayback",
   "audioMuted",
   "nativeWidgetIsVisible",
   "getLastCompositionText",
 };
 static NPIdentifier sPluginMethodIdentifiers[MOZ_ARRAY_LENGTH(sPluginMethodIdentifierNames)];
@@ -308,16 +312,18 @@ static const ScriptableFunction sPluginM
   getWindowPosition,
   constructObject,
   setSitesWithData,
   setSitesWithDataCapabilities,
   getLastKeyText,
   getNPNVdocumentOrigin,
   getMouseUpEventCount,
   queryContentsScaleFactor,
+  queryCSSZoomFactorGetValue,
+  queryCSSZoomFactorSetValue,
   echoString,
   startAudioPlayback,
   stopAudioPlayback,
   getAudioMuted,
   nativeWidgetIsVisible,
   getLastCompositionText,
 };
 
@@ -850,16 +856,17 @@ NPP_New(NPMIMEType pluginType, NPP insta
   instanceData->closeStream = false;
   instanceData->wantsAllStreams = false;
   instanceData->mouseUpEventCount = 0;
   instanceData->bugMode = -1;
   instanceData->asyncDrawing = AD_NONE;
   instanceData->frontBuffer = nullptr;
   instanceData->backBuffer = nullptr;
   instanceData->placeholderWnd = nullptr;
+  instanceData->cssZoomFactor = 1.0;
   instance->pdata = instanceData;
 
   TestNPObject* scriptableObject = (TestNPObject*)NPN_CreateObject(instance, &sNPClass);
   if (!scriptableObject) {
     printf("NPN_CreateObject failed to create an object, can't create a plugin instance\n");
     delete instanceData;
     return NPERR_GENERIC_ERROR;
   }
@@ -1591,16 +1598,21 @@ NPP_SetValue(NPP instance, NPNVariable v
     instanceData->lastReportedPrivateModeState = bool(*static_cast<NPBool*>(value));
     return NPERR_NO_ERROR;
   }
   if (variable == NPNVmuteAudioBool) {
     InstanceData* instanceData = (InstanceData*)(instance->pdata);
     instanceData->audioMuted = bool(*static_cast<NPBool*>(value));
     return NPERR_NO_ERROR;
   }
+  if (variable == NPNVCSSZoomFactor) {
+    InstanceData* instanceData = (InstanceData*)(instance->pdata);
+    instanceData->cssZoomFactor = *static_cast<double*>(value);
+    return NPERR_NO_ERROR;
+  }
   return NPERR_GENERIC_ERROR;
 }
 
 void
 NPP_URLRedirectNotify(NPP instance, const char* url, int32_t status, void* notifyData)
 {
   if (notifyData) {
     URLNotifyData* nd = static_cast<URLNotifyData*>(notifyData);
@@ -3915,16 +3927,48 @@ bool queryContentsScaleFactor(NPObject* 
   if (err != NPERR_NO_ERROR) {
     return false;
   }
 #endif
   DOUBLE_TO_NPVARIANT(scaleFactor, *result);
   return true;
 }
 
+bool queryCSSZoomFactorSetValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+  if (argCount != 0)
+    return false;
+
+  NPP npp = static_cast<TestNPObject*>(npobj)->npp;
+  if (!npp) {
+    return false;
+  }
+  InstanceData* id = static_cast<InstanceData*>(npp->pdata);
+  if (!id) {
+    return false;
+  }
+  DOUBLE_TO_NPVARIANT(id->cssZoomFactor, *result);
+  return true;
+}
+
+bool queryCSSZoomFactorGetValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+  if (argCount != 0)
+    return false;
+
+  double zoomFactor = 1.0;
+  NPError err = NPN_GetValue(static_cast<TestNPObject*>(npobj)->npp,
+                             NPNVCSSZoomFactor, &zoomFactor);
+  if (err != NPERR_NO_ERROR) {
+    return false;
+  }
+  DOUBLE_TO_NPVARIANT(zoomFactor, *result);
+  return true;
+}
+
 bool echoString(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
 {
   if (argCount != 1) {
     return false;
   }
 
   if (!NPVARIANT_IS_STRING(args[0])) {
     return false;
--- a/dom/plugins/test/testplugin/nptest.h
+++ b/dom/plugins/test/testplugin/nptest.h
@@ -153,16 +153,17 @@ typedef struct InstanceData {
   int32_t mouseUpEventCount;
   int32_t bugMode;
   std::string javaCodebase;
   AsyncDrawing asyncDrawing;
   NPAsyncSurface *frontBuffer;
   NPAsyncSurface *backBuffer;
   std::string lastComposition;
   void* placeholderWnd;
+  double cssZoomFactor;
 } InstanceData;
 
 void notifyDidPaint(InstanceData* instanceData);
 
 #if defined(XP_WIN)
 bool setupDxgiSurfaces(NPP npp, InstanceData* instanceData);
 void drawDxgiBitmapColor(InstanceData* instanceData);
 #endif
--- a/dom/push/PushCrypto.jsm
+++ b/dom/push/PushCrypto.jsm
@@ -178,17 +178,17 @@ function generateNonce(base, index) {
     nonce[nonce.byteLength - 1 - i] ^= (index / Math.pow(256, i)) & 0xff;
   }
   return nonce;
 }
 
 this.PushCrypto = {
 
   generateAuthenticationSecret() {
-    return crypto.getRandomValues(new Uint8Array(12));
+    return crypto.getRandomValues(new Uint8Array(16));
   },
 
   generateKeys() {
     return crypto.subtle.generateKey(ECDH_KEY, true, ['deriveBits'])
       .then(cryptoKey =>
          Promise.all([
            crypto.subtle.exportKey('raw', cryptoKey.publicKey),
            crypto.subtle.exportKey('jwk', cryptoKey.privateKey)
--- a/dom/push/test/mochitest.ini
+++ b/dom/push/test/mochitest.ini
@@ -12,11 +12,10 @@ support-files =
 [test_permissions.html]
 [test_register.html]
 [test_multiple_register.html]
 [test_multiple_register_during_service_activation.html]
 [test_unregister.html]
 [test_multiple_register_different_scope.html]
 [test_subscription_change.html]
 [test_data.html]
-# Disabled for too many intermittent failures (bug 1164432)
-#  [test_try_registering_offline_disabled.html]
+[test_try_registering_offline_disabled.html]
 [test_serviceworker_lifetime.html]
--- a/dom/push/test/mockpushserviceparent.js
+++ b/dom/push/test/mockpushserviceparent.js
@@ -80,23 +80,27 @@ MockNetworkInfo.prototype = {
 var pushService = Cc["@mozilla.org/push/Service;1"].
                   getService(Ci.nsIPushService).
                   wrappedJSObject;
 
 var mockWebSocket;
 
 addMessageListener("setup", function () {
   mockWebSocket = new Promise((resolve, reject) => {
+    var mockSocket = null;
     pushService.replaceServiceBackend({
       serverURI: "wss://push.example.org/",
       networkInfo: new MockNetworkInfo(),
       makeWebSocket(uri) {
-        var socket = new MockWebSocketParent(uri);
-        resolve(socket);
-        return socket;
+        if (!mockSocket) {
+          mockSocket = new MockWebSocketParent(uri);
+          resolve(mockSocket);
+        }
+
+        return mockSocket;
       }
     });
   });
 });
 
 addMessageListener("teardown", function () {
   mockWebSocket.then(socket => {
     socket.close();
--- a/dom/push/test/test_data.html
+++ b/dom/push/test/test_data.html
@@ -98,24 +98,24 @@ http://creativecommons.org/licenses/publ
         "Mismatched Base64-encoded key: " + keyName
       );
     });
   });
 
   add_task(function* comparePublicKey() {
     var data = yield sendRequestToWorker({ type: "publicKey" });
     var p256dhKey = new Uint8Array(pushSubscription.getKey("p256dh"));
-    ok(p256dhKey.length > 0, "Missing key share");
+    is(p256dhKey.length, 65, "Key share should be 65 octets");
     isDeeply(
       p256dhKey,
       new Uint8Array(data.p256dh),
       "Mismatched key share"
     );
     var authSecret = new Uint8Array(pushSubscription.getKey("auth"));
-    ok(authSecret.length > 0, "Missing auth secret");
+    ok(authSecret.length, 16, "Auth secret should be 16 octets");
     isDeeply(
       authSecret,
       new Uint8Array(data.auth),
       "Mismatched auth secret"
     );
   });
 
   var version = 0;
--- a/dom/push/test/test_try_registering_offline_disabled.html
+++ b/dom/push/test/test_try_registering_offline_disabled.html
@@ -5,16 +5,17 @@ Bug 1150812: Try to register when servic
 
 Any copyright is dedicated to the Public Domain.
 http://creativecommons.org/licenses/publicdomain/
 
 -->
 <head>
   <title>Test for Bug 1150812</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/dom/push/test/test_utils.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
 </head>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1150812">Mozilla Bug 1150812</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
@@ -81,16 +82,27 @@ http://creativecommons.org/licenses/publ
         ok(subOld.endpoint == sub.endpoint, "getEndpoint - Got the same endpoint back.");
         return sub;
       }, err => {
           ok(false, "could not register for push notification");
           throw err;
       });
   }
 
+  // Load chrome script to change offline status in the
+  // parent process.
+  var chromeScript = SpecialPowers.loadChromeScript(_ => {
+    var { classes: Cc, interfaces: Ci } = Components;
+    var ioService = Cc["@mozilla.org/network/io-service;1"]
+                      .getService(Ci.nsIIOService);
+    addMessageListener("change-status", function(offline) {
+      ioService.offline = offline;
+    });
+  });
+
   function offlineObserver(res) {
     this._res = res;
   }
   offlineObserver.prototype = {
     _res: null,
 
     observe: function(subject, topic, data) {
       debug("observe: " + subject + " " + topic + " " + data);
@@ -105,26 +117,23 @@ http://creativecommons.org/licenses/publ
 
   function changeOfflineState(offline) {
     return new Promise(function(res, rej) {
       var obsService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
                          .getService(SpecialPowers.Ci.nsIObserverService);
       obsService.addObserver(SpecialPowers.wrapCallbackObject(new offlineObserver(res)),
                              "network:offline-status-changed",
                              false);
-      var ioService = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
-                        .getService(SpecialPowers.Ci.nsIIOService);
-      ioService.offline = offline;
+      chromeScript.sendAsyncMessage("change-status", offline);
     });
   }
 
   function changePushServerConnectionEnabled(enable) {
     debug("changePushServerConnectionEnabled");
-    SpecialPowers.pushPrefEnv({"set": [["dom.push.connection.enabled", enable]]},
-                              null);
+    SpecialPowers.setBoolPref("dom.push.connection.enabled", enable);
   }
 
   function unsubscribe(sub) {
     return sub.unsubscribe()
       .then(_ => {ok(true, "Unsubscribed!");});
   }
 
   // go offline then go online
@@ -282,20 +291,14 @@ http://creativecommons.org/licenses/publ
     .then(_ => runTest2())
     .then(_ => runTest3())
     .then(_ => runTest4())
     .then(_ => runTest5())
     .then(_ => runTest6())
     .then(SimpleTest.finish);
   }
 
-  SpecialPowers.pushPrefEnv({"set": [
-    ["dom.push.enabled", true],
-    ["dom.push.connection.enabled", true],
-    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
-    ["dom.serviceWorkers.enabled", true],
-    ["dom.serviceWorkers.testing.enabled", true]
-    ]}, runTest);
+  setupPrefsAndMock(new MockWebSocket()).then(_ => runTest());
   SpecialPowers.addPermission("desktop-notification", true, document);
   SimpleTest.waitForExplicitFinish();
 </script>
 </body>
 </html>
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -1129,18 +1129,17 @@ AudioManager::MaybeUpdateVolumeSettingTo
   }
 
   nsCOMPtr<nsISettingsServiceLock> lock = GetSettingServiceLock();
   if (NS_WARN_IF(!lock)) {
     return;
   }
 
   // Send events to update the Gaia volumes
-  mozilla::AutoSafeJSContext cx;
-  JS::Rooted<JS::Value> value(cx);
+  JS::Rooted<JS::Value> value(nsContentUtils::RootingCx());
   uint32_t volume = 0;
   for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) {
     int32_t streamType = gVolumeData[idx].mStreamType;
     VolumeStreamState* streamState = mStreamStates[streamType].get();
     if(!aForce && !streamState->IsDevicesChanged()) {
       continue;
     }
     // Get volume index of active device.
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -204,18 +204,18 @@ public:
     MOZ_ASSERT(NS_IsMainThread());
     nsCOMPtr<nsISettingsService> settingsService =
       do_GetService("@mozilla.org/settingsService;1");
     NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE);
     nsCOMPtr<nsISettingsServiceLock> lock;
     settingsService->CreateLock(nullptr, getter_AddRefs(lock));
     // lock may be null if this gets called during shutdown.
     if (lock) {
-      mozilla::AutoSafeJSContext cx;
-      JS::Rooted<JS::Value> value(cx, JS::Int32Value(mStatus));
+      JS::Rooted<JS::Value> value(nsContentUtils::RootingCx(),
+				  JS::Int32Value(mStatus));
       lock->Set(UMS_STATUS, value, nullptr, nullptr);
     }
     return NS_OK;
   }
 
 private:
   int32_t mStatus;
 };
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -73,25 +73,23 @@ SystemWorkerManager::Init()
 {
   if (!XRE_IsParentProcess()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   NS_ASSERTION(NS_IsMainThread(), "We can only initialize on the main thread");
   NS_ASSERTION(!mShutdown, "Already shutdown!");
 
-  mozilla::AutoSafeJSContext cx;
-
-  nsresult rv = InitWifi(cx);
+  nsresult rv = InitWifi();
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to initialize WiFi Networking!");
     return rv;
   }
 
-  InitKeyStore(cx);
+  InitKeyStore();
 
   InitAutoMounter();
   InitializeTimeZoneSettingObserver();
   nsCOMPtr<nsIAudioManager> audioManager =
     do_GetService(NS_AUDIOMANAGER_CONTRACTID);
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (!obs) {
@@ -200,27 +198,27 @@ SystemWorkerManager::RegisterRilWorker(u
     return NS_ERROR_FAILURE;
   }
 
   return RilWorker::Register(aClientId, wctd);
 #endif // MOZ_B2G_RIL
 }
 
 nsresult
-SystemWorkerManager::InitWifi(JSContext *cx)
+SystemWorkerManager::InitWifi()
 {
   nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kWifiWorkerCID);
   NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
 
   mWifiWorker = worker;
   return NS_OK;
 }
 
 nsresult
-SystemWorkerManager::InitKeyStore(JSContext *cx)
+SystemWorkerManager::InitKeyStore()
 {
   mKeyStore = new KeyStore();
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(SystemWorkerManager,
                   nsIObserver,
                   nsIInterfaceRequestor,
--- a/dom/system/gonk/SystemWorkerManager.h
+++ b/dom/system/gonk/SystemWorkerManager.h
@@ -54,18 +54,18 @@ public:
 
   static nsIInterfaceRequestor*
   GetInterfaceRequestor();
 
 private:
   SystemWorkerManager();
   ~SystemWorkerManager();
 
-  nsresult InitWifi(JSContext *cx);
-  nsresult InitKeyStore(JSContext *cx);
+  nsresult InitWifi();
+  nsresult InitKeyStore();
 
   nsCOMPtr<nsIWorkerHolder> mWifiWorker;
 
   RefPtr<mozilla::ipc::KeyStore> mKeyStore;
 
   bool mShutdown;
 };
 
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -4,17 +4,16 @@ support-files =
   page_privatestorageevent.html
   position.html
   test-console-api.html
   test_bug1004814.html
   worker_bug1004814.js
   geo_leak_test.html
 
 [browser_test_toolbars_visibility.js]
-skip-if = e10s
 support-files =
   test_new_window_from_content_child.html
 [browser_bug1008941_dismissGeolocationHanger.js]
 skip-if = buildapp == 'mulet'
 [browser_test__content.js]
 skip-if = e10s
 [browser_ConsoleAPITests.js]
 skip-if = e10s
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -160,13 +160,13 @@ skip-if = toolkit == 'android' #bug 7752
 [test_onerror_message.html]
 [test_protochains.html]
 [test_resize_move_windows.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size and position on Android # b2g(Windows can't change size and position on B2G) b2g-debug(Windows can't change size and position on B2G) b2g-desktop(Windows can't change size and position on B2G)
 [test_sizetocontent_clamp.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s #Windows can't change size on Android # b2g(Windows can't change size on B2G) b2g-debug(Windows can't change size on B2G) b2g-desktop(Windows can't change size on B2G)
 [test_toJSON.html]
 [test_window_bar.html]
-skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e10s
+skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
 [test_bug1022869.html]
 [test_bug1112040.html]
 [test_bug1160342_marquee.html]
 [test_bug1171215.html]
--- a/dom/tests/mochitest/bugs/test_window_bar.html
+++ b/dom/tests/mochitest/bugs/test_window_bar.html
@@ -43,33 +43,34 @@ function testWindow(w)
     if (prefname === undefined)
       prefname = feature;
 
     if (SpecialPowers.getBoolPref('dom.disable_window_open_feature.' + prefname)) {
       is(w[feature].visible, true, feature + ' should always be true.');
     }
     else {
       // w.location.search == '?true' if we expect the bars to be on, and
-      // '?false' otherwise.
+      // '?false' otherwise.  By default, no bars are enabled, so '?default'
+      // can be handled the same way as '?false'.
       var enabled = w.location.search == '?true';
       is(w[feature].visible, enabled, feature + ' should follow window.open settings.');
     }
   }
 
   checkFeature('menubar');
   checkFeature('toolbar');
   checkFeature('personalbar');
   checkFeature('scrollbars');
   checkFeature('statusbar', 'status');
   checkFeature('locationbar', 'location');
 
   w.close();
 
   numWindows++;
-  if (numWindows == 2) {
+  if (numWindows == 3) {
     // We're done!
     SimpleTest.finish();
   }
 
 }
 
 SimpleTest.waitForExplicitFinish();
 
@@ -82,12 +83,16 @@ var allBarsWindow =
               true);
 
 var noBarsWindow =
   window.open('file_window_bar.html?false', 'no-bars',
               'menubar=no,toolbar=no,location=no,' +
               'personalbar=no,status=no,scrollbars=no',
               false);
 
+var defaultWindow =
+  window.open('file_window_bar.html?default', 'default-bars',
+              'width=500,height=500', false);
+
 </script>
 </pre>
 </body>
 </html>
--- a/dom/time/DateCacheCleaner.cpp
+++ b/dom/time/DateCacheCleaner.cpp
@@ -27,17 +27,16 @@ public:
   }
 
   ~DateCacheCleaner()
   {
     UnregisterSystemTimezoneChangeObserver(this);
   }
   void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
   {
-    mozilla::AutoSafeJSContext cx;
     JS::ResetTimeZone();
   }
 
 };
 
 StaticAutoPtr<DateCacheCleaner> sDateCacheCleaner;
 
 void
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -7,16 +7,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
  * http://www.w3.org/TR/tracking-dnt/
  * http://www.w3.org/TR/geolocation-API/#geolocation_interface
  * http://www.w3.org/TR/battery-status/#navigatorbattery-interface
  * http://www.w3.org/TR/vibration/#vibration-interface
  * http://www.w3.org/2012/sysapps/runtime/#extension-to-the-navigator-interface-1
  * https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension
  * http://www.w3.org/TR/beacon/#sec-beacon-method
+ * https://html.spec.whatwg.org/#navigatorconcurrenthardware
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  * Opera Software ASA. You are granted a license to use, reproduce
  * and create derivative works of this document.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-navigator-object
 [HeaderFile="Navigator.h", NeedResolve]
@@ -24,29 +25,30 @@ interface Navigator {
   // objects implementing this interface also implement the interfaces given below
 };
 Navigator implements NavigatorID;
 Navigator implements NavigatorLanguage;
 Navigator implements NavigatorOnLine;
 Navigator implements NavigatorContentUtils;
 Navigator implements NavigatorStorageUtils;
 Navigator implements NavigatorFeatures;
+Navigator implements NavigatorConcurrentHardware;
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface NavigatorID {
   // WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla").
   [Constant, Cached]
   readonly attribute DOMString appCodeName; // constant "Mozilla"
   [Constant, Cached]
   readonly attribute DOMString appName;
   [Constant, Cached]
   readonly attribute DOMString appVersion;
   [Constant, Cached]
   readonly attribute DOMString platform;
-  [Pure, Cached, Throws=Workers]
+  [Pure, Cached, Throws]
   readonly attribute DOMString userAgent;
   [Constant, Cached]
   readonly attribute DOMString product; // constant "Gecko"
 
   // Everyone but WebKit/Blink supports this.  See bug 679971.
   [Exposed=Window]
   boolean taintEnabled(); // constant false
 };
@@ -471,8 +473,13 @@ partial interface Navigator {
   [Throws, NewObject, Pref="dom.mozPay.enabled"]
   // The 'jwts' parameter can be either a single DOMString or an array of
   // DOMStrings. In both cases, it represents the base64url encoded and
   // digitally signed payment information. Each payment provider should
   // define its supported JWT format.
   DOMRequest mozPay(any jwts);
 };
 #endif
+
+[NoInterfaceObject, Exposed=(Window,Worker)]
+interface NavigatorConcurrentHardware {
+  readonly attribute unsigned long long hardwareConcurrency;
+};
--- a/dom/webidl/WorkerDebuggerGlobalScope.webidl
+++ b/dom/webidl/WorkerDebuggerGlobalScope.webidl
@@ -1,15 +1,16 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 [Global=(WorkerDebugger), Exposed=WorkerDebugger]
 interface WorkerDebuggerGlobalScope : EventTarget {
+  [Throws]
   readonly attribute object global;
 
   object createSandbox(DOMString name, object prototype);
 
   [Throws]
   void loadSubScript(DOMString url, optional object sandbox);
 
   void enterEventLoop();
--- a/dom/webidl/WorkerNavigator.webidl
+++ b/dom/webidl/WorkerNavigator.webidl
@@ -6,8 +6,9 @@
 [Exposed=Worker]
 interface WorkerNavigator {
 };
 
 WorkerNavigator implements NavigatorID;
 WorkerNavigator implements NavigatorLanguage;
 WorkerNavigator implements NavigatorOnLine;
 WorkerNavigator implements NavigatorDataStore;
+WorkerNavigator implements NavigatorConcurrentHardware;
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -21,16 +21,17 @@
 #include "nsIURI.h"
 #include "nsPIDOMWindow.h"
 
 #include <algorithm>
 #include "BackgroundChild.h"
 #include "GeckoProfiler.h"
 #include "jsfriendapi.h"
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/AtomList.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ErrorEventBinding.h"
 #include "mozilla/dom/EventTargetBinding.h"
@@ -63,16 +64,17 @@
 
 #include "Principal.h"
 #include "SharedWorker.h"
 #include "WorkerDebuggerManager.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 #include "WorkerThread.h"
+#include "prsystem.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::MutexAutoLock;
@@ -2444,16 +2446,38 @@ RuntimeService::CycleCollectAllWorkers()
 }
 
 void
 RuntimeService::SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline)
 {
   BROADCAST_ALL_WORKERS(OfflineStatusChangeEvent, aIsOffline);
 }
 
+uint32_t
+RuntimeService::ClampedHardwareConcurrency() const
+{
+  // This needs to be atomic, because multiple workers, and even mainthread,
+  // could race to initialize it at once.
+  static Atomic<uint32_t> clampedHardwareConcurrency;
+
+  // No need to loop here: if compareExchange fails, that just means that some
+  // other worker has initialized numberOfProcessors, so we're good to go.
+  if (!clampedHardwareConcurrency) {
+    int32_t numberOfProcessors = PR_GetNumberOfProcessors();
+    if (numberOfProcessors <= 0) {
+      numberOfProcessors = 1; // Must be one there somewhere
+    }
+    uint32_t clampedValue = std::min(uint32_t(numberOfProcessors),
+                                     gMaxWorkersPerDomain);
+    clampedHardwareConcurrency.compareExchange(0, clampedValue);
+  }
+
+  return clampedHardwareConcurrency;
+}
+
 // nsISupports
 NS_IMPL_ISUPPORTS(RuntimeService, nsIObserver)
 
 // nsIObserver
 NS_IMETHODIMP
 RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
                         const char16_t* aData)
 {
--- a/dom/workers/RuntimeService.h
+++ b/dom/workers/RuntimeService.h
@@ -244,16 +244,18 @@ public:
   GarbageCollectAllWorkers(bool aShrinking);
 
   void
   CycleCollectAllWorkers();
 
   void
   SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline);
 
+  uint32_t ClampedHardwareConcurrency() const;
+
 private:
   RuntimeService();
   ~RuntimeService();
 
   nsresult
   Init();
 
   void
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -51,16 +51,57 @@
 #include "js/Conversions.h"
 #include "js/TypeDecls.h"
 #include "WorkerPrivate.h"
 #include "xpcpublic.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::workers;
 
+namespace {
+
+void
+AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
+         const nsACString& aRespondWithScriptSpec,
+         uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
+         const nsACString& aMessageName, const nsTArray<nsString>& aParams)
+{
+  MOZ_ASSERT(aInterceptedChannel);
+  nsCOMPtr<nsIConsoleReportCollector> reporter =
+    aInterceptedChannel->GetConsoleReportCollector();
+  if (reporter) {
+    reporter->AddConsoleReport(nsIScriptError::errorFlag,
+                               NS_LITERAL_CSTRING("Service Worker Interception"),
+                               nsContentUtils::eDOM_PROPERTIES,
+                               aRespondWithScriptSpec,
+                               aRespondWithLineNumber,
+                               aRespondWithColumnNumber,
+                               aMessageName, aParams);
+  }
+}
+
+template<typename... Params>
+void
+AsyncLog(nsIInterceptedChannel* aInterceptedChannel,
+         const nsACString& aRespondWithScriptSpec,
+         uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
+         // We have to list one explicit string so that calls with an
+         // nsTArray of params won't end up in here.
+         const nsACString& aMessageName, const nsAString& aFirstParam,
+         Params&&... aParams)
+{
+  nsTArray<nsString> paramsList(sizeof...(Params) + 1);
+  StringArrayAppender::Append(paramsList, sizeof...(Params) + 1,
+                              aFirstParam, Forward<Params>(aParams)...);
+  AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber,
+           aRespondWithColumnNumber, aMessageName, paramsList);
+}
+
+} // anonymous namespace
+
 BEGIN_WORKERS_NAMESPACE
 
 CancelChannelRunnable::CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
                                              nsresult aStatus)
   : mChannel(aChannel)
   , mStatus(aStatus)
 {
 }
@@ -110,53 +151,16 @@ FetchEvent::Constructor(const GlobalObje
   e->mRequest = aOptions.mRequest;
   e->mClientId = aOptions.mClientId;
   e->mIsReload = aOptions.mIsReload;
   return e.forget();
 }
 
 namespace {
 
-void
-AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
-         const nsACString& aRespondWithScriptSpec,
-         uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
-         const nsACString& aMessageName, const nsTArray<nsString>& aParams)
-{
-  MOZ_ASSERT(aInterceptedChannel);
-  nsCOMPtr<nsIConsoleReportCollector> reporter =
-    aInterceptedChannel->GetConsoleReportCollector();
-  if (reporter) {
-    reporter->AddConsoleReport(nsIScriptError::errorFlag,
-                               NS_LITERAL_CSTRING("Service Worker Interception"),
-                               nsContentUtils::eDOM_PROPERTIES,
-                               aRespondWithScriptSpec,
-                               aRespondWithLineNumber,
-                               aRespondWithColumnNumber,
-                               aMessageName, aParams);
-  }
-}
-
-template<typename... Params>
-void
-AsyncLog(nsIInterceptedChannel* aInterceptedChannel,
-         const nsACString& aRespondWithScriptSpec,
-         uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
-         // We have to list one explicit string so that calls with an
-         // nsTArray of params won't end up in here.
-         const nsACString& aMessageName, const nsAString& aFirstParam,
-         Params&&... aParams)
-{
-  nsTArray<nsString> paramsList(sizeof...(Params) + 1);
-  StringArrayAppender::Append(paramsList, sizeof...(Params) + 1,
-                              aFirstParam, Forward<Params>(aParams)...);
-  AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber,
-           aRespondWithColumnNumber, aMessageName, paramsList);
-}
-
 class FinishResponse final : public nsRunnable
 {
   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
   RefPtr<InternalResponse> mInternalResponse;
   ChannelInfo mWorkerChannelInfo;
   const nsCString mScriptSpec;
   const nsCString mResponseURLSpec;
 
rename from dom/workers/Navigator.cpp
rename to dom/workers/WorkerNavigator.cpp
--- a/dom/workers/Navigator.cpp
+++ b/dom/workers/WorkerNavigator.cpp
@@ -6,29 +6,30 @@
 
 #include "DataStore.h"
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DataStore.h"
 #include "mozilla/dom/DataStoreBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
+#include "mozilla/dom/WorkerNavigator.h"
 #include "mozilla/dom/WorkerNavigatorBinding.h"
 
-#include "Navigator.h"
 #include "nsProxyRelease.h"
 #include "RuntimeService.h"
 
 #include "nsIDocument.h"
 
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "WorkerScope.h"
 
-BEGIN_WORKERS_NAMESPACE
+namespace mozilla {
+namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerNavigator)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
 
 /* static */ already_AddRefed<WorkerNavigator>
 WorkerNavigator::Create(bool aOnLine)
@@ -43,17 +44,17 @@ WorkerNavigator::Create(bool aOnLine)
     new WorkerNavigator(properties, aOnLine);
 
   return navigator.forget();
 }
 
 JSObject*
 WorkerNavigator::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
-  return WorkerNavigatorBinding_workers::Wrap(aCx, this, aGivenProto);
+  return WorkerNavigatorBinding::Wrap(aCx, this, aGivenProto);
 }
 
 // A WorkerMainThreadRunnable to synchronously add DataStoreChangeEventProxy on
 // the main thread. We need this because we have to access |mBackingStore| on
 // the main thread.
 class DataStoreAddEventListenerRunnable : public WorkerMainThreadRunnable
 {
   nsMainThreadPtrHandle<DataStore> mBackingStore;
@@ -295,17 +296,17 @@ WorkerNavigator::GetDataStores(JSContext
   }
 
   return promise.forget();
 }
 
 void
 WorkerNavigator::SetLanguages(const nsTArray<nsString>& aLanguages)
 {
-  WorkerNavigatorBinding_workers::ClearCachedLanguagesValue(this);
+  WorkerNavigatorBinding::ClearCachedLanguagesValue(this);
   mProperties.mLanguages = aLanguages;
 }
 
 void
 WorkerNavigator::GetAppName(nsString& aAppName) const
 {
   WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
@@ -394,9 +395,19 @@ WorkerNavigator::GetUserAgent(nsString& 
   MOZ_ASSERT(workerPrivate);
 
   RefPtr<GetUserAgentRunnable> runnable =
     new GetUserAgentRunnable(workerPrivate, aUserAgent);
 
   runnable->Dispatch(aRv);
 }
 
-END_WORKERS_NAMESPACE
+uint64_t
+WorkerNavigator::HardwareConcurrency() const
+{
+  RuntimeService* rts = RuntimeService::GetService();
+  MOZ_ASSERT(rts);
+
+  return rts->ClampedHardwareConcurrency();
+}
+
+} // namespace dom
+} // namespace mozilla
rename from dom/workers/Navigator.h
rename to dom/workers/WorkerNavigator.h
--- a/dom/workers/Navigator.h
+++ b/dom/workers/WorkerNavigator.h
@@ -1,37 +1,33 @@
 /* -*- 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/. */
 
-#ifndef mozilla_dom_workers_navigator_h__
-#define mozilla_dom_workers_navigator_h__
+#ifndef mozilla_dom_workernavigator_h__
+#define mozilla_dom_workernavigator_h__
 
 #include "Workers.h"
 #include "RuntimeService.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 
 // Need this to use Navigator::HasDataStoreSupport() in
 // WorkerNavigatorBinding.cpp
 #include "mozilla/dom/Navigator.h"
 
 namespace mozilla {
 namespace dom {
 class Promise;
-} // namespace dom
-} // namespace mozilla
-
-BEGIN_WORKERS_NAMESPACE
 
 class WorkerNavigator final : public nsWrapperCache
 {
-  typedef struct RuntimeService::NavigatorProperties NavigatorProperties;
+  typedef struct workers::RuntimeService::NavigatorProperties NavigatorProperties;
 
   NavigatorProperties mProperties;
   bool mOnline;
 
   WorkerNavigator(const NavigatorProperties& aProperties,
                   bool aOnline)
     : mProperties(aProperties)
     , mOnline(aOnline)
@@ -107,13 +103,16 @@ public:
   }
 
   void SetLanguages(const nsTArray<nsString>& aLanguages);
 
   already_AddRefed<Promise> GetDataStores(JSContext* aCx,
                                           const nsAString& aName,
                                           const nsAString& aOwner,
                                           ErrorResult& aRv);
+
+  uint64_t HardwareConcurrency() const;
 };
 
-END_WORKERS_NAMESPACE
+} // namespace dom
+} // namespace mozilla
 
-#endif // mozilla_dom_workers_navigator_h__
+#endif // mozilla_dom_workernavigator_h__
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -17,28 +17,28 @@
 #include "mozilla/dom/ImageBitmap.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseWorkerProxy.h"
 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
 #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerGlobalScopeBinding.h"
 #include "mozilla/dom/WorkerLocation.h"
+#include "mozilla/dom/WorkerNavigator.h"
 #include "mozilla/dom/cache/CacheStorage.h"
 #include "mozilla/Services.h"
 #include "nsServiceManagerUtils.h"
 
 #include "nsIDocument.h"
 #include "nsIServiceWorkerManager.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
 
-#include "Navigator.h"
 #include "Principal.h"
 #include "RuntimeService.h"
 #include "ScriptLoader.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
 #include "Performance.h"
 #include "ServiceWorkerClients.h"
 #include "ServiceWorkerManager.h"
@@ -691,19 +691,25 @@ WorkerDebuggerGlobalScope::WrapGlobalObj
 
   return WorkerDebuggerGlobalScopeBinding::Wrap(aCx, this, this, options,
                                                 GetWorkerPrincipal(), true,
                                                 aReflector);
 }
 
 void
 WorkerDebuggerGlobalScope::GetGlobal(JSContext* aCx,
-                                     JS::MutableHandle<JSObject*> aGlobal)
+                                     JS::MutableHandle<JSObject*> aGlobal,
+                                     ErrorResult& aRv)
 {
-  aGlobal.set(mWorkerPrivate->GetOrCreateGlobalScope(aCx)->GetWrapper());
+  WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
+  if (!scope) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+
+  aGlobal.set(scope->GetWrapper());
 }
 
 class WorkerDebuggerSandboxPrivate : public nsIGlobalObject,
                                      public nsWrapperCache
 {
 public:
   explicit WorkerDebuggerSandboxPrivate(JSObject *global)
   {
@@ -926,17 +932,20 @@ WorkerDebuggerGlobalScope::GetConsole(Er
 
   return mConsole;
 }
 
 void
 WorkerDebuggerGlobalScope::Dump(JSContext* aCx,
                                 const Optional<nsAString>& aString) const
 {
-  return mWorkerPrivate->GetOrCreateGlobalScope(aCx)->Dump(aString);
+  WorkerGlobalScope* scope = mWorkerPrivate->GetOrCreateGlobalScope(aCx);
+  if (scope) {
+    scope->Dump(aString);
+  }
 }
 
 nsIGlobalObject*
 GetGlobalObjectForGlobal(JSObject* global)
 {
   nsIGlobalObject* globalObject = nullptr;
   UNWRAP_WORKER_OBJECT(WorkerGlobalScope, global, globalObject);
 
--- a/dom/workers/WorkerScope.h
+++ b/dom/workers/WorkerScope.h
@@ -19,30 +19,30 @@ namespace dom {
 
 class Console;
 class Function;
 class IDBFactory;
 class Promise;
 class RequestOrUSVString;
 class ServiceWorkerRegistrationWorkerThread;
 class WorkerLocation;
+class WorkerNavigator;
 
 namespace cache {
 
 class CacheStorage;
 
 } // namespace cache
 } // namespace dom
 } // namespace mozilla
 
 BEGIN_WORKERS_NAMESPACE
 
 class ServiceWorkerClients;
 class WorkerPrivate;
-class WorkerNavigator;
 class Performance;
 
 class WorkerGlobalScope : public DOMEventTargetHelper,
                           public nsIGlobalObject,
                           public nsSupportsWeakReference
 {
   typedef mozilla::dom::IDBFactory IDBFactory;
 
@@ -292,17 +292,18 @@ public:
 
   virtual JSObject*
   GetGlobalJSObject(void) override
   {
     return GetWrapper();
   }
 
   void
-  GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal);
+  GetGlobal(JSContext* aCx, JS::MutableHandle<JSObject*> aGlobal,
+            ErrorResult& aRv);
 
   void
   CreateSandbox(JSContext* aCx, const nsAString& aName,
                 JS::Handle<JSObject*> aPrototype,
                 JS::MutableHandle<JSObject*> aResult);
 
   void
   LoadSubScript(JSContext* aCx, const nsAString& aURL,
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -9,33 +9,34 @@ EXPORTS.mozilla.dom += [
     'FileReaderSync.h',
     'ServiceWorkerCommon.h',
     'ServiceWorkerContainer.h',
     'ServiceWorkerEvents.h',
     'ServiceWorkerMessageEvent.h',
     'ServiceWorkerRegistrar.h',
     'ServiceWorkerRegistration.h',
     'WorkerLocation.h',
+    'WorkerNavigator.h',
     'WorkerPrefs.h',
     'WorkerPrivate.h',
     'WorkerRunnable.h',
     'WorkerScope.h',
 ]
 
 EXPORTS.mozilla.dom.workers += [
+    'RuntimeService.h',
     'ServiceWorkerManager.h',
     'WorkerDebuggerManager.h',
     'Workers.h',
 ]
 
 # Stuff needed for the bindings, not really public though.
 EXPORTS.mozilla.dom.workers.bindings += [
     'DataStore.h',
     'DataStoreCursor.h',
-    'Navigator.h',
     'Performance.h',
     'ServiceWorker.h',
     'ServiceWorkerClient.h',
     'ServiceWorkerClients.h',
     'ServiceWorkerWindowClient.h',
     'SharedWorker.h',
     'URL.h',
     'WorkerFeature.h',
@@ -50,17 +51,16 @@ XPIDL_SOURCES += [
     'nsIWorkerDebuggerManager.idl',
 ]
 
 UNIFIED_SOURCES += [
     'ChromeWorkerScope.cpp',
     'DataStore.cpp',
     'DataStoreCursor.cpp',
     'FileReaderSync.cpp',
-    'Navigator.cpp',
     'Performance.cpp',
     'Principal.cpp',
     'RegisterBindings.cpp',
     'RuntimeService.cpp',
     'ScriptLoader.cpp',
     'ServiceWorker.cpp',
     'ServiceWorkerClient.cpp',
     'ServiceWorkerClients.cpp',
@@ -75,16 +75,17 @@ UNIFIED_SOURCES += [
     'ServiceWorkerRegistrar.cpp',
     'ServiceWorkerRegistration.cpp',
     'ServiceWorkerScriptCache.cpp',
     'ServiceWorkerWindowClient.cpp',
     'SharedWorker.cpp',
     'URL.cpp',
     'WorkerDebuggerManager.cpp',
     'WorkerLocation.cpp',
+    'WorkerNavigator.cpp',
     'WorkerPrivate.cpp',
     'WorkerRunnable.cpp',
     'WorkerScope.cpp',
     'WorkerThread.cpp',
     'XMLHttpRequest.cpp',
     'XMLHttpRequestUpload.cpp',
 ]
 
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -253,8 +253,9 @@ skip-if = buildapp == 'b2g'
 [test_xhr_timeout.html]
 skip-if = (os == "win") || (os == "mac") || toolkit == 'android' #bug 798220
 [test_xhrAbort.html]
 [test_referrer.html]
 [test_importScripts_3rdparty.html]
 [test_sharedWorker_ports.html]
 [test_sharedWorker_lifetime.html]
 [test_fileReader.html]
+[test_navigator_workers_hardwareConcurrency.html]
--- a/dom/workers/test/navigator_worker.js
+++ b/dom/workers/test/navigator_worker.js
@@ -10,16 +10,17 @@ var supportedProps = [
   "appVersion",
   { name: "getDataStores", b2g: true },
   "platform",
   "product",
   "userAgent",
   "onLine",
   "language",
   "languages",
+  "hardwareConcurrency",
 ];
 
 self.onmessage = function(event) {
   if (!event || !event.data) {
     return;
   }
 
   startTest(event.data.isB2G);
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_navigator_workers_hardwareConcurrency.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for Navigator.hardwareConcurrency</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  SimpleTest.waitForExplicitFinish();
+  var script = "postMessage(navigator.hardwareConcurrency)";
+  var url = URL.createObjectURL(new Blob([script]));
+  var w = new Worker(url);
+  w.onmessage = function(e) {
+    var x = e.data;
+    is(typeof x, "number", "hardwareConcurrency should be a number.");
+    ok(x > 0, "hardwareConcurrency should be greater than 0.");
+    SimpleTest.finish();
+  }
+  </script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -876,19 +876,22 @@ nsXBLPrototypeBinding::Read(nsIObjectInp
 
   for (; interfaceCount > 0; interfaceCount--) {
     nsIID iid;
     rv = aStream->ReadID(&iid);
     NS_ENSURE_SUCCESS(rv, rv);
     mInterfaceTable.Put(iid, mBinding);
   }
 
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> compilationGlobal(cx, xpc::CompilationScope());
-  JSAutoCompartment ac(cx, compilationGlobal);
+  // We're not directly using this AutoJSAPI here, but callees use it via
+  // AutoJSContext.
+  AutoJSAPI jsapi;
+  if (!jsapi.Init(xpc::CompilationScope())) {
+    return NS_ERROR_UNEXPECTED;
+  }
 
   bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding;
   rv = Init(id, aDocInfo, nullptr, isFirstBinding);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We need to set the prototype binding before reading the nsXBLProtoImpl,
   // as it may be retrieved within.
   rv = aDocInfo->SetPrototypeBinding(id, this);
@@ -1019,19 +1022,22 @@ nsXBLPrototypeBinding::ReadNewBinding(ns
 
 nsresult
 nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream)
 {
   // This writes out the binding. Note that mCheckedBaseProto,
   // mKeyHandlersRegistered and mKeyHandlers are not serialized as they are
   // computed on demand.
 
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> compilationGlobal(cx, xpc::CompilationScope());
-  JSAutoCompartment ac(cx, compilationGlobal);
+  // We're not directly using this AutoJSAPI here, but callees use it via
+  // AutoJSContext.
+  AutoJSAPI jsapi;
+  if (!jsapi.Init(xpc::CompilationScope())) {
+    return NS_ERROR_UNEXPECTED;
+  }
 
   uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0;
 
   // mAlternateBindingURI is only set on the first binding.
   if (mAlternateBindingURI) {
     flags |= XBLBinding_Serialize_IsFirstBinding;
   }
 
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -2521,20 +2521,21 @@ nsXULPrototypeScript::~nsXULPrototypeScr
 }
 
 nsresult
 nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
                                 nsXULPrototypeDocument* aProtoDoc,
                                 const nsTArray<RefPtr<mozilla::dom::NodeInfo>> *aNodeInfos)
 {
     NS_ENSURE_TRUE(aProtoDoc, NS_ERROR_UNEXPECTED);
-    AutoSafeJSContext cx;
-    JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
-    NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
-    JSAutoCompartment ac(cx, global);
+
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+        return NS_ERROR_UNEXPECTED;
+    }
 
     NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr ||
                  !mScriptObject,
                  "script source still loading when serializing?!");
     if (!mScriptObject)
         return NS_ERROR_FAILURE;
 
     // Write basic prototype data
@@ -2544,16 +2545,17 @@ nsXULPrototypeScript::Serialize(nsIObjec
     rv = aStream->Write32(mLangVersion);
     if (NS_FAILED(rv)) return rv;
 
     // Calling fromMarkedLocation() is safe because we trace mScriptObject in
     // TraceScriptObject() and because its value is never changed after it has
     // been set.
     JS::Handle<JSScript*> script =
         JS::Handle<JSScript*>::fromMarkedLocation(mScriptObject.address());
+    JSContext* cx = jsapi.cx();
     MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
     return nsContentUtils::XPConnect()->WriteScript(aStream, cx,
                                                     xpc_UnmarkGrayScript(script));
 }
 
 nsresult
 nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
                                          nsXULPrototypeDocument* aProtoDoc)
@@ -2613,20 +2615,21 @@ nsXULPrototypeScript::Deserialize(nsIObj
                  "prototype script not well-initialized when deserializing?!");
 
     // Read basic prototype data
     rv = aStream->Read32(&mLineNo);
     if (NS_FAILED(rv)) return rv;
     rv = aStream->Read32(&mLangVersion);
     if (NS_FAILED(rv)) return rv;
 
-    AutoSafeJSContext cx;
-    JS::Rooted<JSObject*> global(cx, xpc::CompilationScope());
-    NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
-    JSAutoCompartment ac(cx, global);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+        return NS_ERROR_UNEXPECTED;
+    }
+    JSContext* cx = jsapi.cx();
 
     JS::Rooted<JSScript*> newScriptObject(cx);
     rv = nsContentUtils::XPConnect()->ReadScript(aStream, cx,
                                                  newScriptObject.address());
     NS_ENSURE_SUCCESS(rv, rv);
     Set(newScriptObject);
     return NS_OK;
 }
@@ -2741,23 +2744,25 @@ public:
 StaticAutoPtr<nsTArray<nsCOMPtr<nsIOffThreadScriptReceiver>>> NotifyOffThreadScriptCompletedRunnable::sReceivers;
 bool NotifyOffThreadScriptCompletedRunnable::sSetupClearOnShutdown = false;
 
 NS_IMETHODIMP
 NotifyOffThreadScriptCompletedRunnable::Run()
 {
     MOZ_ASSERT(NS_IsMainThread());
 
-    // Note: this unroots mScript so that it is available to be collected by the
-    // JS GC. The receiver needs to root the script before performing a call that
-    // could GC.
-    JSScript *script;
+    JS::Rooted<JSScript*> script(nsContentUtils::RootingCx());
     {
-        AutoSafeJSContext cx;
-        JSAutoCompartment ac(cx, xpc::CompilationScope());
+        AutoJSAPI jsapi;
+        if (!jsapi.Init(xpc::CompilationScope())) {
+            // Now what?  I guess we just leak... this should probably never
+            // happen.
+            return NS_ERROR_UNEXPECTED;
+        }
+        JSContext* cx = jsapi.cx();
         script = JS::FinishOffThreadScript(cx, JS_GetRuntime(cx), mToken);
     }
 
     if (!sReceivers) {
         // We've already shut down.
         return NS_OK;
     }
 
@@ -2782,18 +2787,21 @@ OffThreadScriptReceiverCallback(void *aT
 
 nsresult
 nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf,
                               nsIURI* aURI, uint32_t aLineNo,
                               nsIDocument* aDocument,
                               nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */)
 {
     // We'll compile the script in the compilation scope.
-    AutoSafeJSContext cx;
-    JSAutoCompartment ac(cx, xpc::CompilationScope());
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(xpc::CompilationScope())) {
+        return NS_ERROR_UNEXPECTED;
+    }
+    JSContext* cx = jsapi.cx();
 
     nsAutoCString urlspec;
     nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec);
 
     // Ok, compile it to create a prototype script object!
     NS_ENSURE_TRUE(JSVersion(mLangVersion) != JSVERSION_UNKNOWN, NS_OK);
     JS::CompileOptions options(cx);
     options.setIntroductionType("scriptElement")
--- a/embedding/components/printingui/ipc/nsPrintingProxy.cpp
+++ b/embedding/components/printingui/ipc/nsPrintingProxy.cpp
@@ -68,33 +68,30 @@ NS_IMETHODIMP
 nsPrintingProxy::ShowPrintDialog(mozIDOMWindowProxy *parent,
                                  nsIWebBrowserPrint *webBrowserPrint,
                                  nsIPrintSettings *printSettings)
 {
   NS_ENSURE_ARG(parent);
   NS_ENSURE_ARG(webBrowserPrint);
   NS_ENSURE_ARG(printSettings);
 
-  // Get the root docshell owner of this nsIDOMWindow, which
-  // should map to a TabChild, which we can then pass up to
+  // Get the TabChild for this nsIDOMWindow, which we can then pass up to
   // the parent.
   nsCOMPtr<nsPIDOMWindowOuter> pwin = nsPIDOMWindowOuter::From(parent);
   NS_ENSURE_STATE(pwin);
   nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
   NS_ENSURE_STATE(docShell);
-  nsCOMPtr<nsIDocShellTreeOwner> owner;
-  nsresult rv = docShell->GetTreeOwner(getter_AddRefs(owner));
-  NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsITabChild> tabchild = do_GetInterface(owner);
+  nsCOMPtr<nsITabChild> tabchild = docShell->GetTabChild();
   NS_ENSURE_STATE(tabchild);
 
   TabChild* pBrowser = static_cast<TabChild*>(tabchild.get());
 
   // Next, serialize the nsIWebBrowserPrint and nsIPrintSettings we were given.
+  nsresult rv = NS_OK;
   nsCOMPtr<nsIPrintOptions> po =
     do_GetService("@mozilla.org/gfx/printsettings-service;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PrintData inSettings;
   rv = po->SerializeToPrintData(printSettings, webBrowserPrint, &inSettings);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -129,34 +126,31 @@ nsPrintingProxy::ShowProgress(mozIDOMWin
                               nsIPrintProgressParams** printProgressParams,
                               bool*                  notifyOnOpen)
 {
   NS_ENSURE_ARG(parent);
   NS_ENSURE_ARG(webProgressListener);
   NS_ENSURE_ARG(printProgressParams);
   NS_ENSURE_ARG(notifyOnOpen);
 
-  // Get the root docshell owner of this nsIDOMWindow, which
-  // should map to a TabChild, which we can then pass up to
+  // Get the TabChild for this nsIDOMWindow, which we can then pass up to
   // the parent.
   nsCOMPtr<nsPIDOMWindowOuter> pwin = nsPIDOMWindowOuter::From(parent);
   NS_ENSURE_STATE(pwin);
   nsCOMPtr<nsIDocShell> docShell = pwin->GetDocShell();
   NS_ENSURE_STATE(docShell);
-  nsCOMPtr<nsIDocShellTreeOwner> owner;
-  nsresult rv = docShell->GetTreeOwner(getter_AddRefs(owner));
-  NS_ENSURE_SUCCESS(rv, rv);
-  nsCOMPtr<nsITabChild> tabchild = do_GetInterface(owner);
+  nsCOMPtr<nsITabChild> tabchild = docShell->GetTabChild();
   TabChild* pBrowser = static_cast<TabChild*>(tabchild.get());
 
   RefPtr<PrintProgressDialogChild> dialogChild =
     new PrintProgressDialogChild(openDialogObserver);
 
   SendPPrintProgressDialogConstructor(dialogChild);
 
+  nsresult rv = NS_OK;
   mozilla::Unused << SendShowProgress(pBrowser, dialogChild,
                                       isForPrinting, notifyOnOpen, &rv);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   NS_ADDREF(*webProgressListener = dialogChild);
   NS_ADDREF(*printProgressParams = dialogChild);
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -16,16 +16,17 @@
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsJSPrincipals.h"
 #include "nsIScriptError.h"
 #include "jswrapper.h"
 
 extern mozilla::LazyLogModule MCD;
 using mozilla::AutoSafeJSContext;
+using mozilla::dom::AutoJSAPI;
 
 //*****************************************************************************
 
 static JS::PersistentRooted<JSObject *> autoconfigSb;
 
 nsresult CentralizedAdminPrefManagerInit()
 {
     nsresult rv;
@@ -97,18 +98,21 @@ nsresult EvaluateAdminConfigScript(const
     }
 
     // Grab XPConnect.
     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
     if (NS_FAILED(rv)) {
         return rv;
     }
 
-    AutoSafeJSContext cx;
-    JSAutoCompartment ac(cx, autoconfigSb);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(autoconfigSb)) {
+        return NS_ERROR_UNEXPECTED;
+    }
+    JSContext* cx = jsapi.cx();
 
     nsAutoCString script(js_buffer, length);
     JS::RootedValue v(cx);
 
     nsString convertedScript = NS_ConvertUTF8toUTF16(script);
     if (convertedScript.Length() == 0) {
       nsContentUtils::ReportToConsoleNonLocalized(
         NS_LITERAL_STRING("Your AutoConfig file is ASCII. Please convert it to UTF-8."),
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -1250,17 +1250,17 @@ public:
 
   static already_AddRefed<DrawTarget>
     CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
 
   static already_AddRefed<DrawTarget>
     CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT);
 
   static already_AddRefed<DrawTarget>
-    CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
+    CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false);
 
   static already_AddRefed<ScaledFont>
     CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize);
 
   /**
    * This creates a NativeFontResource from TrueType data.
    *
    * @param aData Pointer to the data
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -1625,16 +1625,39 @@ DrawTargetD2D1::CreateBrushForPattern(co
 
     D2D1_RECT_F samplingBounds;
     Matrix mat = pat->mMatrix;
 
     MOZ_ASSERT(pat->mSurface->IsValid());
 
     RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode, !pat->mSamplingRect.IsEmpty() ? &pat->mSamplingRect : nullptr);
 
+    if (pat->mSurface->GetFormat() == SurfaceFormat::A8) {
+      // See bug 1251431, at least FillOpacityMask does not appear to allow a source bitmapbrush
+      // with source format A8. This creates a BGRA surface with the same alpha values that
+      // the A8 surface has.
+      RefPtr<ID2D1Bitmap> bitmap;
+      image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
+      if (bitmap) {
+        RefPtr<ID2D1Image> oldTarget;
+        RefPtr<ID2D1Bitmap1> tmpBitmap;
+        mDC->CreateBitmap(D2D1::SizeU(pat->mSurface->GetSize().width, pat->mSurface->GetSize().height), nullptr, 0,
+                          &D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
+                          getter_AddRefs(tmpBitmap));
+        mDC->GetTarget(getter_AddRefs(oldTarget));
+        mDC->SetTarget(tmpBitmap);
+
+        RefPtr<ID2D1SolidColorBrush> brush;
+        mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), getter_AddRefs(brush));
+        mDC->FillOpacityMask(bitmap, brush);
+        mDC->SetTarget(oldTarget);
+        image = tmpBitmap;
+      }
+    }
+
     if (!image) {
       return CreateTransparentBlackBrush();
     }
 
     if (pat->mSamplingRect.IsEmpty()) {
       RefPtr<ID2D1Bitmap> bitmap;
       image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
       if (bitmap) {
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -935,20 +935,20 @@ VerifyRGBXFormat(uint8_t* aData, const I
     aData += aStride;
   }
 
   return true;
 }
 #endif
 
 void
-DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
+DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized)
 {
   MOZ_ASSERT((aFormat != SurfaceFormat::B8G8R8X8) ||
-              VerifyRGBXFormat(aData, aSize, aStride, aFormat));
+              aUninitialized || VerifyRGBXFormat(aData, aSize, aStride, aFormat));
 
   SkBitmap bitmap;
   bitmap.setInfo(MakeSkiaImageInfo(aSize, aFormat), aStride);
   bitmap.setPixels(aData);
 
   mCanvas.adopt(new SkCanvas(bitmap));
 
   mSize = aSize;
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -106,17 +106,17 @@ public:
     CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const override;
   virtual already_AddRefed<PathBuilder> CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const override;
   virtual already_AddRefed<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = ExtendMode::CLAMP) const override;
   virtual already_AddRefed<FilterNode> CreateFilter(FilterType aType) override;
   virtual void SetTransform(const Matrix &aTransform) override;
   virtual void *GetNativeSurface(NativeSurfaceType aType) override;
 
   bool Init(const IntSize &aSize, SurfaceFormat aFormat);
-  void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
+  void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat, bool aUninitialized = false);
 
 #ifdef USE_SKIA_GPU
   bool InitWithGrContext(GrContext* aGrContext,
                          const IntSize &aSize,
                          SurfaceFormat aFormat,
                          bool aCached);
   virtual bool
     InitWithGrContext(GrContext* aGrContext,
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -379,33 +379,34 @@ Factory::CreateRecordingDrawTarget(DrawE
   return MakeAndAddRef<DrawTargetRecording>(aRecorder, aDT);
 }
 
 already_AddRefed<DrawTarget>
 Factory::CreateDrawTargetForData(BackendType aBackend,
                                  unsigned char *aData,
                                  const IntSize &aSize,
                                  int32_t aStride,
-                                 SurfaceFormat aFormat)
+                                 SurfaceFormat aFormat,
+                                 bool aUninitialized)
 {
   MOZ_ASSERT(aData);
   if (!AllowedSurfaceSize(aSize)) {
     gfxCriticalError(LoggerOptionsBasedOnSize(aSize)) << "Failed to allocate a surface due to invalid size (DTD) " << aSize;
     return nullptr;
   }
 
   RefPtr<DrawTarget> retVal;
 
   switch (aBackend) {
 #ifdef USE_SKIA
   case BackendType::SKIA:
     {
       RefPtr<DrawTargetSkia> newTarget;
       newTarget = new DrawTargetSkia();
-      newTarget->Init(aData, aSize, aStride, aFormat);
+      newTarget->Init(aData, aSize, aStride, aFormat, aUninitialized);
       retVal = newTarget;
       break;
     }
 #endif
 #ifdef XP_DARWIN
   case BackendType::COREGRAPHICS:
     {
       RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
--- a/gfx/2d/PathHelpers.h
+++ b/gfx/2d/PathHelpers.h
@@ -26,56 +26,48 @@ inline Float ComputeKappaFactor(Float aA
 }
 
 /**
  * Draws a partial arc <= 90 degrees given exact start and end points.
  * Assumes that it is continuing from an already specified start point.
  */
 template <typename T>
 inline void PartialArcToBezier(T* aSink,
-                               const Size& aRadius,
-                               const Point& aStartPoint, const Point& aEndPoint,
                                const Point& aStartOffset, const Point& aEndOffset,
-                               Float aKappaFactor = kKappaFactor,
-                               const Matrix& aTransform = Matrix())
+                               const Matrix& aTransform,
+                               Float aKappaFactor = kKappaFactor)
 {
-  Float kappaX = aKappaFactor * aRadius.width;
-  Float kappaY = aKappaFactor * aRadius.height;
-
   Point cp1 =
-    aStartPoint + Point(-aStartOffset.y * kappaX, aStartOffset.x * kappaY);
+    aStartOffset + Point(-aStartOffset.y, aStartOffset.x) * aKappaFactor;
 
   Point cp2 =
-    aEndPoint + Point(aEndOffset.y * kappaX, -aEndOffset.x * kappaY);
+    aEndOffset + Point(aEndOffset.y, -aEndOffset.x) * aKappaFactor;
 
-  aSink->BezierTo(aTransform * cp1, aTransform * cp2, aTransform * aEndPoint);
+  aSink->BezierTo(aTransform * cp1, aTransform * cp2, aTransform * aEndOffset);
 }
 
 /**
  * Draws an acute arc (<= 90 degrees) given exact start and end points.
  * Specialized version avoiding kappa calculation.
  */
 template <typename T>
 inline void AcuteArcToBezier(T* aSink,
                              const Point& aOrigin, const Size& aRadius,
                              const Point& aStartPoint, const Point& aEndPoint,
                              Float aKappaFactor = kKappaFactor)
 {
   aSink->LineTo(aStartPoint);
   if (!aRadius.IsEmpty()) {
+    Float kappaX = aKappaFactor * aRadius.width / aRadius.height;
+    Float kappaY = aKappaFactor * aRadius.height / aRadius.width;
     Point startOffset = aStartPoint - aOrigin;
-    startOffset.x /= aRadius.width;
-    startOffset.y /= aRadius.height;
     Point endOffset = aEndPoint - aOrigin;
-    endOffset.x /= aRadius.width;
-    endOffset.y /= aRadius.height;
-    PartialArcToBezier(aSink, aRadius,
-                       aStartPoint, aEndPoint,
-                       startOffset, endOffset,
-                       aKappaFactor);
+    aSink->BezierTo(aStartPoint + Point(-startOffset.y * kappaX, startOffset.x * kappaY),
+                    aEndPoint + Point(endOffset.y * kappaX, -endOffset.x * kappaY),
+                    aEndPoint);
   } else if (aEndPoint != aStartPoint) {
     aSink->LineTo(aEndPoint);
   }
 }
 
 /**
  * Draws an acute arc (<= 90 degrees) given exact start and end points.
  */
@@ -108,70 +100,60 @@ void ArcToBezier(T* aSink, const Point &
     aStartAngle = aEndAngle - arcSweepLeft * sweepDirection;
   } else if (arcSweepLeft > Float(2.0f * M_PI)) {
     // Sweeping more than 2 * pi is a full circle.
     arcSweepLeft = Float(2.0f * M_PI);
   }
 
   Float currentStartAngle = aStartAngle;
   Point currentStartOffset(cosf(aStartAngle), sinf(aStartAngle));
-  Point currentStartPoint(currentStartOffset.x * aRadius.width,
-                          currentStartOffset.y * aRadius.height);
-  Matrix transform(cosf(aRotation), sinf(aRotation), -sinf(aRotation), cosf(aRotation), aOrigin.x, aOrigin.y);
-  aSink->LineTo(transform * currentStartPoint);
+  Matrix transform = Matrix::Scaling(aRadius.width, aRadius.height);
+  if (aRotation != 0.0f) {
+    transform *= Matrix::Rotation(aRotation);
+  }
+  transform.PostTranslate(aOrigin);
+  aSink->LineTo(transform * currentStartOffset);
 
   while (arcSweepLeft > 0) {
     Float currentEndAngle =
       currentStartAngle + std::min(arcSweepLeft, Float(M_PI / 2.0f)) * sweepDirection;
-
     Point currentEndOffset(cosf(currentEndAngle), sinf(currentEndAngle));
-    Point currentEndPoint(currentEndOffset.x * aRadius.width,
-                          currentEndOffset.y * aRadius.height);
 
-    PartialArcToBezier(aSink, aRadius,
-                       currentStartPoint, currentEndPoint,
-                       currentStartOffset, currentEndOffset,
-                       ComputeKappaFactor(currentEndAngle - currentStartAngle),
-                       transform);
+    PartialArcToBezier(aSink, currentStartOffset, currentEndOffset, transform,
+                       ComputeKappaFactor(currentEndAngle - currentStartAngle));
 
     // We guarantee here the current point is the start point of the next
     // curve segment.
     arcSweepLeft -= Float(M_PI / 2.0f);
     currentStartAngle = currentEndAngle;
     currentStartOffset = currentEndOffset;
-    currentStartPoint = currentEndPoint;
   }
 }
 
 /* This is basically the ArcToBezier with the parameters for drawing a circle
  * inlined which vastly simplifies it and avoids a bunch of transcedental function
  * calls which should make it faster. */
 template <typename T>
 void EllipseToBezier(T* aSink, const Point &aOrigin, const Size &aRadius)
 {
+  Matrix transform(aRadius.width, 0, 0, aRadius.height, aOrigin.x, aOrigin.y);
   Point currentStartOffset(1, 0);
-  Point currentStartPoint(aOrigin.x + aRadius.width, aOrigin.y);
 
-  aSink->LineTo(currentStartPoint);
+  aSink->LineTo(transform * currentStartOffset);
 
   for (int i = 0; i < 4; i++) {
     // cos(x+pi/2) == -sin(x)
     // sin(x+pi/2) == cos(x)
     Point currentEndOffset(-currentStartOffset.y, currentStartOffset.x);
-    Point currentEndPoint(aOrigin.x + currentEndOffset.x * aRadius.width,
-                          aOrigin.y + currentEndOffset.y * aRadius.height);
 
-    PartialArcToBezier(aSink, aRadius,
-                       currentStartPoint, currentEndPoint,
-                       currentStartOffset, currentEndOffset);
+    PartialArcToBezier(aSink, currentStartOffset, currentEndOffset, transform);
 
     // We guarantee here the current point is the start point of the next
     // curve segment.
     currentStartOffset = currentEndOffset;
-    currentStartPoint = currentEndPoint;
   }
 }
 
 /**
  * Appends a path represending a rectangle to the path being built by
  * aPathBuilder.
  *
  * aRect           The rectangle to append.
--- a/gfx/layers/BufferTexture.cpp
+++ b/gfx/layers/BufferTexture.cpp
@@ -5,16 +5,17 @@
 
 #include "BufferTexture.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/fallible.h"
+#include <algorithm>
 
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"
 #endif
 
 namespace mozilla {
 namespace layers {
 
@@ -240,29 +241,29 @@ BufferTextureData::BorrowDrawTarget()
     return nullptr;
   }
 
   const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
 
   uint32_t stride = ImageDataSerializer::GetRGBStride(rgb);
   mDrawTarget = gfx::Factory::CreateDrawTargetForData(mMoz2DBackend,
                                                       GetBuffer(), rgb.size(),
-                                                      stride, rgb.format());
+                                                      stride, rgb.format(), true);
 
   if (mDrawTarget) {
     RefPtr<gfx::DrawTarget> dt = mDrawTarget;
     return dt.forget();
   }
 
   // TODO - should we warn? should we really fallback to cairo? perhaps
   // at least update mMoz2DBackend...
   if (mMoz2DBackend != gfx::BackendType::CAIRO) {
     mDrawTarget = gfx::Factory::CreateDrawTargetForData(gfx::BackendType::CAIRO,
                                                         GetBuffer(), rgb.size(),
-                                                        stride, rgb.format());
+                                                        stride, rgb.format(), true);
   }
 
   if (!mDrawTarget) {
     gfxCriticalNote << "BorrowDrawTarget failure, original backend " << (int)mMoz2DBackend;
   }
 
   RefPtr<gfx::DrawTarget> dt = mDrawTarget;
   return dt.forget();
@@ -392,26 +393,32 @@ MemoryTextureData::Serialize(SurfaceDesc
   }
 
   uintptr_t ptr = reinterpret_cast<uintptr_t>(mBuffer);
   aOutDescriptor = SurfaceDescriptorBuffer(mDescriptor, MemoryOrShmem(ptr));
 
   return true;
 }
 
-static bool InitBuffer(uint8_t* buf, size_t bufSize, TextureAllocationFlags aAllocFlags)
+static bool InitBuffer(uint8_t* buf, size_t bufSize, gfx::SurfaceFormat aFormat, TextureAllocationFlags aAllocFlags)
 {
   if (!buf) {
     gfxDebug() << "BufferTextureData: Failed to allocate " << bufSize << " bytes";
     return false;
   }
 
   if ((aAllocFlags & ALLOC_CLEAR_BUFFER) ||
       (aAllocFlags & ALLOC_CLEAR_BUFFER_BLACK)) {
-    memset(buf, 0, bufSize);
+    if (aFormat == gfx::SurfaceFormat::B8G8R8X8) {
+      // Even though BGRX was requested, XRGB_UINT32 is what is meant,
+      // so use 0xFF000000 to put alpha in the right place.
+      std::fill_n(reinterpret_cast<uint32_t*>(buf), bufSize / sizeof(uint32_t), 0xFF000000);
+    } else {
+      memset(buf, 0, bufSize);
+    }
   }
 
   if (aAllocFlags & ALLOC_CLEAR_BUFFER_WHITE) {
     memset(buf, 0xFF, bufSize);
   }
 
   return true;
 }
@@ -431,17 +438,17 @@ MemoryTextureData::Create(gfx::IntSize a
   }
 
   uint32_t bufSize = ImageDataSerializer::ComputeRGBBufferSize(aSize, aFormat);
   if (!bufSize) {
     return nullptr;
   }
 
   uint8_t* buf = new (fallible) uint8_t[bufSize];
-  if (!InitBuffer(buf, bufSize, aAllocFlags)) {
+  if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags)) {
     return nullptr;
   }
 
   auto fwd = aAllocator ? aAllocator->AsCompositableForwarder() : nullptr;
   bool hasIntermediateBuffer = fwd ? ComputeHasIntermediateBuffer(aFormat,
                                               fwd->GetCompositorBackendType())
                                    : true;
 
@@ -508,17 +515,17 @@ ShmemTextureData::Create(gfx::IntSize aS
   }
 
   mozilla::ipc::Shmem shm;
   if (!aAllocator->AllocUnsafeShmem(bufSize, OptimalShmemType(), &shm)) {
     return nullptr;
   }
 
   uint8_t* buf = shm.get<uint8_t>();
-  if (!InitBuffer(buf, bufSize, aAllocFlags)) {
+  if (!InitBuffer(buf, bufSize, aFormat, aAllocFlags)) {
     return nullptr;
   }
 
   auto fwd = aAllocator->AsCompositableForwarder();
   bool hasIntermediateBuffer = fwd ? ComputeHasIntermediateBuffer(aFormat,
                                               fwd->GetCompositorBackendType())
                                    : true;
 
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -3,16 +3,17 @@
  * 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 GFX_FRAMEMETRICS_H
 #define GFX_FRAMEMETRICS_H
 
 #include <stdint.h>                     // for uint32_t, uint64_t
 #include "Units.h"                      // for CSSRect, CSSPixel, etc
+#include "mozilla/HashFunctions.h"      // for HashGeneric
 #include "mozilla/Maybe.h"
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/gfx/Rect.h"           // for RoundedIn
 #include "mozilla/gfx/ScaleFactor.h"    // for ScaleFactor
 #include "mozilla/gfx/Logging.h"        // for Log
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "nsString.h"
 
@@ -861,16 +862,21 @@ struct ScrollableLayerGuid {
         return true;
       }
       if (mPresShellId == other.mPresShellId) {
         return mScrollId < other.mScrollId;
       }
     }
     return false;
   }
+
+  uint32_t Hash() const
+  {
+    return HashGeneric(mLayersId, mPresShellId, mScrollId);
+  }
 };
 
 template <int LogLevel>
 gfx::Log<LogLevel>& operator<<(gfx::Log<LogLevel>& log, const ScrollableLayerGuid& aGuid) {
   return log << '(' << aGuid.mLayersId << ',' << aGuid.mPresShellId << ',' << aGuid.mScrollId << ')';
 }
 
 struct ZoomConstraints {
--- a/gfx/layers/apz/test/reftest/reftest.list
+++ b/gfx/layers/apz/test/reftest/reftest.list
@@ -1,16 +1,16 @@
 # The following tests test the async positioning of the scrollbars.
 # Basic root-frame scrollbar with async scrolling
-fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html
-fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html
-fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html
-fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html
-fuzzy-if(Android,13,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html
-fuzzy-if(Android,8,10) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
+skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v.html async-scrollbar-1-v-ref.html
+skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-h.html async-scrollbar-1-h-ref.html
+skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-vh.html async-scrollbar-1-vh-ref.html
+skip-if(!asyncPan) fuzzy-if(Android,6,8) == async-scrollbar-1-v-rtl.html async-scrollbar-1-v-rtl-ref.html
+skip-if(!asyncPan) fuzzy-if(Android,13,8) == async-scrollbar-1-h-rtl.html async-scrollbar-1-h-rtl-ref.html
+skip-if(!asyncPan) fuzzy-if(Android,8,10) == async-scrollbar-1-vh-rtl.html async-scrollbar-1-vh-rtl-ref.html
 
 # Different async zoom levels. Since the scrollthumb gets async-scaled in the
 # compositor, the border-radius ends of the scrollthumb are going to be a little
 # off, hence the fuzzy-if clauses.
 skip-if(!asyncZoom) fuzzy-if(B2G,98,82) == async-scrollbar-zoom-1.html async-scrollbar-zoom-1-ref.html
 skip-if(!asyncZoom) fuzzy-if(B2G,94,146) == async-scrollbar-zoom-2.html async-scrollbar-zoom-2-ref.html
 
 # Meta-viewport tag support
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -847,23 +847,16 @@ TextureClient::CreateForRawBufferAccess(
   if (aAllocFlags & ALLOC_DISALLOW_BUFFERTEXTURECLIENT) {
     return nullptr;
   }
 
   if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
     return nullptr;
   }
 
-  if (aFormat == SurfaceFormat::B8G8R8X8 &&
-      (aAllocFlags != TextureAllocationFlags::ALLOC_CLEAR_BUFFER_BLACK) &&
-      aMoz2DBackend == gfx::BackendType::SKIA) {
-    // skia requires alpha component of RGBX textures to be 255.
-    aAllocFlags = TextureAllocationFlags::ALLOC_CLEAR_BUFFER_WHITE;
-  }
-
   TextureData* texData = BufferTextureData::Create(aSize, aFormat, aMoz2DBackend,
                                                    aTextureFlags, aAllocFlags,
                                                    aAllocator);
   if (!texData) {
     return nullptr;
   }
 
   return MakeAndAddRef<TextureClient>(texData, aTextureFlags, aAllocator);
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -491,21 +491,22 @@ RenderMinimap(ContainerT* aContainer, La
   ParentLayerPoint scrollOffset;
   controller->SampleContentTransformForFrame(&asyncTransformWithoutOverscroll,
                                            scrollOffset);
 
   // Options
   const int verticalPadding = 10;
   const int horizontalPadding = 5;
   gfx::Color backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
-  gfx::Color tileActiveColor(1, 1, 1, 0.5f);
+  gfx::Color tileActiveColor(1, 1, 1, 0.4f);
   gfx::Color tileBorderColor(0, 0, 0, 0.1f);
   gfx::Color pageBorderColor(0, 0, 0);
   gfx::Color displayPortColor(0, 1.f, 0);
-  gfx::Color viewPortColor(0, 0, 1.f);
+  gfx::Color viewPortColor(0, 0, 1.f, 0.3f);
+  gfx::Color visibilityColor(1.f, 0, 0);
 
   // Rects
   const FrameMetrics& fm = aLayer->GetFrameMetrics(0);
   ParentLayerRect compositionBounds = fm.GetCompositionBounds();
   LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel();
   LayerRect viewRect = ParentLayerRect(scrollOffset, compositionBounds.Size()) / LayerToParentLayerScale(1);
   LayerRect dp = (fm.GetDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel();
 
@@ -546,22 +547,55 @@ RenderMinimap(ContainerT* aContainer, La
       if (tileRect.Intersects(dp)) {
         compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform());
       }
       compositor->SlowDrawRect(r, tileBorderColor, clipRect, aContainer->GetEffectiveTransform());
     }
   }
   */
 
+  // Render the scrollable area.
   r = transform.TransformBounds(scrollRect.ToUnknownRect());
   compositor->SlowDrawRect(r, pageBorderColor, clipRect, aContainer->GetEffectiveTransform());
+
+  // If enabled, render information about visibility.
+  if (gfxPrefs::APZMinimapVisibilityEnabled()) {
+    // Retrieve the APZC scrollable layer guid, which we'll use to get the
+    // appropriate visibility information from the layer manager.
+    AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
+    MOZ_ASSERT(controller);
+
+    ScrollableLayerGuid guid = controller->GetGuid();
+
+    // Get the approximately visible region.
+    static CSSIntRegion emptyRegion;
+    CSSIntRegion* visibleRegion = aManager->GetApproximatelyVisibleRegion(guid);
+    if (!visibleRegion) {
+      visibleRegion = &emptyRegion;
+    }
+
+    // Iterate through and draw the rects in the region.
+    for (CSSIntRegion::RectIterator iterator = visibleRegion->RectIter();
+         !iterator.Done();
+         iterator.Next())
+    {
+      CSSIntRect rect = iterator.Get();
+      LayerRect scaledRect = rect * fm.LayersPixelsPerCSSPixel();
+      Rect r = transform.TransformBounds(scaledRect.ToUnknownRect());
+      compositor->FillRect(r, visibilityColor, clipRect, aContainer->GetEffectiveTransform());
+    }
+  }
+
+  // Render the displayport.
   r = transform.TransformBounds(dp.ToUnknownRect());
   compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform());
   r = transform.TransformBounds(dp.ToUnknownRect());
   compositor->SlowDrawRect(r, displayPortColor, clipRect, aContainer->GetEffectiveTransform());
+
+  // Render the viewport.
   r = transform.TransformBounds(viewRect.ToUnknownRect());
   compositor->SlowDrawRect(r, viewPortColor, clipRect, aContainer->GetEffectiveTransform(), 2);
 }
 
 
 template<class ContainerT> void
 RenderLayers(ContainerT* aContainer,
 	     LayerManagerComposite* aManager,
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -215,16 +215,41 @@ public:
 
   static void PlatformSyncBeforeReplyUpdate();
 
   void AddInvalidRegion(const nsIntRegion& aRegion)
   {
     mInvalidRegion.Or(mInvalidRegion, aRegion);
   }
 
+  void ClearApproximatelyVisibleRegions(uint64_t aLayersId,
+                                        const Maybe<uint32_t>& aPresShellId)
+  {
+    for (auto iter = mVisibleRegions.Iter(); !iter.Done(); iter.Next()) {
+      if (iter.Key().mLayersId == aLayersId &&
+          (!aPresShellId || iter.Key().mPresShellId == *aPresShellId)) {
+        iter.Remove();
+      }
+    }
+  }
+
+  void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+                                        const CSSIntRegion& aRegion)
+  {
+    CSSIntRegion* regionForScrollFrame = mVisibleRegions.LookupOrAdd(aGuid);
+    MOZ_ASSERT(regionForScrollFrame);
+
+    *regionForScrollFrame = aRegion;
+  }
+
+  CSSIntRegion* GetApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid)
+  {
+    return mVisibleRegions.Get(aGuid);
+  }
+
   Compositor* GetCompositor() const
   {
     return mCompositor;
   }
 
   // Called by CompositorParent when a new compositor has been created due
   // to a device reset. The layer manager must clear any cached resources
   // attached to the old compositor, and make a best effort at ignoring
@@ -350,16 +375,21 @@ private:
 
   /**
    * Context target, nullptr when drawing directly to our swap chain.
    */
   RefPtr<gfx::DrawTarget> mTarget;
   gfx::IntRect mTargetBounds;
 
   nsIntRegion mInvalidRegion;
+
+  typedef nsClassHashtable<nsGenericHashKey<ScrollableLayerGuid>,
+                           CSSIntRegion> VisibleRegions;
+  VisibleRegions mVisibleRegions;
+
   UniquePtr<FPSState> mFPS;
 
   bool mInTransaction;
   bool mIsCompositorReady;
   bool mDebugOverlayWantsNextFrame;
 
   RefPtr<CompositingRenderTarget> mTwoPassTmpTarget;
   RefPtr<TextRenderer> mTextRenderer;
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -511,16 +511,26 @@ BufferTextureHost::EnsureWrappingTexture
     gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(),
       ImageDataSerializer::ComputeRGBStride(mFormat, mSize.width), mSize, mFormat);
 
   if (!surf) {
     return false;
   }
 
   mFirstSource = mCompositor->CreateDataTextureSourceAround(surf);
+  if (!mFirstSource) {
+    // BasicCompositor::CreateDataTextureSourceAround never returns null
+    // and we don't expect to take this branch if we are using another backend.
+    // Returning false is fine but if we get into this situation it probably
+    // means something fishy is going on, like a texture being used with
+    // several compositor backends.
+    NS_WARNING("Failed to use a BufferTextureHost without intermediate buffer");
+    return false;
+  }
+
   mFirstSource->SetUpdateSerial(mUpdateSerial);
   mFirstSource->SetOwner(this);
 
   return true;
 }
 
 void
 BufferTextureHost::PrepareTextureSource(CompositableTextureSourceRef& aTexture)
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -699,12 +699,35 @@ CompositorChild::SendRequestNotifyAfterR
 {
   MOZ_ASSERT(mCanSend);
   if (!mCanSend) {
     return true;
   }
   return PCompositorChild::SendRequestNotifyAfterRemotePaint();
 }
 
+bool
+CompositorChild::SendClearApproximatelyVisibleRegions(uint64_t aLayersId,
+                                                      uint32_t aPresShellId)
+{
+  MOZ_ASSERT(mCanSend);
+  if (!mCanSend) {
+    return true;
+  }
+  return PCompositorChild::SendClearApproximatelyVisibleRegions(aLayersId,
+                                                                aPresShellId);
+}
+
+bool
+CompositorChild::SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+                                                      const CSSIntRegion& aRegion)
+{
+  MOZ_ASSERT(mCanSend);
+  if (!mCanSend) {
+    return true;
+  }
+  return PCompositorChild::SendNotifyApproximatelyVisibleRegion(aGuid, aRegion);
+}
+
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -121,16 +121,19 @@ public:
   bool SendAdoptChild(const uint64_t& id);
   bool SendMakeSnapshot(const SurfaceDescriptor& inSnapshot, const gfx::IntRect& dirtyRect);
   bool SendFlushRendering();
   bool SendGetTileSize(int32_t* tileWidth, int32_t* tileHeight);
   bool SendStartFrameTimeRecording(const int32_t& bufferSize, uint32_t* startIndex);
   bool SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray<float>* intervals);
   bool SendNotifyRegionInvalidated(const nsIntRegion& region);
   bool SendRequestNotifyAfterRemotePaint();
+  bool SendClearApproximatelyVisibleRegions(uint64_t aLayersId, uint32_t aPresShellId);
+  bool SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+                                            const mozilla::CSSIntRegion& aRegion);
 
 private:
   // Private destructor, to discourage deletion outside of Release():
   virtual ~CompositorChild();
 
   virtual PLayerTransactionChild*
     AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints,
                                 const uint64_t& aId,
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -933,16 +933,49 @@ CompositorParent::RecvStopFrameTimeRecor
                                              InfallibleTArray<float>* intervals)
 {
   if (mLayerManager) {
     mLayerManager->StopFrameTimeRecording(aStartIndex, *intervals);
   }
   return true;
 }
 
+bool
+CompositorParent::RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+                                                       const uint32_t& aPresShellId)
+{
+  ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId));
+  return true;
+}
+
+void
+CompositorParent::ClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+                                                   const Maybe<uint32_t>& aPresShellId)
+{
+  if (mLayerManager) {
+    mLayerManager->ClearApproximatelyVisibleRegions(aLayersId, aPresShellId);
+
+    // We need to recomposite to update the minimap.
+    ScheduleComposition();
+  }
+}
+
+bool
+CompositorParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+                                                       const CSSIntRegion& aRegion)
+{
+  if (mLayerManager) {
+    mLayerManager->UpdateApproximatelyVisibleRegion(aGuid, aRegion);
+
+    // We need to recomposite to update the minimap.
+    ScheduleComposition();
+  }
+  return true;
+}
+
 void
 CompositorParent::ActorDestroy(ActorDestroyReason why)
 {
   CancelCurrentCompositeTask();
   if (mForceCompositionTask) {
     mForceCompositionTask->Cancel();
     mForceCompositionTask = nullptr;
   }
@@ -1746,17 +1779,26 @@ CompositorParent::AllocateLayerTreeId()
   static uint64_t ids = 0;
   return ++ids;
 }
 
 static void
 EraseLayerState(uint64_t aId)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
-  sIndirectLayerTrees.erase(aId);
+
+  auto iter = sIndirectLayerTrees.find(aId);
+  if (iter != sIndirectLayerTrees.end()) {
+    CompositorParent* parent = iter->second.mParent;
+    if (parent) {
+      parent->ClearApproximatelyVisibleRegions(aId, Nothing());
+    }
+
+    sIndirectLayerTrees.erase(iter);
+  }
 }
 
 /*static*/ void
 CompositorParent::DeallocateLayerTreeId(uint64_t aId)
 {
   MOZ_ASSERT(NS_IsMainThread());
   // Here main thread notifies compositor to remove an element from
   // sIndirectLayerTrees. This removed element might be queried soon.
@@ -1926,16 +1968,45 @@ public:
   { return true; }
   virtual bool RecvMakeWidgetSnapshot(const SurfaceDescriptor& aInSnapshot) override
   { return true; }
   virtual bool RecvFlushRendering() override { return true; }
   virtual bool RecvForcePresent() override { return true; }
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return true; }
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; }
   virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override  { return true; }
+
+  virtual bool RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+                                                    const uint32_t& aPresShellId) override
+  {
+    CompositorParent* parent;
+    { // scope lock
+      MonitorAutoLock lock(*sIndirectLayerTreesLock);
+      parent = sIndirectLayerTrees[aLayersId].mParent;
+    }
+    if (parent) {
+      parent->ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId));
+    }
+    return true;
+  }
+
+  virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+                                                    const CSSIntRegion& aRegion) override
+  {
+    CompositorParent* parent;
+    { // scope lock
+      MonitorAutoLock lock(*sIndirectLayerTreesLock);
+      parent = sIndirectLayerTrees[aGuid.mLayersId].mParent;
+    }
+    if (parent) {
+      return parent->RecvNotifyApproximatelyVisibleRegion(aGuid, aRegion);
+    }
+    return true;
+  }
+
   virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override
   {
     *aWidth = gfxPlatform::GetPlatform()->GetTileWidth();
     *aHeight = gfxPlatform::GetPlatform()->GetTileHeight();
     return true;
   }
 
   virtual bool RecvGetFrameUniformity(FrameUniformityData* aOutData) override
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -246,16 +246,23 @@ public:
   virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override;
   virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override;
   virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override;
 
   // Unused for chrome <-> compositor communication (which this class does).
   // @see CrossProcessCompositorParent::RecvRequestNotifyAfterRemotePaint
   virtual bool RecvRequestNotifyAfterRemotePaint() override { return true; };
 
+  virtual bool RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+                                                    const uint32_t& aPresShellId) override;
+  void ClearApproximatelyVisibleRegions(const uint64_t& aLayersId,
+                                        const Maybe<uint32_t>& aPresShellId);
+  virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
+                                                    const CSSIntRegion& aRegion) override;
+
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
                                    const uint64_t& aTransactionId,
                                    const TargetConfig& aTargetConfig,
                                    const InfallibleTArray<PluginWindowData>& aPlugins,
                                    bool aIsFirstPaint,
                                    bool aScheduleComposite,
--- a/gfx/layers/ipc/PCompositor.ipdl
+++ b/gfx/layers/ipc/PCompositor.ipdl
@@ -12,20 +12,22 @@ include protocol PLayer;
 include protocol PLayerTransaction;
 include "mozilla/GfxMessageUtils.h";
 
 using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
 using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
 using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
+using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
 using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
 using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
 using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
 using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
+using mozilla::CSSIntRegion from "Units.h";
 using mozilla::LayoutDeviceIntPoint from "Units.h";
 using mozilla::LayoutDeviceIntRegion from "Units.h";
 using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
 using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h";
 
 namespace mozilla {
 namespace layers {
 
@@ -173,16 +175,26 @@ parent:
   /**
    * The child (content/chrome thread) requests that the parent inform it when
    * the graphics objects are ready to display.
    * @see PBrowser
    * @see RemotePaintIsReady
    */
   async RequestNotifyAfterRemotePaint();
 
+  // The child clears the 'approximately visible' regions associated with the
+  // provided layers ID and pres shell ID (i.e., the regions for all view IDs
+  // associated with those IDs).
+  async ClearApproximatelyVisibleRegions(uint64_t layersId, uint32_t presShellId);
+
+  // The child sends a region containing rects associated with the provided
+  // scrollable layer GUID that the child considers 'approximately visible'.
+  // We visualize this information in the APZ minimap.
+  async NotifyApproximatelyVisibleRegion(ScrollableLayerGuid guid, CSSIntRegion region);
+
 child:
   // Send back Compositor Frame Metrics from APZCs so tiled layers can
   // update progressively.
   async SharedCompositorFrameMetrics(Handle metrics, CrossProcessMutexHandle mutex, uint64_t aLayersId, uint32_t aAPZCId);
   async ReleaseSharedCompositorFrameMetrics(ViewID aId, uint32_t aAPZCId);
 };
 
 } // layers
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -241,47 +241,22 @@ gfxAndroidPlatform::GetCommonFallbackFon
             }
             break;
         }
     }
     // and try Droid Sans Fallback as a last resort
     aFontList.AppendElement("Droid Sans Fallback");
 }
 
-nsresult
-gfxAndroidPlatform::GetFontList(nsIAtom *aLangGroup,
-                                const nsACString& aGenericFamily,
-                                nsTArray<nsString>& aListOfFonts)
-{
-    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
-                                                         aGenericFamily,
-                                                         aListOfFonts);
-    return NS_OK;
-}
-
 void
 gfxAndroidPlatform::GetSystemFontList(InfallibleTArray<FontListEntry>* retValue)
 {
     gfxFT2FontList::PlatformFontList()->GetSystemFontList(retValue);
 }
 
-nsresult
-gfxAndroidPlatform::UpdateFontList()
-{
-    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
-    return NS_OK;
-}
-
-nsresult
-gfxAndroidPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
-{
-    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
-    return NS_OK;
-}
-
 gfxPlatformFontList*
 gfxAndroidPlatform::CreatePlatformFontList()
 {
     gfxPlatformFontList* list = new gfxFT2FontList();
     if (NS_SUCCEEDED(list->InitFontList())) {
         return list;
     }
     gfxPlatformFontList::Shutdown();
@@ -321,44 +296,16 @@ gfxAndroidPlatform::CreateFontGroup(cons
 }
 
 FT_Library
 gfxAndroidPlatform::GetFTLibrary()
 {
     return gPlatformFTLibrary;
 }
 
-gfxFontEntry*
-gfxAndroidPlatform::LookupLocalFont(const nsAString& aFontName,
-                                    uint16_t aWeight,
-                                    int16_t aStretch,
-                                    uint8_t aStyle)
-{
-    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
-                                                                    aWeight,
-                                                                    aStretch,
-                                                                    aStyle);
-}
-
-gfxFontEntry* 
-gfxAndroidPlatform::MakePlatformFont(const nsAString& aFontName,
-                                     uint16_t aWeight,
-                                     int16_t aStretch,
-                                     uint8_t aStyle,
-                                     const uint8_t* aFontData,
-                                     uint32_t aLength)
-{
-    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
-                                                                     aWeight,
-                                                                     aStretch,
-                                                                     aStyle,
-                                                                     aFontData,
-                                                                     aLength);
-}
-
 already_AddRefed<ScaledFont>
 gfxAndroidPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
 {
     return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
 }
 
 bool
 gfxAndroidPlatform::FontHintingEnabled()
--- a/gfx/thebes/gfxAndroidPlatform.h
+++ b/gfx/thebes/gfxAndroidPlatform.h
@@ -40,40 +40,21 @@ public:
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);
 
     // to support IPC font list (sharing between chrome and content)
     void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue);
 
     // platform implementations of font functions
     virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags);
     virtual gfxPlatformFontList* CreatePlatformFontList();
-    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          uint16_t aWeight,
-                                          int16_t aStretch,
-                                          uint8_t aStyle);
-    virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           uint16_t aWeight,
-                                           int16_t aStretch,
-                                           uint8_t aStyle,
-                                           const uint8_t* aFontData,
-                                           uint32_t aLength);
 
     virtual void GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList);
 
-    virtual nsresult GetFontList(nsIAtom *aLangGroup,
-                                 const nsACString& aGenericFamily,
-                                 nsTArray<nsString>& aListOfFonts);
-
-    virtual nsresult UpdateFontList();
-
-    virtual nsresult GetStandardFamilyName(const nsAString& aFontName,
-                                           nsAString& aFamilyName);
-
     gfxFontGroup*
     CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                     const gfxFontStyle *aStyle,
                     gfxTextPerfMetrics* aTextPerf,
                     gfxUserFontSet *aUserFontSet,
                     gfxFloat aDevToCssSize) override;
 
     virtual bool FontHintingEnabled() override;
--- a/gfx/thebes/gfxDWriteCommon.cpp
+++ b/gfx/thebes/gfxDWriteCommon.cpp
@@ -3,16 +3,17 @@
  * 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 "gfxDWriteCommon.h"
 
 #include <unordered_map>
 
 #include "mozilla/Atomics.h"
+#include "mozilla/gfx/Logging.h"
 
 static mozilla::Atomic<uint64_t> sNextFontFileKey;
 static std::unordered_map<uint64_t, IDWriteFontFileStream*> sFontFileStreams;
 
 IDWriteFontFileLoader* gfxDWriteFontFileLoader::mInstance = nullptr;
 
 class gfxDWriteFontFileStream final : public IDWriteFontFileStream
 {
@@ -153,16 +154,20 @@ HRESULT
 gfxDWriteFontFileLoader::CreateCustomFontFile(FallibleTArray<uint8_t>& aFontData,
                                               IDWriteFontFile** aFontFile,
                                               IDWriteFontFileStream** aFontFileStream)
 {
   MOZ_ASSERT(aFontFile);
   MOZ_ASSERT(aFontFileStream);
 
   IDWriteFactory *factory = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
+  if (!factory) {
+    gfxCriticalError() << "Failed to get DWrite Factory in CreateCustomFontFile.";
+    return E_FAIL;
+  }
 
   uint64_t fontFileKey = sNextFontFileKey++;
   RefPtr<IDWriteFontFileStream> ffsRef = new gfxDWriteFontFileStream(&aFontData, fontFileKey);
   sFontFileStreams[fontFileKey] = ffsRef;
 
   RefPtr<IDWriteFontFile> fontFile;
   HRESULT hr = factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey), Instance(), getter_AddRefs(fontFile));
   if (FAILED(hr)) {
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -726,16 +726,20 @@ gfxFontUtils::MapUVSToGlyphFormat14(cons
 
     size_t index;
     if (!BinarySearch(Format14CmapWrapper(*cmap14),
                       0, cmap14->numVarSelectorRecords, aVS, &index)) {
         return 0;
     }
 
     const uint32_t nonDefUVSOffset = cmap14->varSelectorRecords[index].nonDefaultUVSOffset;
+    if (!nonDefUVSOffset) {
+        return 0;
+    }
+
     const NonDefUVSTable *table = reinterpret_cast<const NonDefUVSTable*>
                                       (aBuf + nonDefUVSOffset);
 
     if (BinarySearch(NonDefUVSTableWrapper(*table), 0, table->numUVSMappings,
                      aCh, &index)) {
         return table->uvsMappings[index].glyphID;
     }
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1376,23 +1376,36 @@ gfxPlatform::BackendTypeForName(const ns
   return BackendType::NONE;
 }
 
 nsresult
 gfxPlatform::GetFontList(nsIAtom *aLangGroup,
                          const nsACString& aGenericFamily,
                          nsTArray<nsString>& aListOfFonts)
 {
-    return NS_ERROR_NOT_IMPLEMENTED;
+    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
+                                                         aGenericFamily,
+                                                         aListOfFonts);
+    return NS_OK;
 }
 
 nsresult
 gfxPlatform::UpdateFontList()
 {
-    return NS_ERROR_NOT_IMPLEMENTED;
+    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
+    return NS_OK;
+}
+
+nsresult
+gfxPlatform::GetStandardFamilyName(const nsAString& aFontName,
+                                   nsAString& aFamilyName)
+{
+    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName,
+                                                                   aFamilyName);
+    return NS_OK;
 }
 
 bool
 gfxPlatform::DownloadableFontsEnabled()
 {
     if (mAllowDownloadableFonts == UNINITIALIZED_VALUE) {
         mAllowDownloadableFonts =
             Preferences::GetBool(GFX_DOWNLOADABLE_FONTS_ENABLED, false);
@@ -1458,32 +1471,41 @@ gfxPlatform::UseGraphiteShaping()
         mGraphiteShapingEnabled =
             Preferences::GetBool(GFX_PREF_GRAPHITE_SHAPING, false);
     }
 
     return mGraphiteShapingEnabled;
 }
 
 gfxFontEntry*
+gfxPlatform::LookupLocalFont(const nsAString& aFontName,
+                             uint16_t aWeight,
+                             int16_t aStretch,
+                             uint8_t aStyle)
+{
+    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
+                                                                    aWeight,
+                                                                    aStretch,
+                                                                    aStyle);
+}
+
+gfxFontEntry*
 gfxPlatform::MakePlatformFont(const nsAString& aFontName,
                               uint16_t aWeight,
                               int16_t aStretch,
                               uint8_t aStyle,
                               const uint8_t* aFontData,
                               uint32_t aLength)
 {
-    // Default implementation does not handle activating downloaded fonts;
-    // just free the data and return.
-    // Platforms that support @font-face must override this,
-    // using the data to instantiate the font, and taking responsibility
-    // for freeing it when no longer required.
-    if (aFontData) {
-        free((void*)aFontData);
-    }
-    return nullptr;
+    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
+                                                                     aWeight,
+                                                                     aStretch,
+                                                                     aStyle,
+                                                                     aFontData,
+                                                                     aLength);
 }
 
 mozilla::layers::DiagnosticTypes
 gfxPlatform::GetLayerDiagnosticTypes()
 {
   mozilla::layers::DiagnosticTypes type = DiagnosticTypes::NO_DIAGNOSTIC;
   if (gfxPrefs::DrawLayerBorders()) {
     type |= mozilla::layers::DiagnosticTypes::LAYER_BORDERS;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -324,17 +324,17 @@ public:
         NS_NOTREACHED("oops, this platform doesn't have a gfxPlatformFontList implementation");
         return nullptr;
     }
 
     /**
      * Resolving a font name to family name. The result MUST be in the result of GetFontList().
      * If the name doesn't in the system, aFamilyName will be empty string, but not failed.
      */
-    virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) = 0;
+    virtual nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName);
 
     /**
      * Create the appropriate platform font group
      */
     virtual gfxFontGroup*
     CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                     const gfxFontStyle *aStyle,
                     gfxTextPerfMetrics* aTextPerf,
@@ -345,18 +345,17 @@ public:
      * Look up a local platform font using the full font face name.
      * (Needed to support @font-face src local().)
      * Ownership of the returned gfxFontEntry is passed to the caller,
      * who must either AddRef() or delete.
      */
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           uint16_t aWeight,
                                           int16_t aStretch,
-                                          uint8_t aStyle)
-    { return nullptr; }
+                                          uint8_t aStyle);
 
     /**
      * Activate a platform font.  (Needed to support @font-face src url().)
      * aFontData is a NS_Malloc'ed block that must be freed by this function
      * (or responsibility passed on) when it is no longer needed; the caller
      * will NOT free it.
      * Ownership of the returned gfxFontEntry is passed to the caller,
      * who must either AddRef() or delete.
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -126,66 +126,27 @@ gfxPlatformMac::CreateOffscreenSurface(c
 
 already_AddRefed<ScaledFont>
 gfxPlatformMac::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
 {
     gfxMacFont *font = static_cast<gfxMacFont*>(aFont);
     return font->GetScaledFont(aTarget);
 }
 
-nsresult
-gfxPlatformMac::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
-{
-    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
-    return NS_OK;
-}
-
 gfxFontGroup *
 gfxPlatformMac::CreateFontGroup(const FontFamilyList& aFontFamilyList,
                                 const gfxFontStyle *aStyle,
                                 gfxTextPerfMetrics* aTextPerf,
                                 gfxUserFontSet *aUserFontSet,
                                 gfxFloat aDevToCssSize)
 {
     return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf,
                             aUserFontSet, aDevToCssSize);
 }
 
-// these will move to gfxPlatform once all platforms support the fontlist
-gfxFontEntry* 
-gfxPlatformMac::LookupLocalFont(const nsAString& aFontName,
-                                uint16_t aWeight,
-                                int16_t aStretch,
-                                uint8_t aStyle)
-{
-    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
-                                                                    aWeight,
-                                                                    aStretch,
-                                                                    aStyle);
-}
-
-gfxFontEntry* 
-gfxPlatformMac::MakePlatformFont(const nsAString& aFontName,
-                                 uint16_t aWeight,
-                                 int16_t aStretch,
-                                 uint8_t aStyle,
-                                 const uint8_t* aFontData,
-                                 uint32_t aLength)
-{
-    // Ownership of aFontData is received here, and passed on to
-    // gfxPlatformFontList::MakePlatformFont(), which must ensure the data
-    // is released with free when no longer needed
-    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
-                                                                     aWeight,
-                                                                     aStretch,
-                                                                     aStyle,
-                                                                     aFontData,
-                                                                     aLength);
-}
-
 bool
 gfxPlatformMac::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
 
     // accept supported formats
@@ -198,33 +159,16 @@ gfxPlatformMac::IsFontFormatSupported(ns
     if (aFormatFlags != 0) {
         return false;
     }
 
     // no format hint set, need to look at data
     return true;
 }
 
-// these will also move to gfxPlatform once all platforms support the fontlist
-nsresult
-gfxPlatformMac::GetFontList(nsIAtom *aLangGroup,
-                            const nsACString& aGenericFamily,
-                            nsTArray<nsString>& aListOfFonts)
-{
-    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
-    return NS_OK;
-}
-
-nsresult
-gfxPlatformMac::UpdateFontList()
-{
-    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
-    return NS_OK;
-}
-
 static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
 static const char kFontAppleBraille[] = "Apple Braille";
 static const char kFontAppleColorEmoji[] = "Apple Color Emoji";
 static const char kFontAppleSymbols[] = "Apple Symbols";
 static const char kFontDevanagariSangamMN[] = "Devanagari Sangam MN";
 static const char kFontEuphemiaUCAS[] = "Euphemia UCAS";
 static const char kFontGeneva[] = "Geneva";
 static const char kFontGeezaPro[] = "Geeza Pro";
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -28,46 +28,27 @@ public:
 
     virtual already_AddRefed<gfxASurface>
       CreateOffscreenSurface(const IntSize& aSize,
                              gfxImageFormat aFormat) override;
 
     already_AddRefed<mozilla::gfx::ScaledFont>
       GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont) override;
 
-    nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override;
-
     gfxFontGroup*
     CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                     const gfxFontStyle *aStyle,
                     gfxTextPerfMetrics* aTextPerf,
                     gfxUserFontSet *aUserFontSet,
                     gfxFloat aDevToCssSize) override;
 
-    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          uint16_t aWeight,
-                                          int16_t aStretch,
-                                          uint8_t aStyle) override;
-
     virtual gfxPlatformFontList* CreatePlatformFontList() override;
 
-    virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           uint16_t aWeight,
-                                           int16_t aStretch,
-                                           uint8_t aStyle,
-                                           const uint8_t* aFontData,
-                                           uint32_t aLength) override;
-
     bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) override;
 
-    nsresult GetFontList(nsIAtom *aLangGroup,
-                         const nsACString& aGenericFamily,
-                         nsTArray<nsString>& aListOfFonts) override;
-    nsresult UpdateFontList() override;
-
     virtual void GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList) override;
 
     // lookup the system font for a particular system font type and set
     // the name and style characteristics
     static void
     LookupSystemFont(mozilla::LookAndFeel::FontID aSystemFontID,
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -162,16 +162,17 @@ private:
   DECL_GFX_PREF(Live, "apz.fling_friction",                    APZFlingFriction, float, 0.002f);
   DECL_GFX_PREF(Live, "apz.fling_stop_on_tap_threshold",       APZFlingStopOnTapThreshold, float, 0.05f);
   DECL_GFX_PREF(Live, "apz.fling_stopped_threshold",           APZFlingStoppedThreshold, float, 0.01f);
   DECL_GFX_PREF(Live, "apz.highlight_checkerboarded_areas",    APZHighlightCheckerboardedAreas, bool, false);
   DECL_GFX_PREF(Live, "apz.max_velocity_inches_per_ms",        APZMaxVelocity, float, -1.0f);
   DECL_GFX_PREF(Once, "apz.max_velocity_queue_size",           APZMaxVelocityQueueSize, uint32_t, 5);
   DECL_GFX_PREF(Live, "apz.min_skate_speed",                   APZMinSkateSpeed, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.minimap.enabled",                   APZMinimap, bool, false);
+  DECL_GFX_PREF(Live, "apz.minimap.visibility.enabled",        APZMinimapVisibilityEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.overscroll.enabled",                APZOverscrollEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.overscroll.spring_friction",        APZOverscrollSpringFriction, float, 0.015f);
   DECL_GFX_PREF(Live, "apz.overscroll.spring_stiffness",       APZOverscrollSpringStiffness, float, 0.001f);
   DECL_GFX_PREF(Live, "apz.overscroll.stop_distance_threshold", APZOverscrollStopDistanceThreshold, float, 5.0f);
   DECL_GFX_PREF(Live, "apz.overscroll.stop_velocity_threshold", APZOverscrollStopVelocityThreshold, float, 0.01f);
   DECL_GFX_PREF(Live, "apz.overscroll.stretch_factor",         APZOverscrollStretchFactor, float, 0.5f);
   DECL_GFX_PREF(Live, "apz.paint_skipping.enabled",            APZPaintSkipping, bool, true);
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -645,34 +645,16 @@ gfxWindowsPlatform::GetScaledFontForFont
       return Factory::CreateScaledFontWithCairo(nativeFont,
                                                 aFont->GetAdjustedSize(),
                                                 aFont->GetCairoScaledFont());
     }
 
     return Factory::CreateScaledFontForNativeFont(nativeFont, aFont->GetAdjustedSize());
 }
 
-nsresult
-gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup,
-                                const nsACString& aGenericFamily,
-                                nsTArray<nsString>& aListOfFonts)
-{
-    gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, aGenericFamily, aListOfFonts);
-
-    return NS_OK;
-}
-
-nsresult
-gfxWindowsPlatform::UpdateFontList()
-{
-    gfxPlatformFontList::PlatformFontList()->UpdateFontList();
-
-    return NS_OK;
-}
-
 static const char kFontAparajita[] = "Aparajita";
 static const char kFontArabicTypesetting[] = "Arabic Typesetting";
 static const char kFontArial[] = "Arial";
 static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
 static const char kFontCambria[] = "Cambria";
 static const char kFontCambriaMath[] = "Cambria Math";
 static const char kFontEbrima[] = "Ebrima";
 static const char kFontEstrangeloEdessa[] = "Estrangelo Edessa";
@@ -895,62 +877,27 @@ gfxWindowsPlatform::GetCommonFallbackFon
         }
     }
 
     // Arial Unicode MS has lots of glyphs for obscure characters,
     // use it as a last resort
     aFontList.AppendElement(kFontArialUnicodeMS);
 }
 
-nsresult
-gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
-{
-    gfxPlatformFontList::PlatformFontList()->GetStandardFamilyName(aFontName, aFamilyName);
-    return NS_OK;
-}
-
 gfxFontGroup *
 gfxWindowsPlatform::CreateFontGroup(const FontFamilyList& aFontFamilyList,
                                     const gfxFontStyle *aStyle,
                                     gfxTextPerfMetrics* aTextPerf,
                                     gfxUserFontSet *aUserFontSet,
                                     gfxFloat aDevToCssSize)
 {
     return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf,
                             aUserFontSet, aDevToCssSize);
 }
 
-gfxFontEntry* 
-gfxWindowsPlatform::LookupLocalFont(const nsAString& aFontName,
-                                    uint16_t aWeight,
-                                    int16_t aStretch,
-                                    uint8_t aStyle)
-{
-    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
-                                                                    aWeight,
-                                                                    aStretch,
-                                                                    aStyle);
-}
-
-gfxFontEntry* 
-gfxWindowsPlatform::MakePlatformFont(const nsAString& aFontName,
-                                     uint16_t aWeight,
-                                     int16_t aStretch,
-                                     uint8_t aStyle,
-                                     const uint8_t* aFontData,
-                                     uint32_t aLength)
-{
-    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
-                                                                     aWeight,
-                                                                     aStretch,
-                                                                     aStyle,
-                                                                     aFontData,
-                                                                     aLength);
-}
-
 bool
 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
 {
     // check for strange format flags
     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
                  "strange font format hint set");
 
     // accept supported formats
--- a/gfx/thebes/gfxWindowsPlatform.h
+++ b/gfx/thebes/gfxWindowsPlatform.h
@@ -154,53 +154,27 @@ public:
      * Verifies a D2D device is present and working, will attempt to create one
      * it is non-functional or non-existant.
      *
      * \param aAttemptForce Attempt to force D2D cairo device creation by using
      * cairo device creation routines.
      */
     void VerifyD2DDevice(bool aAttemptForce);
 
-    nsresult GetFontList(nsIAtom *aLangGroup,
-                         const nsACString& aGenericFamily,
-                         nsTArray<nsString>& aListOfFonts) override;
-
-    nsresult UpdateFontList();
-
     virtual void GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
                                         int32_t aRunScript,
                                         nsTArray<const char*>& aFontList) override;
 
-    nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override;
-
     gfxFontGroup*
     CreateFontGroup(const mozilla::FontFamilyList& aFontFamilyList,
                     const gfxFontStyle *aStyle,
                     gfxTextPerfMetrics* aTextPerf,
                     gfxUserFontSet *aUserFontSet,
                     gfxFloat aDevToCssSize) override;
 
-    /**
-     * Look up a local platform font using the full font face name (needed to support @font-face src local() )
-     */
-    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          uint16_t aWeight,
-                                          int16_t aStretch,
-                                          uint8_t aStyle) override;
-
-    /**
-     * Activate a platform font (needed to support @font-face src url() )
-     */
-    virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           uint16_t aWeight,
-                                           int16_t aStretch,
-                                           uint8_t aStyle,
-                                           const uint8_t* aFontData,
-                                           uint32_t aLength) override;
-
     virtual bool CanUseHardwareVideoDecoding() override;
 
     /**
      * Check whether format is supported on a platform or not (if unclear, returns true)
      */
     virtual bool IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags) override;
 
     bool DidRenderingDeviceReset(DeviceResetReason* aResetReason = nullptr) override;
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -470,54 +470,77 @@ GeckoChildProcessHost::SetAlreadyDead()
     base::CloseProcessHandle(mChildProcessHandle);
   }
 
   mChildProcessHandle = 0;
 }
 
 int32_t GeckoChildProcessHost::mChildCounter = 0;
 
-//
-// Wrapper function for handling GECKO_SEPARATE_NSPR_LOGS
-//
-bool
-GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, base::ProcessArchitecture arch)
+void
+GeckoChildProcessHost::SetChildLogName(const char* varName, const char* origLogName)
 {
-  // If NSPR log files are not requested, we're done.
-  const char* origLogName = PR_GetEnv("NSPR_LOG_FILE");
-  if (!origLogName) {
-    return PerformAsyncLaunchInternal(aExtraOpts, arch);
-  }
-
   // We currently have no portable way to launch child with environment
   // different than parent.  So temporarily change NSPR_LOG_FILE so child
   // inherits value we want it to have. (NSPR only looks at NSPR_LOG_FILE at
   // startup, so it's 'safe' to play with the parent's environment this way.)
-  nsAutoCString setChildLogName("NSPR_LOG_FILE=");
+  nsAutoCString setChildLogName(varName);
   setChildLogName.Append(origLogName);
 
-  // remember original value so we can restore it.
-  // - buffer needs to be permanently allocated for PR_SetEnv()
-  // - Note: this code is not called re-entrantly, nor are restoreOrigLogName
-  //   or mChildCounter touched by any other thread, so this is safe.
-  static char* restoreOrigLogName = 0;
-  if (!restoreOrigLogName)
-    restoreOrigLogName = strdup(setChildLogName.get());
-
   // Append child-specific postfix to name
   setChildLogName.AppendLiteral(".child-");
-  setChildLogName.AppendInt(++mChildCounter);
+  setChildLogName.AppendInt(mChildCounter);
 
   // Passing temporary to PR_SetEnv is ok here because env gets copied
   // by exec, etc., to permanent storage in child when process launched.
   PR_SetEnv(setChildLogName.get());
+}
+
+bool
+GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, base::ProcessArchitecture arch)
+{
+  // If NSPR log files are not requested, we're done.
+  const char* origNSPRLogName = PR_GetEnv("NSPR_LOG_FILE");
+  const char* origMozLogName = PR_GetEnv("MOZ_LOG_FILE");
+  if (!origNSPRLogName && !origMozLogName) {
+    return PerformAsyncLaunchInternal(aExtraOpts, arch);
+  }
+
+  ++mChildCounter;
+
+  // remember original value so we can restore it.
+  // - Note: this code is not called re-entrantly, nor are restoreOrig*LogName
+  //   or mChildCounter touched by any other thread, so this is safe.
+  static nsAutoCString restoreOrigNSPRLogName;
+  static nsAutoCString restoreOrigMozLogName;
+
+  if (origNSPRLogName) {
+    if (restoreOrigNSPRLogName.IsEmpty()) {
+      restoreOrigNSPRLogName.AssignLiteral("NSPR_LOG_FILE=");
+      restoreOrigNSPRLogName.Append(origNSPRLogName);
+    }
+    SetChildLogName("NSPR_LOG_FILE=", origNSPRLogName);
+  }
+  if (origMozLogName) {
+    if (restoreOrigMozLogName.IsEmpty()) {
+      restoreOrigMozLogName.AssignLiteral("MOZ_LOG_FILE=");
+      restoreOrigMozLogName.Append(origMozLogName);
+    }
+    SetChildLogName("MOZ_LOG_FILE=", origMozLogName);
+  }
+
   bool retval = PerformAsyncLaunchInternal(aExtraOpts, arch);
 
   // Revert to original value
-  PR_SetEnv(restoreOrigLogName);
+  if (origNSPRLogName) {
+    PR_SetEnv(restoreOrigNSPRLogName.get());
+  }
+  if (origMozLogName) {
+    PR_SetEnv(restoreOrigMozLogName.get());
+  }
 
   return retval;
 }
 
 bool
 GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts,
                                              base::ProcessArchitecture aArch)
 {
--- a/ipc/glue/GeckoChildProcessHost.h
+++ b/ipc/glue/GeckoChildProcessHost.h
@@ -186,16 +186,18 @@ private:
   bool PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts,
                                   base::ProcessArchitecture arch);
 
   bool RunPerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
 			     base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture());
 
   static void GetPathToBinary(FilePath& exePath);
 
+  void SetChildLogName(const char* varName, const char* origLogName);
+
   // In between launching the subprocess and handing off its IPC
   // channel, there's a small window of time in which *we* might still
   // be the channel listener, and receive messages.  That's bad
   // because we have no idea what to do with those messages.  So queue
   // them here until we hand off the eventual listener.
   //
   // FIXME/cjones: this strongly indicates bad design.  Shame on us.
   std::queue<IPC::Message> mQueue;
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -41,16 +41,18 @@
 
 #include "TestShellChild.h"
 #include "TestShellParent.h"
 
 using mozilla::ipc::XPCShellEnvironment;
 using mozilla::ipc::TestShellChild;
 using mozilla::ipc::TestShellParent;
 using mozilla::AutoSafeJSContext;
+using mozilla::dom::AutoJSAPI;
+using mozilla::dom::AutoEntryScript;
 using namespace JS;
 
 namespace {
 
 static const char kDefaultRuntimeScriptFilename[] = "xpcshell.js";
 
 class XPCShellDirProvider : public nsIDirectoryServiceProvider
 {
@@ -68,18 +70,21 @@ public:
 private:
     nsCOMPtr<nsIFile> mGREDir;
     nsCOMPtr<nsIFile> mGREBinDir;
 };
 
 inline XPCShellEnvironment*
 Environment(Handle<JSObject*> global)
 {
-    AutoSafeJSContext cx;
-    JSAutoCompartment ac(cx, global);
+    AutoJSAPI jsapi;
+    if (!jsapi.Init(global)) {
+        return nullptr;
+    }
+    JSContext* cx = jsapi.cx();
     Rooted<Value> v(cx);
     if (!JS_GetProperty(cx, global, "__XPCShellEnvironment", &v) ||
         !v.get().isDouble())
     {
         return nullptr;
     }
     return static_cast<XPCShellEnvironment*>(v.get().toPrivate());
 }
@@ -446,20 +451,24 @@ XPCShellEnvironment::CreateEnvironment()
 
 XPCShellEnvironment::XPCShellEnvironment()
 :   mQuitting(false)
 {
 }
 
 XPCShellEnvironment::~XPCShellEnvironment()
 {
+    if (GetGlobalObject()) {
+        AutoJSAPI jsapi;
+        if (!jsapi.Init(GetGlobalObject())) {
+            return;
+        }
+        JSContext* cx = jsapi.cx();
+        Rooted<JSObject*> global(cx, GetGlobalObject());
 
-    AutoSafeJSContext cx;
-    Rooted<JSObject*> global(cx, GetGlobalObject());
-    if (global) {
         {
             JSAutoCompartment ac(cx, global);
             JS_SetAllNonReservedSlotsToUndefined(cx, global);
         }
         mGlobalHolder.reset();
 
         JSRuntime *rt = JS_GetRuntime(cx);
         JS_GC(rt);
@@ -563,19 +572,19 @@ XPCShellEnvironment::Init()
 
     return true;
 }
 
 bool
 XPCShellEnvironment::EvaluateString(const nsString& aString,
                                     nsString* aResult)
 {
-  AutoSafeJSContext cx;
-  JS::Rooted<JSObject*> global(cx, GetGlobalObject());
-  JSAutoCompartment ac(cx, global);
+  AutoEntryScript aes(GetGlobalObject(),
+                      "ipc XPCShellEnvironment::EvaluateString");
+  JSContext* cx = aes.cx();
 
   JS::CompileOptions options(cx);
   options.setFileAndLine("typein", 0);
   JS::Rooted<JSScript*> script(cx);
   if (!JS_CompileUCScript(cx, aString.get(), aString.Length(), options,
                           &script))
   {
      return false;
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -42,18 +42,20 @@ function MapIteratorNext() {
     // Steps 2-3.
     if (!IsObject(O) || !IsMapIterator(O))
         return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext");
 
     // Steps 4-5 (implemented in _GetNextMapEntryForIterator).
     // Steps 8-9 (omitted).
 
     var mapIterationResultPair = iteratorTemp.mapIterationResultPair;
-    if (!mapIterationResultPair)
-        mapIterationResultPair = iteratorTemp.mapIterationResultPair = [null, null];
+    if (!mapIterationResultPair) {
+        mapIterationResultPair = iteratorTemp.mapIterationResultPair =
+            _CreateMapIterationResultPair();
+    }
 
     var retVal = {value: undefined, done: true};
 
     // Step 10.a, 11.
     var done = _GetNextMapEntryForIterator(O, mapIterationResultPair);
     if (!done) {
         // Steps 10.b-c (omitted).
 
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -181,17 +181,37 @@ MapIteratorObject::finalize(FreeOp* fop,
 {
     fop->delete_(MapIteratorObjectRange(static_cast<NativeObject*>(obj)));
 }
 
 bool
 MapIteratorObject::next(JSContext* cx, Handle<MapIteratorObject*> mapIterator,
                         HandleArrayObject resultPairObj)
 {
+    // Check invariants for inlined _GetNextMapEntryForIterator.
+
+    // The array should be tenured, so that post-barrier can be done simply.
+    MOZ_ASSERT(resultPairObj->isTenured());
+
+    // The array elements should be fixed.
+    MOZ_ASSERT(resultPairObj->hasFixedElements());
     MOZ_ASSERT(resultPairObj->getDenseInitializedLength() == 2);
+    MOZ_ASSERT(resultPairObj->getDenseCapacity() >= 2);
+
+#ifdef DEBUG
+    // The array elements should be null, so that inlined
+    // _GetNextMapEntryForIterator doesn't have to perform pre-barrier.
+    RootedValue val(cx);
+    if (!GetElement(cx, resultPairObj, resultPairObj, 0, &val))
+        return false;
+    MOZ_ASSERT(val.isNull());
+    if (!GetElement(cx, resultPairObj, resultPairObj, 1, &val))
+        return false;
+    MOZ_ASSERT(val.isNull());
+#endif
 
     ValueMap::Range* range = MapIteratorObjectRange(mapIterator);
     if (!range || range->empty()) {
         js_delete(range);
         mapIterator->setReservedSlot(RangeSlot, PrivateValue(nullptr));
         return true;
     }
     switch (mapIterator->kind()) {
@@ -208,16 +228,39 @@ MapIteratorObject::next(JSContext* cx, H
         resultPairObj->setDenseElementWithType(cx, 1, range->front().value);
         break;
       }
     }
     range->popFront();
     return false;
 }
 
+/* static */ JSObject*
+MapIteratorObject::createResultPair(JSContext* cx)
+{
+    RootedArrayObject resultPairObj(cx, NewDenseFullyAllocatedArray(cx, 2, nullptr, TenuredObject));
+    if (!resultPairObj)
+        return nullptr;
+
+    Rooted<TaggedProto> proto(cx, resultPairObj->getTaggedProto());
+    ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultPairObj->getClass(), proto);
+    if (!group)
+        return nullptr;
+    resultPairObj->setGroup(group);
+
+    resultPairObj->setDenseInitializedLength(2);
+    resultPairObj->initDenseElement(0, NullValue());
+    resultPairObj->initDenseElement(1, NullValue());
+
+    // See comments in MapIteratorObject::next.
+    AddTypePropertyId(cx, resultPairObj, JSID_VOID, TypeSet::UnknownType());
+
+    return resultPairObj;
+}
+
 
 /*** Map *****************************************************************************************/
 
 const Class MapObject::class_ = {
     "Map",
     JSCLASS_HAS_PRIVATE |
     JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
     nullptr, // addProperty
--- a/js/src/builtin/MapObject.h
+++ b/js/src/builtin/MapObject.h
@@ -159,16 +159,18 @@ class MapIteratorObject : public NativeO
     static const JSFunctionSpec methods[];
     static MapIteratorObject* create(JSContext* cx, HandleObject mapobj, ValueMap* data,
                                      MapObject::IteratorKind kind);
     static void finalize(FreeOp* fop, JSObject* obj);
 
     static bool next(JSContext* cx, Handle<MapIteratorObject*> mapIterator,
                      HandleArrayObject resultPairObj);
 
+    static JSObject* createResultPair(JSContext* cx);
+
   private:
     inline MapObject::IteratorKind kind() const;
 };
 
 class SetObject : public NativeObject {
   public:
     enum IteratorKind { Values, Entries };
     static JSObject* initClass(JSContext* cx, JSObject* obj);
--- a/js/src/ds/OrderedHashTable.h
+++ b/js/src/ds/OrderedHashTable.h
@@ -279,54 +279,56 @@ class OrderedHashTable
      *         r.popFront();
      *         // ...do things that might modify map...
      *     }
      */
     class Range
     {
         friend class OrderedHashTable;
 
-        OrderedHashTable& ht;
+        // Cannot be a reference since we need to be able to do
+        // |offsetof(Range, ht)|.
+        OrderedHashTable* ht;
 
-        /* The index of front() within ht.data. */
+        /* The index of front() within ht->data. */
         uint32_t i;
 
         /*
-         * The number of nonempty entries in ht.data to the left of front().
+         * The number of nonempty entries in ht->data to the left of front().
          * This is used when the table is resized or compacted.
          */
         uint32_t count;
 
         /*
          * Links in the doubly-linked list of active Ranges on ht.
          *
          * prevp points to the previous Range's .next field;
-         *   or to ht.ranges if this is the first Range in the list.
+         *   or to ht->ranges if this is the first Range in the list.
          * next points to the next Range;
          *   or nullptr if this is the last Range in the list.
          *
          * Invariant: *prevp == this.
          */
         Range** prevp;
         Range* next;
 
         /*
          * Create a Range over all the entries in ht.
-         * (This is private on purpose. End users must use ht.all().)
+         * (This is private on purpose. End users must use ht->all().)
          */
-        explicit Range(OrderedHashTable& ht) : ht(ht), i(0), count(0), prevp(&ht.ranges), next(ht.ranges) {
+        explicit Range(OrderedHashTable* ht) : ht(ht), i(0), count(0), prevp(&ht->ranges), next(ht->ranges) {
             *prevp = this;
             if (next)
                 next->prevp = &next;
             seek();
         }
 
       public:
         Range(const Range& other)
-            : ht(other.ht), i(other.i), count(other.count), prevp(&ht.ranges), next(ht.ranges)
+            : ht(other.ht), i(other.i), count(other.count), prevp(&ht->ranges), next(ht->ranges)
         {
             *prevp = this;
             if (next)
                 next->prevp = &next;
         }
 
         ~Range() {
             *prevp = next;
@@ -334,17 +336,17 @@ class OrderedHashTable
                 next->prevp = prevp;
         }
 
       private:
         // Prohibit copy assignment.
         Range& operator=(const Range& other) = delete;
 
         void seek() {
-            while (i < ht.dataLength && Ops::isEmpty(Ops::getKey(ht.data[i].element)))
+            while (i < ht->dataLength && Ops::isEmpty(Ops::getKey(ht->data[i].element)))
                 i++;
         }
 
         /*
          * The hash table calls this when an entry is removed.
          * j is the index of the removed entry.
          */
         void onRemove(uint32_t j) {
@@ -380,91 +382,107 @@ class OrderedHashTable
             MOZ_ASSERT(valid());
             prevp = &next;
             next = this;
         }
 
       public:
         bool empty() const {
             MOZ_ASSERT(valid());
-            return i >= ht.dataLength;
+            return i >= ht->dataLength;
         }
 
         /*
          * Return the first element in the range. This must not be called if
          * this->empty().
          *
          * Warning: Removing an entry from the table also removes it from any
          * live Ranges, and a Range can become empty that way, rendering
          * front() invalid. If in doubt, check empty() before calling front().
          */
         T& front() {
             MOZ_ASSERT(valid());
             MOZ_ASSERT(!empty());
-            return ht.data[i].element;
+            return ht->data[i].element;
         }
 
         /*
          * Remove the first element from this range.
          * This must not be called if this->empty().
          *
          * Warning: Removing an entry from the table also removes it from any
          * live Ranges, and a Range can become empty that way, rendering
          * popFront() invalid. If in doubt, check empty() before calling
          * popFront().
          */
         void popFront() {
             MOZ_ASSERT(valid());
             MOZ_ASSERT(!empty());
-            MOZ_ASSERT(!Ops::isEmpty(Ops::getKey(ht.data[i].element)));
+            MOZ_ASSERT(!Ops::isEmpty(Ops::getKey(ht->data[i].element)));
             count++;
             i++;
             seek();
         }
 
         /*
          * Change the key of the front entry.
          *
          * This calls Ops::hash on both the current key and the new key.
          * Ops::hash on the current key must return the same hash code as
          * when the entry was added to the table.
          */
         void rekeyFront(const Key& k) {
             MOZ_ASSERT(valid());
-            Data& entry = ht.data[i];
-            HashNumber oldHash = prepareHash(Ops::getKey(entry.element)) >> ht.hashShift;
-            HashNumber newHash = prepareHash(k) >> ht.hashShift;
+            Data& entry = ht->data[i];
+            HashNumber oldHash = prepareHash(Ops::getKey(entry.element)) >> ht->hashShift;
+            HashNumber newHash = prepareHash(k) >> ht->hashShift;
             Ops::setKey(entry.element, k);
             if (newHash != oldHash) {
                 // Remove this entry from its old hash chain. (If this crashes
                 // reading nullptr, it would mean we did not find this entry on
                 // the hash chain where we expected it. That probably means the
                 // key's hash code changed since it was inserted, breaking the
                 // hash code invariant.)
-                Data** ep = &ht.hashTable[oldHash];
+                Data** ep = &ht->hashTable[oldHash];
                 while (*ep != &entry)
                     ep = &(*ep)->chain;
                 *ep = entry.chain;
 
                 // Add it to the new hash chain. We could just insert it at the
                 // beginning of the chain. Instead, we do a bit of work to
                 // preserve the invariant that hash chains always go in reverse
                 // insertion order (descending memory order). No code currently
                 // depends on this invariant, so it's fine to kill it if
                 // needed.
-                ep = &ht.hashTable[newHash];
+                ep = &ht->hashTable[newHash];
                 while (*ep && *ep > &entry)
                     ep = &(*ep)->chain;
                 entry.chain = *ep;
                 *ep = &entry;
             }
         }
+
+        static size_t offsetOfHashTable() {
+            return offsetof(Range, ht);
+        }
+        static size_t offsetOfI() {
+            return offsetof(Range, i);
+        }
+        static size_t offsetOfCount() {
+            return offsetof(Range, count);
+        }
+        static size_t offsetOfPrevP() {
+            return offsetof(Range, prevp);
+        }
+        static size_t offsetOfNext() {
+            return offsetof(Range, next);
+        }
     };
 
-    Range all() { return Range(*this); }
+    Range all() { return Range(this); }
 
     /*
      * Change the value of the given key.
      *
      * This calls Ops::hash on both the current key and the new key.
      * Ops::hash on the current key must return the same hash code as
      * when the entry was added to the table.
      */
@@ -499,16 +517,28 @@ class OrderedHashTable
         // needed.
         ep = &hashTable[newHash];
         while (*ep && *ep > entry)
             ep = &(*ep)->chain;
         entry->chain = *ep;
         *ep = entry;
     }
 
+    static size_t offsetOfDataLength() {
+        return offsetof(OrderedHashTable, dataLength);
+    }
+    static size_t offsetOfData() {
+        return offsetof(OrderedHashTable, data);
+    }
+#ifdef DEBUG
+    static size_t sizeofData() {
+        return sizeof(Data);
+    }
+#endif
+
   private:
     /* Logarithm base 2 of the number of buckets in the hash table initially. */
     static uint32_t initialBucketsLog2() { return 1; }
     static uint32_t initialBuckets() { return 1 << initialBucketsLog2(); }
 
     /*
      * The maximum load factor (mean number of entries per bucket).
      * It is an invariant that
@@ -673,16 +703,23 @@ class OrderedHashMap
       public:
         Entry() : key(), value() {}
         template <typename V>
         Entry(const Key& k, V&& v) : key(k), value(Forward<V>(v)) {}
         Entry(Entry&& rhs) : key(Move(rhs.key)), value(Move(rhs.value)) {}
 
         const Key key;
         Value value;
+
+        static size_t offsetOfKey() {
+            return offsetof(Entry, key);
+        }
+        static size_t offsetOfValue() {
+            return offsetof(Entry, value);
+        }
     };
 
   private:
     struct MapOps : OrderedHashPolicy
     {
         typedef Key KeyType;
         static void makeEmpty(Entry* e) {
             OrderedHashPolicy::makeEmpty(const_cast<Key*>(&e->key));
@@ -717,16 +754,28 @@ class OrderedHashMap
     }
 
     void rekeyOneEntry(const Key& current, const Key& newKey) {
         const Entry* e = get(current);
         if (!e)
             return;
         return impl.rekeyOneEntry(current, newKey, Entry(newKey, e->value));
     }
+
+    static size_t offsetOfImplDataLength() {
+        return Impl::offsetOfDataLength();
+    }
+    static size_t offsetOfImplData() {
+        return Impl::offsetOfData();
+    }
+#ifdef DEBUG
+    static size_t sizeofImplData() {
+        return Impl::sizeofData();
+    }
+#endif
 };
 
 template <class T, class OrderedHashPolicy, class AllocPolicy>
 class OrderedHashSet
 {
   private:
     struct SetOps : OrderedHashPolicy
     {
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -6385,21 +6385,26 @@ BytecodeEmitter::emitFunction(ParseNode*
      */
     if (fun->isInterpreted()) {
         bool singleton = checkRunOnceContext();
         if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton))
             return false;
 
         SharedContext* outersc = sc;
         if (fun->isInterpretedLazy()) {
-            if (!fun->lazyScript()->sourceObject()) {
-                JSObject* scope = innermostStaticScope();
-                JSObject* source = script->sourceObject();
-                fun->lazyScript()->setParent(scope, &source->as<ScriptSourceObject>());
-            }
+            // We need to update the static scope chain regardless of whether
+            // the LazyScript has already been initialized, due to the case
+            // where we previously successfully compiled an inner function's
+            // lazy script but failed to compile the outer script after the
+            // fact. If we attempt to compile the outer script again, the
+            // static scope chain will be newly allocated and will mismatch
+            // the previously compiled LazyScript's.
+            ScriptSourceObject* source = &script->sourceObject()->as<ScriptSourceObject>();
+            JSObject* scope = innermostStaticScope();
+            fun->lazyScript()->setEnclosingScopeAndSource(scope, source);
             if (emittingRunOnceLambda)
                 fun->lazyScript()->setTreatAsRunOnce();
         } else {
 
             if (outersc->isFunctionBox() && outersc->asFunctionBox()->mightAliasLocals())
                 funbox->setMightAliasLocals();      // inherit mightAliasLocals from parent
             MOZ_ASSERT_IF(outersc->strict(), funbox->strictScript);
 
--- a/js/src/gc/Barrier.cpp
+++ b/js/src/gc/Barrier.cpp
@@ -18,31 +18,16 @@
 #include "vm/ScopeObject.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/Symbol.h"
 
 namespace js {
 
 #ifdef DEBUG
 
-template <typename T>
-void
-BarrieredBase<T>::assertTypeConstraints() const
-{
-    static_assert(mozilla::IsBaseOf<gc::Cell, typename mozilla::RemovePointer<T>::Type>::value ||
-                  mozilla::IsSame<JS::Value, T>::value ||
-                  mozilla::IsSame<jsid, T>::value ||
-                  mozilla::IsSame<TaggedProto, T>::value,
-                  "ensure only supported types are instantiated with barriers");
-}
-#define INSTANTIATE_ALL_VALID_TYPES(type) \
-    template void BarrieredBase<type>::assertTypeConstraints() const;
-FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TYPES)
-#undef INSTANTIATE_ALL_VALID_TYPES
-
 bool
 HeapSlot::preconditionForSet(NativeObject* owner, Kind kind, uint32_t slot)
 {
     return kind == Slot
          ? &owner->getSlotRef(slot) == this
          : &owner->getDenseElement(slot) == (const Value*)this;
 }
 
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -168,16 +168,21 @@
  *      -> T::writeBarrierPost
  *  -> InternalBarrierMethods<Value>::postBarrier
  *      -> StoreBuffer::put
  *
  * These classes are designed to be used by the internals of the JS engine.
  * Barriers designed to be used externally are provided in js/RootingAPI.h.
  * These external barriers call into the same post-barrier implementations at
  * InternalBarrierMethods<T>::post via an indirect call to Heap(.+)Barrier.
+ *
+ * These clases are designed to be used to wrap GC thing pointers or values that
+ * act like them (i.e. JS::Value and jsid).  It is possible to use them for
+ * other types by supplying the necessary barrier implementations but this
+ * is not usually necessary and should be done with caution.
  */
 
 class JSAtom;
 struct JSCompartment;
 class JSFlatString;
 class JSLinearString;
 
 namespace JS {
@@ -317,40 +322,29 @@ template <typename T>
 class BarrieredBaseMixins {};
 
 // Base class of all barrier types.
 template <typename T>
 class BarrieredBase : public BarrieredBaseMixins<T>
 {
   protected:
     // BarrieredBase is not directly instantiable.
-    explicit BarrieredBase(T v) : value(v) {
-#ifdef DEBUG
-        assertTypeConstraints();
-#endif
-    }
+    explicit BarrieredBase(T v) : value(v) {}
 
     // Storage for all barrier classes. |value| must be a GC thing reference
     // type: either a direct pointer to a GC thing or a supported tagged
     // pointer that can reference GC things, such as JS::Value or jsid. Nested
     // barrier types are NOT supported. See assertTypeConstraints.
     T value;
 
   public:
     // Note: this is public because C++ cannot friend to a specific template instantiation.
     // Friending to the generic template leads to a number of unintended consequences, including
     // template resolution ambiguity and a circular dependency with Tracing.h.
     T* unsafeUnbarrieredForTracing() { return &value; }
-
-  private:
-#ifdef DEBUG
-    // Static type assertions about T must be moved out of line to avoid
-    // circular dependencies between Barrier classes and GC memory definitions.
-    void assertTypeConstraints() const;
-#endif
 };
 
 // Base class for barriered pointer types that intercept only writes.
 template <class T>
 class WriteBarrieredBase : public BarrieredBase<T>
 {
   protected:
     // WriteBarrieredBase is not directly instantiable.
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -957,18 +957,17 @@ class GCRuntime
     bool shouldCompact();
     void beginCompactPhase();
     IncrementalProgress compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget);
     void endCompactPhase(JS::gcreason::Reason reason);
     void sweepTypesAfterCompacting(Zone* zone);
     void sweepZoneAfterCompacting(Zone* zone);
     bool relocateArenas(Zone* zone, JS::gcreason::Reason reason, Arena*& relocatedListOut,
                         SliceBudget& sliceBudget);
-    void updateAllCellPointersParallel(MovingTracer* trc, Zone* zone);
-    void updateAllCellPointersSerial(MovingTracer* trc, Zone* zone);
+    void updateAllCellPointers(MovingTracer* trc, Zone* zone);
     void updatePointersToRelocatedCells(Zone* zone);
     void protectAndHoldArenas(Arena* arenaList);
     void unprotectHeldRelocatedArenas();
     void releaseRelocatedArenas(Arena* arenaList);
     void releaseRelocatedArenasWithoutUnlocking(Arena* arenaList, const AutoLockGC& lock);
     void finishCollection(JS::gcreason::Reason reason);
 
     void computeNonIncrementalMarkingForValidation();
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -643,30 +643,16 @@ class Arena
     }
 
     void unsetAllocDuringSweep() {
         MOZ_ASSERT(allocatedDuringIncremental);
         allocatedDuringIncremental = 0;
         auxNextLink = 0;
     }
 
-    Arena* getNextArenaToUpdateAndUnlink() {
-        MOZ_ASSERT(!hasDelayedMarking && !allocatedDuringIncremental && !markOverflow);
-        Arena* next = reinterpret_cast<Arena*>(auxNextLink << ArenaShift);
-        auxNextLink = 0;
-        return next;
-    }
-
-    void setNextArenaToUpdate(Arena* arena) {
-        MOZ_ASSERT(!(uintptr_t(arena) & ArenaMask));
-        MOZ_ASSERT(!hasDelayedMarking && !allocatedDuringIncremental && !markOverflow);
-        MOZ_ASSERT(!auxNextLink);
-        auxNextLink = arena->address() >> ArenaShift;
-    }
-
     template <typename T>
     size_t finalize(FreeOp* fop, AllocKind thingKind, size_t thingSize);
 
     static void staticAsserts();
 
     void unmarkAll();
 };
 
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -331,23 +331,25 @@ Statistics::formatCompactSliceMessage() 
 
     const size_t index = slices.length() - 1;
     const SliceData& slice = slices[index];
 
     char budgetDescription[200];
     slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
 
     const char* format =
-        "GC Slice %u - Pause: %.3fms of %s budget (@ %.3fms); Reason: %s; Reset: %s%s; Times: ";
+        "GC Slice %u - Pause: %.3fms of %s budget (@ %.3fms); Reason: %s; Reset: %s%s; Cycles: %u "
+        "Times: ";
     char buffer[1024];
     memset(buffer, 0, sizeof(buffer));
     JS_snprintf(buffer, sizeof(buffer), format, index,
                 t(slice.duration()), budgetDescription, t(slice.start - slices[0].start),
                 ExplainReason(slice.reason),
-                slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "");
+                slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "",
+                slice.cycleCount);
 
     FragmentVector fragments;
     if (!fragments.append(DuplicateString(buffer)) ||
         !fragments.append(formatCompactSlicePhaseTimes(slices[index].phaseTimes)))
     {
         return UniqueChars(nullptr);
     }
     return Join(fragments);
@@ -512,26 +514,30 @@ Statistics::formatDetailedSliceDescripti
     char budgetDescription[200];
     slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
 
     const char* format =
 "\
   ---- Slice %u ----\n\
     Reason: %s\n\
     Reset: %s%s\n\
+    State: %s -> %s\n\
     Page Faults: %ld\n\
     Pause: %.3fms of %s budget (@ %.3fms)\n\
+    Cycles: %u\n\
 ";
     char buffer[1024];
     memset(buffer, 0, sizeof(buffer));
     JS_snprintf(buffer, sizeof(buffer), format, i,
                 ExplainReason(slice.reason),
                 slice.resetReason ? "yes - " : "no", slice.resetReason ? slice.resetReason : "",
+                gc::StateName(slice.initialState), gc::StateName(slice.finalState),
                 uint64_t(slice.endFaults - slice.startFaults),
-                t(slice.duration()), budgetDescription, t(slice.start - slices[0].start));
+                t(slice.duration()), budgetDescription, t(slice.start - slices[0].start),
+                slice.cycleCount);
     return DuplicateString(buffer);
 }
 
 UniqueChars
 Statistics::formatDetailedPhaseTimes(const PhaseTimeTable phaseTimes)
 {
     static const char* LevelToIndent[] = { "", "  ", "    ", "      " };
     static const int64_t MaxUnaccountedChildTimeUS = 50;
@@ -668,42 +674,48 @@ Statistics::formatJsonDescription(uint64
                 counts[STAT_NEW_CHUNK],
                 counts[STAT_DESTROY_CHUNK]);
     return DuplicateString(buffer);
 }
 
 UniqueChars
 Statistics::formatJsonSliceDescription(unsigned i, const SliceData& slice)
 {
-    int64_t duration = slices[i].duration();
-    int64_t when = slices[i].start - slices[0].start;
+    int64_t duration = slice.duration();
+    int64_t when = slice.start - slices[0].start;
     char budgetDescription[200];
     slice.budget.describe(budgetDescription, sizeof(budgetDescription) - 1);
-    int64_t pageFaults = slices[i].endFaults - slices[i].startFaults;
+    int64_t pageFaults = slice.endFaults - slice.startFaults;
 
     const char* format =
         "\"slice\":%d,"
         "\"pause\":%llu.%03llu,"
         "\"when\":%llu.%03llu,"
         "\"reason\":\"%s\","
+        "\"initial_state\":\"%s\","
+        "\"final_state\":\"%s\","
         "\"budget\":\"%s\","
         "\"page_faults\":%llu,"
         "\"start_timestamp\":%llu,"
-        "\"end_timestamp\":%llu,";
+        "\"end_timestamp\":%llu,"
+        "\"cycle_count\":%u,";
     char buffer[1024];
     memset(buffer, 0, sizeof(buffer));
     JS_snprintf(buffer, sizeof(buffer), format,
                 i,
                 duration / 1000, duration % 1000,
                 when / 1000, when % 1000,
-                ExplainReason(slices[i].reason),
+                ExplainReason(slice.reason),
+                gc::StateName(slice.initialState),
+                gc::StateName(slice.finalState),
                 budgetDescription,
                 pageFaults,
-                slices[i].start,
-                slices[i].end);
+                slice.start,
+                slice.end,
+                slice.cycleCount);
     return DuplicateString(buffer);
 }
 
 UniqueChars
 FilterJsonKey(const char*const buffer)
 {
     char* mut = strdup(buffer);
     char* c = mut;
@@ -969,17 +981,18 @@ Statistics::beginSlice(const ZoneGCStats
 {
     gcDepth++;
     this->zoneStats = zoneStats;
 
     bool first = !runtime->gc.isIncrementalGCInProgress();
     if (first)
         beginGC(gckind);
 
-    SliceData data(budget, reason, PRMJ_Now(), JS_GetCurrentEmbedderTime(), GetPageFaultCount());
+    SliceData data(budget, reason, PRMJ_Now(), JS_GetCurrentEmbedderTime(), GetPageFaultCount(),
+                   runtime->gc.state());
     if (!slices.append(data)) {
         // If we are OOM, set a flag to indicate we have missing slice data.
         aborted = true;
         return;
     }
 
     runtime->addTelemetry(JS_TELEMETRY_GC_REASON, reason);
 
@@ -994,16 +1007,17 @@ Statistics::beginSlice(const ZoneGCStats
 
 void
 Statistics::endSlice()
 {
     if (!aborted) {
         slices.back().end = PRMJ_Now();
         slices.back().endTimestamp = JS_GetCurrentEmbedderTime();
         slices.back().endFaults = GetPageFaultCount();
+        slices.back().finalState = runtime->gc.state();
 
         int64_t sliceTime = slices.back().end - slices.back().start;
         runtime->addTelemetry(JS_TELEMETRY_GC_SLICE_MS, t(sliceTime));
         runtime->addTelemetry(JS_TELEMETRY_GC_RESET, !!slices.back().resetReason);
 
         if (slices.back().budget.isTimeBudget()) {
             int64_t budget_ms = slices.back().budget.timeBudget.budget;
             runtime->addTelemetry(JS_TELEMETRY_GC_BUDGET_MS, budget_ms);
@@ -1033,16 +1047,23 @@ Statistics::endSlice()
     /* Do this after the slice callback since it uses these values. */
     if (last)
         PodArrayZero(counts);
 
     gcDepth--;
     MOZ_ASSERT(gcDepth >= 0);
 }
 
+void
+Statistics::setSliceCycleCount(unsigned cycleCount)
+{
+    if (!aborted)
+        slices.back().cycleCount = cycleCount;
+}
+
 bool
 Statistics::startTimingMutator()
 {
     if (phaseNestingDepth != 0) {
         // Should only be called from outside of GC.
         MOZ_ASSERT(phaseNestingDepth == 1);
         MOZ_ASSERT(phaseNesting[0] == PHASE_MUTATOR);
         return false;
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -167,16 +167,17 @@ struct Statistics
 
     void beginPhase(Phase phase);
     void endPhase(Phase phase);
     void endParallelPhase(Phase phase, const GCParallelTask* task);
 
     void beginSlice(const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
                     SliceBudget budget, JS::gcreason::Reason reason);
     void endSlice();
+    void setSliceCycleCount(unsigned cycleCount);
 
     bool startTimingMutator();
     bool stopTimingMutator(double& mutator_ms, double& gc_ms);
 
     void reset(const char* reason) {
         if (!aborted)
             slices.back().resetReason = reason;
     }
@@ -230,33 +231,38 @@ struct Statistics
             return phaseNesting[0] == PHASE_MUTATOR ? PHASE_NONE : phaseNesting[0];
         return phaseNesting[phaseNestingDepth - 1];
     }
 
     static const size_t MAX_NESTING = 20;
 
     struct SliceData {
         SliceData(SliceBudget budget, JS::gcreason::Reason reason, int64_t start,
-                  double startTimestamp, size_t startFaults)
+                  double startTimestamp, size_t startFaults, gc::State initialState)
           : budget(budget), reason(reason),
+            initialState(initialState),
+            finalState(gc::NO_INCREMENTAL),
             resetReason(nullptr),
             start(start), startTimestamp(startTimestamp),
-            startFaults(startFaults)
+            startFaults(startFaults),
+            cycleCount(0)
         {
             for (auto i : mozilla::MakeRange(NumTimingArrays))
                 mozilla::PodArrayZero(phaseTimes[i]);
         }
 
         SliceBudget budget;
         JS::gcreason::Reason reason;
+        gc::State initialState, finalState;
         const char* resetReason;
         int64_t start, end;
         double startTimestamp, endTimestamp;
         size_t startFaults, endFaults;
         PhaseTimeTable phaseTimes;
+        unsigned cycleCount;
 
         int64_t duration() const { return end - start; }
     };
 
     typedef Vector<SliceData, 8, SystemAllocPolicy> SliceDataVector;
     typedef SliceDataVector::ConstRange SliceRange;
 
     SliceRange sliceRange() const { return slices.all(); }
@@ -360,16 +366,20 @@ struct MOZ_RAII AutoGCSlice
     AutoGCSlice(Statistics& stats, const ZoneGCStats& zoneStats, JSGCInvocationKind gckind,
                 SliceBudget budget, JS::gcreason::Reason reason)
       : stats(stats)
     {
         stats.beginSlice(zoneStats, gckind, budget, reason);
     }
     ~AutoGCSlice() { stats.endSlice(); }
 
+    void setCycleCount(unsigned cycleCount) {
+        stats.setSliceCycleCount(cycleCount);
+    }
+
     Statistics& stats;
 };
 
 struct MOZ_RAII AutoPhase
 {
     AutoPhase(Statistics& stats, Phase phase)
       : stats(stats), task(nullptr), phase(phase), enabled(true)
     {
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -144,16 +144,18 @@ JS::TraceIncomingCCWs(JSTracer* trc, con
                 // across zones multiple times, and don't hold a strong
                 // reference.
                 continue;
 
               case CrossCompartmentKey::ObjectWrapper:
               case CrossCompartmentKey::DebuggerObject:
               case CrossCompartmentKey::DebuggerSource:
               case CrossCompartmentKey::DebuggerEnvironment:
+              case CrossCompartmentKey::DebuggerWasmScript:
+              case CrossCompartmentKey::DebuggerWasmSource:
                 obj = static_cast<JSObject*>(key.wrapped);
                 // Ignore CCWs whose wrapped value doesn't live in our given
                 // set of zones.
                 if (!compartments.has(obj->compartment()))
                     continue;
 
                 TraceManuallyBarrieredEdge(trc, &obj, "cross-compartment wrapper");
                 MOZ_ASSERT(obj == key.wrapped);
--- a/js/src/gdb/tests/test-Interpreter.cpp
+++ b/js/src/gdb/tests/test-Interpreter.cpp
@@ -67,26 +67,26 @@ FRAGMENT(Interpreter, Regs) {
   breakpoint();
 
   (void) regs;
 }
 
 FRAGMENT(Interpreter, AbstractFramePtr) {
 
     js::AbstractFramePtr sfidptr;
-    GDBTestInitAbstractFramePtr(sfidptr, (js::ScriptFrameIter::Data*) 0xdeeb0);
+    GDBTestInitAbstractFramePtr(sfidptr, (js::ScriptFrameIter::Data*) uintptr_t(0xdeeb0));
 
     js::AbstractFramePtr ifptr;
-    GDBTestInitAbstractFramePtr(ifptr, (js::InterpreterFrame*) 0x8badf00);
+    GDBTestInitAbstractFramePtr(ifptr, (js::InterpreterFrame*) uintptr_t(0x8badf00));
 
     js::AbstractFramePtr bfptr;
-    GDBTestInitAbstractFramePtr(bfptr, (js::jit::BaselineFrame*) 0xbadcafe0);
+    GDBTestInitAbstractFramePtr(bfptr, (js::jit::BaselineFrame*) uintptr_t(0xbadcafe0));
 
     js::AbstractFramePtr rfptr;
-    GDBTestInitAbstractFramePtr(rfptr, (js::jit::RematerializedFrame*) 0xdabbad00);
+    GDBTestInitAbstractFramePtr(rfptr, (js::jit::RematerializedFrame*) uintptr_t(0xdabbad00));
 
     breakpoint();
 
     (void) sfidptr;
     (void) ifptr;
     (void) bfptr;
     (void) rfptr;
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1240502.js
@@ -0,0 +1,3 @@
+if (!('oomTest' in this))
+    quit();
+oomTest(() => eval(`Array(..."ABC")`));
--- a/js/src/jit-test/tests/debug/Frame-eval-25.js
+++ b/js/src/jit-test/tests/debug/Frame-eval-25.js
@@ -1,17 +1,25 @@
-// |jit-test| error: TypeError
-//
 // Make sure we can recover missing arguments even when it gets assigned to
 // another slot.
 
+load(libdir + "asserts.js");
 load(libdir + "evalInFrame.js");
 
 function h() {
   evalInFrame(1, "a.push(0)");
 }
 
 function f() {
   var a = arguments;
   h();
 }
 
-f();
+assertThrowsInstanceOf(f, TypeError);
+
+function g() {
+  {
+    let a = arguments;
+    h();
+  }
+}
+
+assertThrowsInstanceOf(g, TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1257045.js
@@ -0,0 +1,11 @@
+if (!wasmIsSupported())
+  quit();
+
+fullcompartmentchecks(true);
+var g = newGlobal();
+var dbg = new Debugger(g);
+dbg.onNewScript = (function(script) {
+    s = script;
+})
+g.eval(`Wasm.instantiateModule(wasmTextToBinary('(module (func) (export "" 0))'));`);
+s.source;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1238555.js
@@ -0,0 +1,12 @@
+if (!('oomTest' in this))
+  quit();
+
+oomTest(
+  function x() {
+    try {
+      eval('let ')
+    } catch (ex) {
+      (function() {})()
+    }
+  }
+);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parser/bug-1254164.js
@@ -0,0 +1,6 @@
+// |jit-test| slow;
+
+var s = '';
+for (var i = 0; i < 70000; i++)
+    s += 'function x' + i + '() { x' + i + '(); }\n';
+eval("(function() { " + s + " })();");
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3099,46 +3099,64 @@ class OutOfLineCallPostWriteBarrier : pu
     LInstruction* lir() const {
         return lir_;
     }
     const LAllocation* object() const {
         return object_;
     }
 };
 
-void
-CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool)
-{
-    saveLiveVolatile(ool->lir());
-
-    const LAllocation* obj = ool->object();
-
+static void
+EmitPostWriteBarrier(MacroAssembler& masm, Register objreg, bool isGlobal,
+                     AllocatableGeneralRegisterSet regs)
+{
+    Register runtimereg = regs.takeAny();
+    masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
+
+    void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
+    masm.setupUnalignedABICall(regs.takeAny());
+    masm.passABIArg(runtimereg);
+    masm.passABIArg(objreg);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
+}
+
+void
+CodeGenerator::emitPostWriteBarrier(const LAllocation* obj)
+{
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
 
     Register objreg;
     bool isGlobal = false;
     if (obj->isConstant()) {
         JSObject* object = &obj->toConstant()->toObject();
         isGlobal = object->is<GlobalObject>();
         objreg = regs.takeAny();
         masm.movePtr(ImmGCPtr(object), objreg);
     } else {
         objreg = ToRegister(obj);
         regs.takeUnchecked(objreg);
     }
 
-    Register runtimereg = regs.takeAny();
-    masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
-
-    void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
-    masm.setupUnalignedABICall(regs.takeAny());
-    masm.passABIArg(runtimereg);
-    masm.passABIArg(objreg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
-
+    EmitPostWriteBarrier(masm, objreg, isGlobal, regs);
+}
+
+void
+CodeGenerator::emitPostWriteBarrier(Register objreg)
+{
+    AllocatableGeneralRegisterSet regs(GeneralRegisterSet::Volatile());
+    regs.takeUnchecked(objreg);
+    EmitPostWriteBarrier(masm, objreg, false, regs);
+}
+
+void
+CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool)
+{
+    saveLiveVolatile(ool->lir());
+    const LAllocation* obj = ool->object();
+    emitPostWriteBarrier(obj);
     restoreLiveVolatile(ool->lir());
 
     masm.jump(ool->rejoin());
 }
 
 template <class LPostBarrierType>
 void
 CodeGenerator::visitPostWriteBarrierCommonO(LPostBarrierType* lir, OutOfLineCode* ool)
@@ -5650,16 +5668,144 @@ CodeGenerator::visitSetArrayLength(LSetA
     RegisterOrInt32Constant newLength = ToRegisterOrInt32Constant(lir->index());
 
     masm.inc32(&newLength);
     masm.store32(newLength, length);
     // Restore register value if it is used/captured after.
     masm.dec32(&newLength);
 }
 
+static inline void
+ValueMapRangeFront(MacroAssembler& masm, Register range, Register i, Register front)
+{
+    masm.loadPtr(Address(range, ValueMap::Range::offsetOfHashTable()), front);
+    masm.loadPtr(Address(front, ValueMap::offsetOfImplData()), front);
+
+    MOZ_ASSERT(ValueMap::sizeofImplData() == 24);
+    masm.mulBy3(i, i);
+    masm.lshiftPtr(Imm32(3), i);
+    masm.addPtr(i, front);
+}
+
+static inline void
+ValueMapRangePopFront(MacroAssembler& masm, Register range, Register front, Register dataLength,
+                      Register temp)
+{
+    Register i = temp;
+
+    masm.add32(Imm32(1), Address(range, ValueMap::Range::offsetOfCount()));
+
+    masm.load32(Address(range, ValueMap::Range::offsetOfI()), i);
+    masm.add32(Imm32(1), i);
+
+    Label done, seek;
+    masm.bind(&seek);
+    masm.branch32(Assembler::AboveOrEqual, i, dataLength, &done);
+
+    MOZ_ASSERT(ValueMap::sizeofImplData() == 24);
+    masm.addPtr(Imm32(24), front);
+
+    masm.branchTestMagic(Assembler::NotEqual, Address(front, ValueMap::Entry::offsetOfKey()),
+                         JS_HASH_KEY_EMPTY, &done);
+
+    masm.add32(Imm32(1), i);
+    masm.jump(&seek);
+
+    masm.bind(&done);
+    masm.store32(i, Address(range, ValueMap::Range::offsetOfI()));
+}
+
+static inline void
+ValueMapRangeDestruct(MacroAssembler& masm, Register range, Register temp0, Register temp1)
+{
+    Register next = temp0;
+    Register prevp = temp1;
+
+    masm.loadPtr(Address(range, ValueMap::Range::offsetOfNext()), next);
+    masm.loadPtr(Address(range, ValueMap::Range::offsetOfPrevP()), prevp);
+    masm.storePtr(next, Address(prevp, 0));
+
+    Label hasNoNext;
+    masm.branchTestPtr(Assembler::Zero, next, next, &hasNoNext);
+
+    masm.storePtr(prevp, Address(next, ValueMap::Range::offsetOfPrevP()));
+
+    masm.bind(&hasNoNext);
+
+    masm.callFreeStub(range);
+}
+
+void
+CodeGenerator::visitGetNextMapEntryForIterator(LGetNextMapEntryForIterator* lir)
+{
+    Register iter = ToRegister(lir->iter());
+    Register result = ToRegister(lir->result());
+    Register temp = ToRegister(lir->temp0());
+    Register dataLength = ToRegister(lir->temp1());
+    Register range = ToRegister(lir->temp2());
+    Register output = ToRegister(lir->output());
+
+    masm.loadPrivate(Address(iter, NativeObject::getFixedSlotOffset(MapIteratorObject::RangeSlot)),
+                     range);
+
+    Label iterDone, done;
+    masm.branchTestPtr(Assembler::Zero, range, range, &iterDone);
+
+    masm.load32(Address(range, ValueMap::Range::offsetOfI()), temp);
+    masm.loadPtr(Address(range, ValueMap::Range::offsetOfHashTable()), dataLength);
+    masm.load32(Address(dataLength, ValueMap::offsetOfImplDataLength()), dataLength);
+    masm.branch32(Assembler::AboveOrEqual, temp, dataLength, &iterDone);
+    {
+        masm.push(iter);
+
+        Register front = iter;
+        ValueMapRangeFront(masm, range, temp, front);
+
+        size_t elementsOffset = NativeObject::offsetOfFixedElements();
+
+        Address keyAddress(front, ValueMap::Entry::offsetOfKey());
+        Address valueAddress(front, ValueMap::Entry::offsetOfValue());
+        masm.storeValue(keyAddress, Address(result, elementsOffset), temp);
+        masm.storeValue(valueAddress, Address(result, elementsOffset + sizeof(Value)), temp);
+
+        Label keyIsNotObject, valueIsNotNurseryObject, emitBarrier;
+        masm.branchTestObject(Assembler::NotEqual, keyAddress, &keyIsNotObject);
+        masm.branchValueIsNurseryObject(Assembler::Equal, keyAddress, temp,
+                                        &emitBarrier);
+        masm.bind(&keyIsNotObject);
+        masm.branchTestObject(Assembler::NotEqual, valueAddress, &valueIsNotNurseryObject);
+        masm.branchValueIsNurseryObject(Assembler::NotEqual, valueAddress, temp,
+                                        &valueIsNotNurseryObject);
+        {
+            masm.bind(&emitBarrier);
+            saveVolatile(temp);
+            emitPostWriteBarrier(result);
+            restoreVolatile(temp);
+        }
+        masm.bind(&valueIsNotNurseryObject);
+
+        ValueMapRangePopFront(masm, range, front, dataLength, temp);
+
+        masm.pop(iter);
+        masm.move32(Imm32(0), output);
+    }
+    masm.jump(&done);
+    {
+        masm.bind(&iterDone);
+
+        ValueMapRangeDestruct(masm, range, temp, dataLength);
+
+        masm.storeValue(PrivateValue(nullptr),
+                        Address(iter, NativeObject::getFixedSlotOffset(MapIteratorObject::RangeSlot)));
+
+        masm.move32(Imm32(1), output);
+    }
+    masm.bind(&done);
+}
+
 void
 CodeGenerator::visitTypedArrayLength(LTypedArrayLength* lir)
 {
     Register obj = ToRegister(lir->object());
     Register out = ToRegister(lir->output());
     masm.unboxInt32(Address(obj, TypedArrayObject::lengthOffset()), out);
 }
 
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -134,16 +134,18 @@ class CodeGenerator : public CodeGenerat
     void visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite* lir);
     void visitGuardObjectIdentity(LGuardObjectIdentity* guard);
     void visitGuardReceiverPolymorphic(LGuardReceiverPolymorphic* lir);
     void visitGuardUnboxedExpando(LGuardUnboxedExpando* lir);
     void visitLoadUnboxedExpando(LLoadUnboxedExpando* lir);
     void visitTypeBarrierV(LTypeBarrierV* lir);
     void visitTypeBarrierO(LTypeBarrierO* lir);
     void visitMonitorTypes(LMonitorTypes* lir);
+    void emitPostWriteBarrier(const LAllocation* obj);
+    void emitPostWriteBarrier(Register objreg);
     template <class LPostBarrierType>
     void visitPostWriteBarrierCommonO(LPostBarrierType* lir, OutOfLineCode* ool);
     template <class LPostBarrierType>
     void visitPostWriteBarrierCommonV(LPostBarrierType* lir, OutOfLineCode* ool);
     void visitPostWriteBarrierO(LPostWriteBarrierO* lir);
     void visitPostWriteElementBarrierO(LPostWriteElementBarrierO* lir);
     void visitPostWriteBarrierV(LPostWriteBarrierV* lir);
     void visitPostWriteElementBarrierV(LPostWriteElementBarrierV* lir);
@@ -202,16 +204,17 @@ class CodeGenerator : public CodeGenerat
     void visitCreateThisWithTemplate(LCreateThisWithTemplate* lir);
     void visitCreateArgumentsObject(LCreateArgumentsObject* lir);
     void visitGetArgumentsObjectArg(LGetArgumentsObjectArg* lir);
     void visitSetArgumentsObjectArg(LSetArgumentsObjectArg* lir);
     void visitReturnFromCtor(LReturnFromCtor* lir);
     void visitComputeThis(LComputeThis* lir);
     void visitArrayLength(LArrayLength* lir);
     void visitSetArrayLength(LSetArrayLength* lir);
+    void visitGetNextMapEntryForIterator(LGetNextMapEntryForIterator* lir);
     void visitTypedArrayLength(LTypedArrayLength* lir);
     void visitTypedArrayElements(LTypedArrayElements* lir);
     void visitSetDisjointTypedElements(LSetDisjointTypedElements* lir);
     void visitTypedObjectElements(LTypedObjectElements* lir);
     void visitSetTypedObjectOffset(LSetTypedObjectOffset* lir);
     void visitTypedObjectDescr(LTypedObjectDescr* ins);
     void visitStringLength(LStringLength* lir);
     void visitSubstr(LSubstr* lir);
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -104,16 +104,18 @@
     _(IntrinsicSubstringKernel)     \
     _(IntrinsicDefineDataProperty)  \
                                     \
     _(IntrinsicIsArrayIterator)     \
     _(IntrinsicIsMapIterator)       \
     _(IntrinsicIsStringIterator)    \
     _(IntrinsicIsListIterator)      \
                                     \
+    _(IntrinsicGetNextMapEntryForIterator) \
+                                    \
     _(IntrinsicIsTypedArray)        \
     _(IntrinsicIsPossiblyWrappedTypedArray) \
     _(IntrinsicTypedArrayLength)    \
     _(IntrinsicPossiblyWrappedTypedArrayLength)    \
     _(IntrinsicSetDisjointTypedElements) \
                                     \
     _(IntrinsicObjectIsTypedObject) \
     _(IntrinsicObjectIsTransparentTypedObject) \
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -836,16 +836,19 @@ class IonBuilder
     InliningStatus inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target);
     InliningStatus inlineAtomicsIsLockFree(CallInfo& callInfo);
 
     // Slot intrinsics.
     InliningStatus inlineUnsafeSetReservedSlot(CallInfo& callInfo);
     InliningStatus inlineUnsafeGetReservedSlot(CallInfo& callInfo,
                                                MIRType knownValueType);
 
+    // Map intrinsics.
+    InliningStatus inlineGetNextMapEntryForIterator(CallInfo& callInfo);
+
     // TypedArray intrinsics.
     enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays };
     InliningStatus inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior);
     InliningStatus inlineIsTypedArray(CallInfo& callInfo);
     InliningStatus inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo);
     InliningStatus inlineTypedArrayLength(CallInfo& callInfo);
     InliningStatus inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo);
     InliningStatus inlineSetDisjointTypedElements(CallInfo& callInfo);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2693,16 +2693,28 @@ LIRGenerator::visitSetArrayLength(MSetAr
     MOZ_ASSERT(ins->index()->type() == MIRType_Int32);
 
     MOZ_ASSERT(ins->index()->isConstant());
     add(new(alloc()) LSetArrayLength(useRegister(ins->elements()),
                                      useRegisterOrConstant(ins->index())), ins);
 }
 
 void
+LIRGenerator::visitGetNextMapEntryForIterator(MGetNextMapEntryForIterator* ins)
+{
+    MOZ_ASSERT(ins->iter()->type() == MIRType_Object);
+    MOZ_ASSERT(ins->result()->type() == MIRType_Object);
+    auto lir = new(alloc()) LGetNextMapEntryForIterator(useRegister(ins->iter()),
+                                                        useRegister(ins->result()),
+                                                        temp(), temp(), temp());
+    define(lir, ins);
+    assignSafepoint(lir, ins);
+}
+
+void
 LIRGenerator::visitTypedArrayLength(MTypedArrayLength* ins)
 {
     MOZ_ASSERT(ins->object()->type() == MIRType_Object);
     define(new(alloc()) LTypedArrayLength(useRegisterAtStart(ins->object())), ins);
 }
 
 void
 LIRGenerator::visitTypedArrayElements(MTypedArrayElements* ins)
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -187,16 +187,17 @@ class LIRGenerator : public LIRGenerator
     void visitStoreSlot(MStoreSlot* ins);
     void visitFilterTypeSet(MFilterTypeSet* ins);
     void visitTypeBarrier(MTypeBarrier* ins);
     void visitMonitorTypes(MMonitorTypes* ins);
     void visitPostWriteBarrier(MPostWriteBarrier* ins);
     void visitPostWriteElementBarrier(MPostWriteElementBarrier* ins);
     void visitArrayLength(MArrayLength* ins);
     void visitSetArrayLength(MSetArrayLength* ins);
+    void visitGetNextMapEntryForIterator(MGetNextMapEntryForIterator* ins);
     void visitTypedArrayLength(MTypedArrayLength* ins);
     void visitTypedArrayElements(MTypedArrayElements* ins);
     void visitSetDisjointTypedElements(MSetDisjointTypedElements* ins);
     void visitTypedObjectElements(MTypedObjectElements* ins);
     void visitSetTypedObjectOffset(MSetTypedObjectOffset* ins);
     void visitTypedObjectDescr(MTypedObjectDescr* ins);
     void visitInitializedLength(MInitializedLength* ins);
     void visitSetInitializedLength(MSetInitializedLength* ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -255,16 +255,20 @@ IonBuilder::inlineNativeCall(CallInfo& c
         return inlineHasClass(callInfo, &MapIteratorObject::class_);
       case InlinableNative::IntrinsicIsStringIterator:
         return inlineHasClass(callInfo, &StringIteratorObject::class_);
       case InlinableNative::IntrinsicIsListIterator:
         return inlineHasClass(callInfo, &ListIteratorObject::class_);
       case InlinableNative::IntrinsicDefineDataProperty:
         return inlineDefineDataProperty(callInfo);
 
+      // Map intrinsics.
+      case InlinableNative::IntrinsicGetNextMapEntryForIterator:
+        return inlineGetNextMapEntryForIterator(callInfo);
+
       // TypedArray intrinsics.
       case InlinableNative::IntrinsicIsTypedArray:
         return inlineIsTypedArray(callInfo);
       case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray:
         return inlineIsPossiblyWrappedTypedArray(callInfo);
       case InlinableNative::IntrinsicPossiblyWrappedTypedArrayLength:
         return inlinePossiblyWrappedTypedArrayLength(callInfo);
       case InlinableNative::IntrinsicTypedArrayLength:
@@ -2186,16 +2190,56 @@ IonBuilder::inlineHasClass(CallInfo& cal
         }
     }
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
+IonBuilder::inlineGetNextMapEntryForIterator(CallInfo& callInfo)
+{
+    if (callInfo.argc() != 2 || callInfo.constructing()) {
+        trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
+        return InliningStatus_NotInlined;
+    }
+
+    MDefinition* iterArg = callInfo.getArg(0);
+    MDefinition* resultArg = callInfo.getArg(1);
+
+    if (iterArg->type() != MIRType_Object)
+        return InliningStatus_NotInlined;
+
+    TemporaryTypeSet* iterTypes = iterArg->resultTypeSet();
+    const Class* iterClasp = iterTypes ? iterTypes->getKnownClass(constraints()) : nullptr;
+    if (iterClasp != &MapIteratorObject::class_)
+        return InliningStatus_NotInlined;
+
+    if (resultArg->type() != MIRType_Object)
+        return InliningStatus_NotInlined;
+
+    TemporaryTypeSet* resultTypes = resultArg->resultTypeSet();
+    const Class* resultClasp = resultTypes ? resultTypes->getKnownClass(constraints()) : nullptr;
+    if (resultClasp != &ArrayObject::class_)
+        return InliningStatus_NotInlined;
+
+    callInfo.setImplicitlyUsedUnchecked();
+
+    MInstruction* next = MGetNextMapEntryForIterator::New(alloc(), iterArg,
+                                                          resultArg);
+    current->add(next);
+    current->push(next);
+
+    if (!resumeAfter(next))
+        return InliningStatus_Error;
+
+    return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
 IonBuilder::inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior)
 {
     MOZ_ASSERT(!callInfo.constructing());
     MOZ_ASSERT(callInfo.argc() == 1);
 
     if (callInfo.getArg(0)->type() != MIRType_Object)
         return InliningStatus_NotInlined;
     if (getInlineReturnType() != MIRType_Boolean)
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -8700,16 +8700,44 @@ class MSetArrayLength
     MDefinition* index() const {
         return getOperand(1);
     }
     AliasSet getAliasSet() const override {
         return AliasSet::Store(AliasSet::ObjectFields);
     }
 };
 
+class MGetNextMapEntryForIterator
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >::Data
+{
+  protected:
+    explicit MGetNextMapEntryForIterator(MDefinition* iter, MDefinition* result)
+      : MBinaryInstruction(iter, result)
+    {
+        setResultType(MIRType_Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(GetNextMapEntryForIterator)
+
+    static MGetNextMapEntryForIterator* New(TempAllocator& alloc, MDefinition* iter, MDefinition* result)
+    {
+        return new(alloc) MGetNextMapEntryForIterator(iter, result);
+    }
+
+    MDefinition* iter() {
+        return getOperand(0);
+    }
+
+    MDefinition* result() {
+        return getOperand(1);
+    }
+};
+
 // Read the length of a typed array.
 class MTypedArrayLength
   : public MUnaryInstruction,
     public SingleObjectPolicy::Data
 {
     explicit MTypedArrayLength(MDefinition* obj)
       : MUnaryInstruction(obj)
     {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -175,16 +175,17 @@ namespace jit {
     _(GuardReceiverPolymorphic)                                             \
     _(GuardObjectGroup)                                                     \
     _(GuardObjectIdentity)                                                  \
     _(GuardClass)                                                           \
     _(GuardUnboxedExpando)                                                  \
     _(LoadUnboxedExpando)                                                   \
     _(ArrayLength)                                                          \
     _(SetArrayLength)                                                       \
+    _(GetNextMapEntryForIterator)                                           \
     _(TypedArrayLength)                                                     \
     _(TypedArrayElements)                                                   \
     _(SetDisjointTypedElements)                                             \
     _(TypedObjectDescr)                                                     \
     _(TypedObjectElements)                                                  \
     _(SetTypedObjectOffset)                                                 \
     _(InitializedLength)                                                    \
     _(SetInitializedLength)                                                 \
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -844,16 +844,19 @@ class MacroAssembler : public MacroAssem
 
     template <typename T>
     inline CodeOffsetJump branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH;
     template <typename T>
     inline CodeOffsetJump branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH;
 
     void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label* label)
         DEFINED_ON(arm, arm64, mips_shared, x86, x64);
+    void branchPtrInNurseryRange(Condition cond, const Address& address, Register temp, Label* label)
+        DEFINED_ON(x86);
+    void branchValueIsNurseryObject(Condition cond, const Address& address, Register temp, Label* label) PER_ARCH;
     void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label* label) PER_ARCH;
 
     // This function compares a Value (lhs) which is having a private pointer
     // boxed inside a js::Value, with a raw pointer (rhs).
     inline void branchPrivatePtr(Condition cond, const Address& lhs, Register rhs, Label* label) PER_ARCH;
 
     inline void branchFloat(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs,
                             Label* label) PER_SHARED_ARCH;
@@ -1001,16 +1004,18 @@ class MacroAssembler : public MacroAssem
         DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
 
     inline void branchTestMagic(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
     inline void branchTestMagic(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
     template <class L>
     inline void branchTestMagic(Condition cond, const ValueOperand& value, L label)
         DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
 
+    inline void branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label) PER_ARCH;
+
     inline void branchTestMagicValue(Condition cond, const ValueOperand& val, JSWhyMagic why,
                                      Label* label);
 
     void branchTestValue(Condition cond, const ValueOperand& lhs,
                          const Value& rhs, Label* label) PER_ARCH;
 
     // Checks if given Value is evaluated to true or false in a condition.
     // The type of the value should match the type of the method.
@@ -1028,16 +1033,23 @@ class MacroAssembler : public MacroAssem
     inline void branch32Impl(Condition cond, const T& length, const RegisterOrInt32Constant& key,
                              Label* label);
 
     template <typename T, typename S>
     inline void branchPtrImpl(Condition cond, const T& lhs, const S& rhs, Label* label)
         DEFINED_ON(x86_shared);
 
     template <typename T>
+    void branchPtrInNurseryRangeImpl(Condition cond, const T& ptr, Register temp, Label* label)
+        DEFINED_ON(x86);
+    template <typename T>
+    void branchValueIsNurseryObjectImpl(Condition cond, const T& value, Register temp, Label* label)
+        DEFINED_ON(arm64, mips64, x64);
+
+    template <typename T>
     inline void branchTestUndefinedImpl(Condition cond, const T& t, Label* label)
         DEFINED_ON(arm, arm64, x86_shared);
     template <typename T>
     inline void branchTestInt32Impl(Condition cond, const T& t, Label* label)
         DEFINED_ON(arm, arm64, x86_shared);
     template <typename T>
     inline void branchTestDoubleImpl(Condition cond, const T& t, Label* label)
         DEFINED_ON(arm, arm64, x86_shared);
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -141,19 +141,19 @@ class RegisterDump
 class MachineState
 {
     mozilla::Array<Registers::RegisterContent*, Registers::Total> regs_;
     mozilla::Array<FloatRegisters::RegisterContent*, FloatRegisters::Total> fpregs_;
 
   public:
     MachineState() {
 #ifndef JS_CODEGEN_NONE
-        for (unsigned i = 0; i < Registers::Total; i++)
+        for (uintptr_t i = 0; i < Registers::Total; i++)
             regs_[i] = reinterpret_cast<Registers::RegisterContent*>(i + 0x100);
-        for (unsigned i = 0; i < FloatRegisters::Total; i++)
+        for (uintptr_t i = 0; i < FloatRegisters::Total; i++)
             fpregs_[i] = reinterpret_cast<FloatRegisters::RegisterContent*>(i + 0x200);
 #endif
     }
 
     static MachineState FromBailout(RegisterDump::GPRArray& regs, RegisterDump::FPUArray& fpregs);
 
     void setRegisterLocation(Register reg, uintptr_t* up) {
         regs_[reg.code()] = (Registers::RegisterContent*) up;
--- a/js/src/jit/arm/MacroAssembler-arm-inl.h
+++ b/js/src/jit/arm/MacroAssembler-arm-inl.h
@@ -1159,16 +1159,23 @@ MacroAssembler::branchTestMagic(Conditio
 template <typename T, class L>
 void
 MacroAssembler::branchTestMagicImpl(Condition cond, const T& t, L label)
 {
     cond = testMagic(cond, t);
     ma_b(label, cond);
 }
 
+void
+MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
+{
+    branchTestMagic(cond, valaddr, label);
+    branch32(cond, ToPayload(valaddr), Imm32(why), label);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerARMCompat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), ToPayload(addr));
 }
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -5018,16 +5018,31 @@ MacroAssembler::branchPtrInNurseryRange(
 
     ma_mov(Imm32(startChunk), scratch2);
     as_rsb(scratch2, scratch2, lsr(ptr, Nursery::ChunkShift));
     branch32(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
              scratch2, Imm32(nursery.numChunks()), label);
 }
 
 void
+MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address,
+                                           Register temp, Label* label)
+{
+    MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
+    Label done;
+
+    branchTestObject(Assembler::NotEqual, address, cond == Assembler::Equal ? &done : label);
+    loadPtr(address, temp);
+    branchPtrInNurseryRange(cond, temp, InvalidReg, label);
+
+    bind(&done);
+}
+
+void
 MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value,
                                            Register temp, Label* label)
 {
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
 
     Label done;
 
     branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label);
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -840,16 +840,23 @@ class MacroAssemblerARMCompat : public M
             ma_mov(Imm32(jv.s.payload.i32), scratch2);
         ma_str(scratch2, ToPayload(dest));
     }
     void storeValue(const Value& val, BaseIndex dest) {
         ScratchRegisterScope scratch(asMasm());
         ma_alu(dest.base, lsl(dest.index, dest.scale), scratch, OpAdd);
         storeValue(val, Address(scratch, dest.offset));
     }
+    void storeValue(const Address& src, const Address& dest, Register temp) {
+        load32(ToType(src), temp);
+        store32(temp, ToType(dest));
+
+        load32(ToPayload(src), temp);
+        store32(temp, ToPayload(dest));
+    }
 
     void loadValue(Address src, ValueOperand val);
     void loadValue(Operand dest, ValueOperand val) {
         loadValue(dest.toAddress(), val);
     }
     void loadValue(const BaseIndex& addr, ValueOperand val);
     void tagValue(JSValueType type, Register payload, ValueOperand dest);
 
--- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h
@@ -1258,16 +1258,24 @@ MacroAssembler::branchTestMagic(Conditio
 template <typename T, class L>
 void
 MacroAssembler::branchTestMagicImpl(Condition cond, const T& t, L label)
 {
     Condition c = testMagic(cond, t);
     B(label, c);
 }
 
+void
+MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
+{
+    uint64_t magic = MagicValue(why).asRawBits();
+    cmpPtr(valaddr, ImmWord(magic));
+    B(label, cond);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 template <typename T>
 void
 MacroAssemblerCompat::addToStackPtr(T t)
 {
     asMasm().addPtr(t, getStackPointer());
--- a/js/src/jit/arm64/MacroAssembler-arm64.cpp
+++ b/js/src/jit/arm64/MacroAssembler-arm64.cpp
@@ -712,33 +712,48 @@ MacroAssembler::branchPtrInNurseryRange(
     const Nursery& nursery = GetJitContext()->runtime->gcNursery();
     movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
     addPtr(ptr, temp);
     branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
               temp, ImmWord(nursery.nurserySize()), label);
 }
 
 void
+MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address, Register temp,
+                                           Label* label)
+{
+    branchValueIsNurseryObjectImpl(cond, address, temp, label);
+}
+
+void
 MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp,
                                            Label* label)
 {
-    MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+    branchValueIsNurseryObjectImpl(cond, value.valueReg(), temp, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchValueIsNurseryObjectImpl(Condition cond, const T& value, Register temp,
+                                               Label* label)
+{
+   MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     MOZ_ASSERT(temp != ScratchReg && temp != ScratchReg2); // Both may be used internally.
 
     const Nursery& nursery = GetJitContext()->runtime->gcNursery();
 
     // Avoid creating a bogus ObjectValue below.
     if (!nursery.exists())
         return;
 
     // 'Value' representing the start of the nursery tagged as a JSObject
     Value start = ObjectValue(*reinterpret_cast<JSObject*>(nursery.start()));
 
     movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), temp);
-    addPtr(value.valueReg(), temp);
+    addPtr(value, temp);
     branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
               temp, ImmWord(nursery.nurserySize()), label);
 }
 
 void
 MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs,
                                 const Value& rhs, Label* label)
 {
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -274,16 +274,20 @@ class MacroAssemblerCompat : public vixl
         vixl::UseScratchRegisterScope temps(this);
         const Register scratch = temps.AcquireX().asUnsized();
         moveValue(val, ValueOperand(scratch));
         storeValue(ValueOperand(scratch), dest);
     }
     void storeValue(ValueOperand val, BaseIndex dest) {
         storePtr(val.valueReg(), dest);
     }
+    void storeValue(const Address& src, const Address& dest, Register temp) {
+        loadPtr(src, temp);
+        storePtr(temp, dest);
+    }
 
     template <typename T>
     void storeUnboxedValue(ConstantOrRegister value, MIRType valueType, const T& dest, MIRType slotType) {
         if (valueType == MIRType_Double) {
             storeDouble(value.reg().typedReg().fpu(), dest);
             return;
         }
 
--- a/js/src/jit/mips32/MacroAssembler-mips32-inl.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32-inl.h
@@ -382,16 +382,23 @@ MacroAssembler::branchTestPrimitive(Cond
 
 template <class L>
 void
 MacroAssembler::branchTestMagic(Condition cond, const ValueOperand& value, L label)
 {
     ma_b(value.typeReg(), ImmTag(JSVAL_TAG_MAGIC), label, cond);
 }
 
+void
+MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
+{
+    branchTestMagic(cond, valaddr, label);
+    branch32(cond, ToPayload(valaddr), Imm32(why), label);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerMIPSCompat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), ToPayload(addr));
 }
--- a/js/src/jit/mips32/MacroAssembler-mips32.cpp
+++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp
@@ -2138,16 +2138,31 @@ MacroAssembler::callWithABINoProfiler(co
     call(t9);
     callWithABIPost(stackAdjust, result);
 }
 
 // ===============================================================
 // Branch functions
 
 void
+MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address,
+                                           Register temp, Label* label)
+{
+    MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
+    Label done;
+
+    branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label);
+    loadPtr(address, temp);
+    branchPtrInNurseryRange(cond, temp, InvalidReg, label);
+
+    bind(&done);
+}
+
+void
 MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value,
                                            Register temp, Label* label)
 {
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
 
     Label done;
 
     branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label);
--- a/js/src/jit/mips32/MacroAssembler-mips32.h
+++ b/js/src/jit/mips32/MacroAssembler-mips32.h
@@ -452,16 +452,23 @@ class MacroAssemblerMIPSCompat : public 
 
     void storeValue(ValueOperand val, Operand dst);
     void storeValue(ValueOperand val, const BaseIndex& dest);
     void storeValue(JSValueType type, Register reg, BaseIndex dest);
     void storeValue(ValueOperand val, const Address& dest);
     void storeValue(JSValueType type, Register reg, Address dest);
     void storeValue(const Value& val, Address dest);
     void storeValue(const Value& val, BaseIndex dest);
+    void storeValue(const Address& src, const Address& dest, Register temp) {
+        load32(ToType(src), temp);
+        store32(temp, ToType(dest));
+
+        load32(ToPayload(src), temp);
+        store32(temp, ToPayload(dest));
+    }
 
     void loadValue(Address src, ValueOperand val);
     void loadValue(Operand dest, ValueOperand val) {
         loadValue(dest.toAddress(), val);
     }
     void loadValue(const BaseIndex& addr, ValueOperand val);
     void tagValue(JSValueType type, Register payload, ValueOperand dest);
 
--- a/js/src/jit/mips64/MacroAssembler-mips64-inl.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64-inl.h
@@ -341,16 +341,25 @@ template <class L>
 void
 MacroAssembler::branchTestMagic(Condition cond, const ValueOperand& value, L label)
 {
     SecondScratchRegisterScope scratch2(*this);
     splitTag(value, scratch2);
     ma_b(scratch2, ImmTag(JSVAL_TAG_MAGIC), label, cond);
 }
 
+void
+MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
+{
+    uint64_t magic = MagicValue(why).asRawBits();
+    ScratchRegisterScope scratch(*this);
+    loadPtr(valaddr, scratch);
+    ma_b(scratch, ImmWord(magic), cond, label);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerMIPS64Compat::incrementInt32Value(const Address& addr)
 {
     asMasm().add32(Imm32(1), addr);
 }
--- a/js/src/jit/mips64/MacroAssembler-mips64.cpp
+++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp
@@ -2300,27 +2300,42 @@ MacroAssembler::callWithABINoProfiler(co
     call(t9);
     callWithABIPost(stackAdjust, result);
 }
 
 // ===============================================================
 // Branch functions
 
 void
+MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address, Register temp,
+                                           Label* label)
+{
+    branchValueIsNurseryObject(cond, address, temp, label);
+}
+
+void
 MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value,
                                            Register temp, Label* label)
 {
+    branchValueIsNurseryObject(cond, value.valueReg(), temp, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchValueIsNurseryObjectImpl(Condition cond, const T& value, Register temp,
+                                               Label* label)
+{
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
 
     // 'Value' representing the start of the nursery tagged as a JSObject
     const Nursery& nursery = GetJitContext()->runtime->gcNursery();
     Value start = ObjectValue(*reinterpret_cast<JSObject *>(nursery.start()));
 
     movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), SecondScratchReg);
-    addPtr(value.valueReg(), SecondScratchReg);
+    addPtr(value, SecondScratchReg);
     branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
               SecondScratchReg, Imm32(nursery.nurserySize()), label);
 }
 
 void
 MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs,
                                 const Value& rhs, Label* label)
 {
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -471,16 +471,20 @@ class MacroAssemblerMIPS64Compat : publi
 
     void storeValue(ValueOperand val, Operand dst);
     void storeValue(ValueOperand val, const BaseIndex& dest);
     void storeValue(JSValueType type, Register reg, BaseIndex dest);
     void storeValue(ValueOperand val, const Address& dest);
     void storeValue(JSValueType type, Register reg, Address dest);
     void storeValue(const Value& val, Address dest);
     void storeValue(const Value& val, BaseIndex dest);
+    void storeValue(const Address& src, const Address& dest, Register temp) {
+        loadPtr(src, temp);
+        storePtr(temp, dest);
+    }
 
     void loadValue(Address src, ValueOperand val);
     void loadValue(Operand dest, ValueOperand val) {
         loadValue(dest.toAddress(), val);
     }
     void loadValue(const BaseIndex& addr, ValueOperand val);
     void tagValue(JSValueType type, Register payload, ValueOperand dest);
 
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -541,17 +541,17 @@ class CodeLocationJump
     uint8_t* jumpTableEntry_;
 #endif
 
   public:
     CodeLocationJump() {
         raw_ = nullptr;
         setUninitialized();
 #ifdef JS_SMALL_BRANCH
-        jumpTableEntry_ = (uint8_t*) 0xdeadab1e;
+        jumpTableEntry_ = (uint8_t*) uintptr_t(0xdeadab1e);
 #endif
     }
     CodeLocationJump(JitCode* code, CodeOffsetJump base) {
         *this = base;
         repoint(code);
     }
 
     void operator = (CodeOffsetJump base) {
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -4725,16 +4725,49 @@ class LSetArrayLength : public LInstruct
     const LAllocation* elements() {
         return getOperand(0);
     }
     const LAllocation* index() {
         return getOperand(1);
     }
 };
 
+class LGetNextMapEntryForIterator : public LInstructionHelper<1, 2, 3>
+{
+  public:
+    LIR_HEADER(GetNextMapEntryForIterator)
+
+    explicit LGetNextMapEntryForIterator(const LAllocation& iter, const LAllocation& result,
+                                         const LDefinition& temp0, const LDefinition& temp1,
+                                         const LDefinition& temp2)
+    {
+        setOperand(0, iter);
+        setOperand(1, result);
+        setTemp(0, temp0);
+        setTemp(1, temp1);
+        setTemp(2, temp2);
+    }
+
+    const LAllocation* iter() {
+        return getOperand(0);
+    }
+    const LAllocation* result() {
+        return getOperand(1);
+    }
+    const LDefinition* temp0() {
+        return getTemp(0);
+    }
+    const LDefinition* temp1() {
+        return getTemp(1);
+    }
+    const LDefinition* temp2() {
+        return getTemp(2);
+    }
+};
+
 // Read the length of a typed array.
 class LTypedArrayLength : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(TypedArrayLength)
 
     explicit LTypedArrayLength(const LAllocation& obj) {
         setOperand(0, obj);
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -310,16 +310,17 @@
     _(SetPropertyPolymorphicT)      \
     _(CallIteratorStart)            \
     _(IteratorStart)                \
     _(IteratorMore)                 \
     _(IsNoIterAndBranch)            \
     _(IteratorEnd)                  \
     _(ArrayLength)                  \
     _(SetArrayLength)               \
+    _(GetNextMapEntryForIterator)   \
     _(TypedArrayLength)             \
     _(TypedArrayElements)           \
     _(SetDisjointTypedElements)     \
     _(TypedObjectDescr)             \
     _(TypedObjectElements)          \
     _(SetTypedObjectOffset)         \
     _(StringLength)                 \
     _(ArgumentsLength)              \
--- a/js/src/jit/x64/MacroAssembler-x64-inl.h
+++ b/js/src/jit/x64/MacroAssembler-x64-inl.h
@@ -400,16 +400,24 @@ MacroAssembler::branchTest64(Condition c
 
 void
 MacroAssembler::branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label)
 {
     test32(value.valueReg(), value.valueReg());
     j(truthy ? NonZero : Zero, label);
 }
 
+void
+MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
+{
+    uint64_t magic = MagicValue(why).asRawBits();
+    cmpPtr(valaddr, ImmWord(magic));
+    j(cond, label);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 void
 MacroAssemblerX64::incrementInt32Value(const Address& addr)
 {
     asMasm().addPtr(Imm32(1), addr);
 }
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -441,33 +441,48 @@ MacroAssembler::branchPtrInNurseryRange(
     const Nursery& nursery = GetJitContext()->runtime->gcNursery();
     movePtr(ImmWord(-ptrdiff_t(nursery.start())), scratch);
     addPtr(ptr, scratch);
     branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
               scratch, Imm32(nursery.nurserySize()), label);
 }
 
 void
+MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address, Register temp,
+                                           Label* label)
+{
+    branchValueIsNurseryObjectImpl(cond, address, temp, label);
+}
+
+void
 MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp,
                                            Label* label)
 {
+    branchValueIsNurseryObjectImpl(cond, value.valueReg(), temp, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchValueIsNurseryObjectImpl(Condition cond, const T& value, Register temp,
+                                               Label* label)
+{
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
 
     const Nursery& nursery = GetJitContext()->runtime->gcNursery();
 
     // Avoid creating a bogus ObjectValue below.
     if (!nursery.exists())
         return;
 
     // 'Value' representing the start of the nursery tagged as a JSObject
     Value start = ObjectValue(*reinterpret_cast<JSObject*>(nursery.start()));
 
     ScratchRegisterScope scratch(*this);
     movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), scratch);
-    addPtr(value.valueReg(), scratch);
+    addPtr(value, scratch);
     branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
               scratch, Imm32(nursery.nurserySize()), label);
 }
 
 void
 MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs,
                                 const Value& rhs, Label* label)
 {
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -139,16 +139,20 @@ class MacroAssemblerX64 : public MacroAs
         } else {
             mov(ImmWord(jv.asBits), scratch);
         }
         movq(scratch, Operand(dest));
     }
     void storeValue(ValueOperand val, BaseIndex dest) {
         storeValue(val, Operand(dest));
     }
+    void storeValue(const Address& src, const Address& dest, Register temp) {
+        loadPtr(src, temp);
+        storePtr(temp, dest);
+    }
     void loadValue(Operand src, ValueOperand val) {
         movq(src, val.valueReg());
     }
     void loadValue(Address src, ValueOperand val) {
         loadValue(Operand(src), val);
     }
     void loadValue(const BaseIndex& src, ValueOperand val) {
         loadValue(Operand(src), val);
--- a/js/src/jit/x86/MacroAssembler-x86-inl.h
+++ b/js/src/jit/x86/MacroAssembler-x86-inl.h
@@ -381,16 +381,23 @@ MacroAssembler::branchTest64(Condition c
 
 void
 MacroAssembler::branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label)
 {
     test32(value.payloadReg(), value.payloadReg());
     j(truthy ? NonZero : Zero, label);
 }
 
+void
+MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label)
+{
+    branchTestMagic(cond, valaddr, label);
+    branch32(cond, ToPayload(valaddr), Imm32(why), label);
+}
+
 //}}} check_macroassembler_style
 // ===============================================================
 
 // Note: this function clobbers the source register.
 void
 MacroAssemblerX86::convertUInt32ToDouble(Register src, FloatRegister dest)
 {
     // src is [0, 2^32-1]
--- a/js/src/jit/x86/MacroAssembler-x86.cpp
+++ b/js/src/jit/x86/MacroAssembler-x86.cpp
@@ -445,28 +445,57 @@ MacroAssembler::callWithABINoProfiler(co
 
 // ===============================================================
 // Branch functions
 
 void
 MacroAssembler::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp,
                                         Label* label)
 {
+    MOZ_ASSERT(ptr != temp);
+    branchPtrInNurseryRangeImpl(cond, ptr, temp, label);
+}
+
+void
+MacroAssembler::branchPtrInNurseryRange(Condition cond, const Address& address, Register temp,
+                                        Label* label)
+{
+    branchPtrInNurseryRangeImpl(cond, address, temp, label);
+}
+
+template <typename T>
+void
+MacroAssembler::branchPtrInNurseryRangeImpl(Condition cond, const T& ptr, Register temp,
+                                            Label* label)
+{
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
-    MOZ_ASSERT(ptr != temp);
     MOZ_ASSERT(temp != InvalidReg);  // A temp register is required for x86.
 
     const Nursery& nursery = GetJitContext()->runtime->gcNursery();
     movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp);
     addPtr(ptr, temp);
     branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual,
               temp, Imm32(nursery.nurserySize()), label);
 }
 
 void
+MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address, Register temp,
+                                           Label* label)
+{
+    MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
+    Label done;
+
+    branchTestObject(Assembler::NotEqual, address, cond == Assembler::Equal ? &done : label);
+    branchPtrInNurseryRange(cond, address, temp, label);
+
+    bind(&done);
+}
+
+void
 MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp,
                                            Label* label)
 {
     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
 
     Label done;
 
     branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label);
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -145,16 +145,26 @@ class MacroAssemblerX86 : public MacroAs
     void storeValue(const Value& val, const T& dest) {
         jsval_layout jv = JSVAL_TO_IMPL(val);
         storeTypeTag(ImmTag(jv.s.tag), Operand(dest));
         storePayload(val, Operand(dest));
     }
     void storeValue(ValueOperand val, BaseIndex dest) {
         storeValue(val, Operand(dest));
     }
+    void storeValue(const Address& src, const Address& dest, Register temp) {
+        MOZ_ASSERT(src.base != temp);
+        MOZ_ASSERT(dest.base != temp);
+
+        load32(ToType(src), temp);
+        store32(temp, ToType(dest));
+
+        load32(ToPayload(src), temp);
+        store32(temp, ToPayload(dest));
+    }
     void loadValue(Operand src, ValueOperand val) {
         Operand payload = ToPayload(src);
         Operand type = ToType(src);
 
         // Ensure that loading the payload does not erase the pointer to the
         // Value in memory or the index.
         Register baseReg = Register::FromCode(src.base());
         Register indexReg = (src.kind() == Operand::MEM_SCALE) ? Register::FromCode(src.index()) : InvalidReg;
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -221,17 +221,19 @@ class WrapperMapRef : public BufferableR
 
     void trace(JSTracer* trc) override {
         CrossCompartmentKey prior = key;
         if (key.debugger)
             TraceManuallyBarrieredEdge(trc, &key.debugger, "CCW debugger");
         if (key.kind == CrossCompartmentKey::ObjectWrapper ||
             key.kind == CrossCompartmentKey::DebuggerObject ||
             key.kind == CrossCompartmentKey::DebuggerEnvironment ||
-            key.kind == CrossCompartmentKey::DebuggerSource)
+            key.kind == CrossCompartmentKey::DebuggerSource ||
+            key.kind == CrossCompartmentKey::DebuggerWasmScript ||
+            key.kind == CrossCompartmentKey::DebuggerWasmSource)
         {
             MOZ_ASSERT(IsInsideNursery(key.wrapped) ||
                        key.wrapped->asTenured().getTraceKind() == JS::TraceKind::Object);
             TraceManuallyBarrieredEdge(trc, reinterpret_cast<JSObject**>(&key.wrapped),
                                        "CCW wrapped object");
         }
         if (key.debugger == prior.debugger && key.wrapped == prior.wrapped)
             return;
@@ -762,16 +764,18 @@ bool
 CrossCompartmentKey::needsSweep()
 {
     bool keyDying;
     switch (kind) {
       case CrossCompartmentKey::ObjectWrapper:
       case CrossCompartmentKey::DebuggerObject:
       case CrossCompartmentKey::DebuggerEnvironment:
       case CrossCompartmentKey::DebuggerSource:
+      case CrossCompartmentKey::DebuggerWasmScript:
+      case CrossCompartmentKey::DebuggerWasmSource:
           MOZ_ASSERT(IsInsideNursery(wrapped) ||
                      wrapped->asTenured().getTraceKind() == JS::TraceKind::Object);
           keyDying = IsAboutToBeFinalizedUnbarriered(reinterpret_cast<JSObject**>(&wrapped));
           break;
       case CrossCompartmentKey::StringWrapper:
           MOZ_ASSERT(wrapped->asTenured().getTraceKind() == JS::TraceKind::String);
           keyDying = IsAboutToBeFinalizedUnbarriered(reinterpret_cast<JSString**>(&wrapped));
           break;
@@ -1010,17 +1014,17 @@ JSCompartment::updateDebuggerObservesFla
     MOZ_ASSERT(flag == DebuggerObservesAllExecution ||
                flag == DebuggerObservesCoverage ||
                flag == DebuggerObservesAsmJS);
 
     GlobalObject* global = zone()->runtimeFromMainThread()->gc.isForegroundSweeping()
                            ? unsafeUnbarrieredMaybeGlobal()
                            : maybeGlobal();
     const GlobalObject::DebuggerVector* v = global->getDebuggers();
-    for (Debugger * const* p = v->begin(); p != v->end(); p++) {
+    for (auto p = v->begin(); p != v->end(); p++) {
         Debugger* dbg = *p;
         if (flag == DebuggerObservesAllExecution ? dbg->observesAllExecution() :
             flag == DebuggerObservesCoverage ? dbg->observesCoverage() :
             dbg->observesAsmJS())
         {
             debugModeBits |= flag;
             return;
         }
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -68,17 +68,19 @@ class DtoaCache {
 struct CrossCompartmentKey
 {
     enum Kind {
         ObjectWrapper,
         StringWrapper,
         DebuggerScript,
         DebuggerSource,
         DebuggerObject,
-        DebuggerEnvironment
+        DebuggerEnvironment,
+        DebuggerWasmScript,
+        DebuggerWasmSource
     };
 
     Kind kind;
     JSObject* debugger;
     js::gc::Cell* wrapped;
 
     explicit CrossCompartmentKey(JSObject* wrapped)
       : kind(ObjectWrapper), debugger(nullptr), wrapped(wrapped)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2484,71 +2484,85 @@ UpdateCellPointers(MovingTracer* trc, Ar
       default:
         MOZ_CRASH("Invalid alloc kind for UpdateCellPointers");
     }
 }
 
 namespace js {
 namespace gc {
 
+struct ArenaListSegment
+{
+    Arena* begin;
+    Arena* end;
+};
+
 struct ArenasToUpdate
 {
-    enum KindsToUpdate {
+    enum UpdateKind {
+        NONE = 0,
         FOREGROUND = 1,
         BACKGROUND = 2,
         ALL = FOREGROUND | BACKGROUND
     };
-    ArenasToUpdate(Zone* zone, KindsToUpdate kinds);
+    ArenasToUpdate(Zone* zone, UpdateKind kind);
     bool done() { return kind == AllocKind::LIMIT; }
-    Arena* getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned max);
+    ArenaListSegment getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned maxLength);
 
   private:
-    KindsToUpdate kinds; // Selects which thing kinds to iterate
+    UpdateKind kinds; // Selects which thing kinds to iterate
     Zone* zone;          // Zone to process
     AllocKind kind;      // Current alloc kind to process
     Arena* arena;  // Next arena to process
 
     AllocKind nextAllocKind(AllocKind i) { return AllocKind(uint8_t(i) + 1); }
+    UpdateKind updateKind(AllocKind kind);
     bool shouldProcessKind(AllocKind kind);
     Arena* next(AutoLockHelperThreadState& lock);
 };
 
-bool ArenasToUpdate::shouldProcessKind(AllocKind kind)
+ArenasToUpdate::UpdateKind
+ArenasToUpdate::updateKind(AllocKind kind)
 {
     MOZ_ASSERT(IsValidAllocKind(kind));
 
     // GC things that do not contain JSObject pointers don't need updating.
     if (kind == AllocKind::FAT_INLINE_STRING ||
         kind == AllocKind::STRING ||
         kind == AllocKind::EXTERNAL_STRING ||
         kind == AllocKind::SYMBOL)
     {
-        return false;
+        return NONE;
     }
 
     // We try to update as many GC things in parallel as we can, but there are
     // kinds for which this might not be safe:
     //  - we assume JSObjects that are foreground finalized are not safe to
     //    update in parallel
     //  - updating a shape touches child shapes in fixupShapeTreeAfterMovingGC()
-    if (js::gc::IsBackgroundFinalized(kind) &&
-        kind != AllocKind::SHAPE &&
-        kind != AllocKind::ACCESSOR_SHAPE)
+    if (!js::gc::IsBackgroundFinalized(kind) ||
+        kind == AllocKind::SHAPE || kind == AllocKind::ACCESSOR_SHAPE)
     {
-        return (kinds & BACKGROUND) != 0;
-    } else {
-        return (kinds & FOREGROUND) != 0;
-    }
-}
-
-ArenasToUpdate::ArenasToUpdate(Zone* zone, KindsToUpdate kinds)
+        return FOREGROUND;
+    }
+
+    return BACKGROUND;
+}
+
+bool
+ArenasToUpdate::shouldProcessKind(AllocKind kind)
+{
+    return (updateKind(kind) & kinds) != 0;
+}
+
+ArenasToUpdate::ArenasToUpdate(Zone* zone, UpdateKind kinds)
   : kinds(kinds), zone(zone), kind(AllocKind::FIRST), arena(nullptr)
 {
     MOZ_ASSERT(zone->isGCCompacting());
-    MOZ_ASSERT(kinds && !(kinds & ~ALL));
+    MOZ_ASSERT(!(kinds & ~ALL));
 }
 
 Arena*
 ArenasToUpdate::next(AutoLockHelperThreadState& lock)
 {
     // Find the next arena to update.
     //
     // This iterates through the GC thing kinds filtered by shouldProcessKind(),
@@ -2566,153 +2580,135 @@ ArenasToUpdate::next(AutoLockHelperThrea
         }
     }
 
     MOZ_ASSERT(!arena);
     MOZ_ASSERT(done());
     return nullptr;
 }
 
-Arena*
-ArenasToUpdate::getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned count)
-{
-    if (done())
-        return nullptr;
-
-    Arena* head = nullptr;
-    Arena* tail = nullptr;
-
-    for (unsigned i = 0; i < count; ++i) {
-        Arena* arena = next(lock);
-        if (!arena)
-            break;
-
-        if (tail)
-            tail->setNextArenaToUpdate(arena);
-        else
-            head = arena;
-        tail = arena;
-    }
-
-    return head;
+ArenaListSegment
+ArenasToUpdate::getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned maxLength)
+{
+    Arena* begin = next(lock);
+    if (!begin)
+        return { nullptr, nullptr };
+
+    Arena* last = begin;
+    unsigned count = 1;
+    while (last->next && count < maxLength) {
+        last = last->next;
+        count++;
+    }
+
+    arena = last;
+    return { begin, last->next };
 }
 
 struct UpdateCellPointersTask : public GCParallelTask
 {
-    // Number of arenas to update in one block.
+    // Maximum number of arenas to update in one block.
 #ifdef DEBUG
-    static const unsigned ArenasToProcess = 16;
+    static const unsigned MaxArenasToProcess = 16;
 #else
-    static const unsigned ArenasToProcess = 256;
+    static const unsigned MaxArenasToProcess = 256;
 #endif
 
-    UpdateCellPointersTask() : rt_(nullptr), source_(nullptr), arenaList_(nullptr) {}
-    void init(JSRuntime* rt, ArenasToUpdate* source, AutoLockHelperThreadState& lock);
+    UpdateCellPointersTask(JSRuntime* rt, ArenasToUpdate* source, AutoLockHelperThreadState& lock)
+      : rt_(rt), source_(source)
+    {}
+
     ~UpdateCellPointersTask() override { join(); }
 
   private:
     JSRuntime* rt_;
     ArenasToUpdate* source_;
-    Arena* arenaList_;
+    ArenaListSegment arenas_;
 
     virtual void run() override;
-    void getArenasToUpdate(AutoLockHelperThreadState& lock);
+    bool getArenasToUpdate();
     void updateArenas();
 };
 
-void
-UpdateCellPointersTask::init(JSRuntime* rt, ArenasToUpdate* source, AutoLockHelperThreadState& lock)
-{
-    rt_ = rt;
-    source_ = source;
-    getArenasToUpdate(lock);
-}
-
-void
-UpdateCellPointersTask::getArenasToUpdate(AutoLockHelperThreadState& lock)
-{
-    arenaList_ = source_->getArenasToUpdate(lock, ArenasToProcess);
+bool
+UpdateCellPointersTask::getArenasToUpdate()
+{
+    AutoLockHelperThreadState lock;
+    arenas_ = source_->getArenasToUpdate(lock, MaxArenasToProcess);
+    return arenas_.begin != nullptr;
 }
 
 void
 UpdateCellPointersTask::updateArenas()
 {
     MovingTracer trc(rt_);
-    for (Arena* arena = arenaList_;
-         arena;
-         arena = arena->getNextArenaToUpdateAndUnlink())
-    {
+    for (Arena* arena = arenas_.begin; arena != arenas_.end; arena = arena->next)
         UpdateCellPointers(&trc, arena);
-    }
-    arenaList_ = nullptr;
 }
 
 /* virtual */ void
 UpdateCellPointersTask::run()
 {
-    MOZ_ASSERT(!HelperThreadState().isLocked());
-    while (arenaList_) {
+    while (getArenasToUpdate())
         updateArenas();
-        {
-            AutoLockHelperThreadState lock;
-            getArenasToUpdate(lock);
-        }
-    }
 }
 
 } // namespace gc
 } // namespace js
 
-void
-GCRuntime::updateAllCellPointersParallel(MovingTracer* trc, Zone* zone)
+static const size_t MinCellUpdateBackgroundTasks = 2;
+static const size_t MaxCellUpdateBackgroundTasks = 8;
+
+static size_t
+CellUpdateBackgroundTaskCount()
+{
+    if (!CanUseExtraThreads())
+        return 0;
+
+    size_t targetTaskCount = HelperThreadState().cpuCount / 2;
+    return Min(Max(targetTaskCount, MinCellUpdateBackgroundTasks), MaxCellUpdateBackgroundTasks);
+}
+
+void
+GCRuntime::updateAllCellPointers(MovingTracer* trc, Zone* zone)
 {
     AutoDisableProxyCheck noProxyCheck(rt); // These checks assert when run in parallel.
 
-    const size_t minTasks = 2;
-    const size_t maxTasks = 8;
-    size_t targetTaskCount = HelperThreadState().cpuCount / 2;
-    size_t taskCount = Min(Max(targetTaskCount, minTasks), maxTasks);
-    UpdateCellPointersTask bgTasks[maxTasks];
-    UpdateCellPointersTask fgTask;
-
-    ArenasToUpdate fgArenas(zone, ArenasToUpdate::FOREGROUND);
-    ArenasToUpdate bgArenas(zone, ArenasToUpdate::BACKGROUND);
-
-    unsigned tasksStarted = 0;
-    {
-        AutoLockHelperThreadState lock;
-        unsigned i;
-        for (i = 0; i < taskCount && !bgArenas.done(); ++i) {
-            bgTasks[i].init(rt, &bgArenas, lock);
-            startTask(bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
-        }
-        tasksStarted = i;
-
-        fgTask.init(rt, &fgArenas, lock);
-    }
-
-    fgTask.runFromMainThread(rt);
+    size_t bgTaskCount = CellUpdateBackgroundTaskCount();
+
+    ArenasToUpdate
+        fgArenas(zone, bgTaskCount == 0 ? ArenasToUpdate::ALL : ArenasToUpdate::FOREGROUND);
+    ArenasToUpdate
+        bgArenas(zone, bgTaskCount == 0 ? ArenasToUpdate::NONE : ArenasToUpdate::BACKGROUND);
+
+    Maybe<UpdateCellPointersTask> fgTask;
+    Maybe<UpdateCellPointersTask> bgTasks[MaxCellUpdateBackgroundTasks];
+
+    size_t tasksStarted = 0;
 
     {
         AutoLockHelperThreadState lock;
-        for (unsigned i = 0; i < tasksStarted; ++i)
-            joinTask(bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
-    }
-}
-
-void
-GCRuntime::updateAllCellPointersSerial(MovingTracer* trc, Zone* zone)
-{
-    UpdateCellPointersTask task;
+
+        fgTask.emplace(rt, &fgArenas, lock);
+
+        for (size_t i = 0; i < bgTaskCount && !bgArenas.done(); i++) {
+            bgTasks[i].emplace(rt, &bgArenas, lock);
+            startTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
+            tasksStarted = i;
+        }
+    }
+
+    fgTask->runFromMainThread(rt);
+
     {
         AutoLockHelperThreadState lock;
-        ArenasToUpdate allArenas(zone, ArenasToUpdate::ALL);
-        task.init(rt, &allArenas, lock);
-    }
-    task.runFromMainThread(rt);
+
+        for (size_t i = 0; i < tasksStarted; i++)
+            joinTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS);
+    }
 }
 
 /*
  * Update pointers to relocated cells by doing a full heap traversal and sweep.
  *
  * The latter is necessary to update weak references which are not marked as
  * part of the traversal.
  */
@@ -2768,20 +2764,17 @@ GCRuntime::updatePointersToRelocatedCell
     // Call callbacks to get the rest of the system to fixup other untraced pointers.
     callWeakPointerZoneGroupCallbacks();
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
         callWeakPointerCompartmentCallbacks(comp);
 
     // Finally, iterate through all cells that can contain JSObject pointers to
     // update them. Since updating each cell is independent we try to
     // parallelize this as much as possible.
-    if (CanUseExtraThreads())
-        updateAllCellPointersParallel(&trc, zone);
-    else
-        updateAllCellPointersSerial(&trc, zone);
+    updateAllCellPointers(&trc, zone);
 }
 
 void
 GCRuntime::protectAndHoldArenas(Arena* arenaList)
 {
     for (Arena* arena = arenaList; arena; ) {
         MOZ_ASSERT(arena->allocated());
         Arena* next = arena->next;
@@ -4141,16 +4134,18 @@ GCRuntime::markCompartments()
         for (JSCompartment::WrapperEnum e(c); !e.empty(); e.popFront()) {
             const CrossCompartmentKey& key = e.front().key();
             JSCompartment* dest;
             switch (key.kind) {
               case CrossCompartmentKey::ObjectWrapper:
               case CrossCompartmentKey::DebuggerObject:
               case CrossCompartmentKey::DebuggerSource:
               case CrossCompartmentKey::DebuggerEnvironment:
+              case CrossCompartmentKey::DebuggerWasmScript:
+              case CrossCompartmentKey::DebuggerWasmSource:
                 dest = static_cast<JSObject*>(key.wrapped)->compartment();
                 break;
               case CrossCompartmentKey::DebuggerScript:
                 dest = static_cast<JSScript*>(key.wrapped)->compartment();
                 break;
               default:
                 dest = nullptr;
                 break;
@@ -4584,17 +4579,19 @@ JSCompartment::findOutgoingEdges(Compone
                 JS::Zone* w = other.zone();
                 if (w->isGCMarking())
                     finder.addEdgeTo(w);
             }
         } else {
             MOZ_ASSERT(kind == CrossCompartmentKey::DebuggerScript ||
                        kind == CrossCompartmentKey::DebuggerSource ||
                        kind == CrossCompartmentKey::DebuggerObject ||
-                       kind == CrossCompartmentKey::DebuggerEnvironment);
+                       kind == CrossCompartmentKey::DebuggerEnvironment ||
+                       kind == CrossCompartmentKey::DebuggerWasmScript ||
+                       kind == CrossCompartmentKey::DebuggerWasmSource);
             /*
              * Add edge for debugger object wrappers, to ensure (in conjuction
              * with call to Debugger::findCompartmentEdges below) that debugger
              * and debuggee objects are always swept in the same group.
              */
             JS::Zone* w = other.zone();
             if (w->isGCMarking())
                 finder.addEdgeTo(w);
@@ -6423,17 +6420,19 @@ GCRuntime::collect(bool nonincrementalBy
 
     AutoTraceLog logGC(TraceLoggerForMainThread(rt), TraceLogger_GC);
     AutoStopVerifyingBarriers av(rt, IsShutdownGC(reason));
     AutoEnqueuePendingParseTasksAfterGC aept(*this);
     AutoScheduleZonesForGC asz(rt);
     gcstats::AutoGCSlice agc(stats, scanZonesBeforeGC(), invocationKind, budget, reason);
 
     bool repeat = false;
+    unsigned cycleCount = 0;
     do {
+        cycleCount++;
         poked = false;
         bool wasReset = gcCycle(nonincrementalByAPI, budget, reason);
 
         /* Need to re-schedule all zones for GC. */
         if (poked && cleanUpEverything)
             JS::PrepareForFullGC(rt);
 
         /*
@@ -6456,16 +6455,18 @@ GCRuntime::collect(bool nonincrementalBy
         /*
          * If we reset an existing GC, we need to start a new one. Also, we
          * repeat GCs that happen during shutdown (the gcShouldCleanUpEverything
          * case) until we can be sure that no additional garbage is created
          * (which typically happens if roots are dropped during finalizers).
          */
         repeat = (poked && cleanUpEverything) || wasReset || repeatForDeadZone;
     } while (repeat);
+
+    agc.setCycleCount(cycleCount);
 }
 
 js::AutoEnqueuePendingParseTasksAfterGC::~AutoEnqueuePendingParseTasksAfterGC()
 {
     if (!gc_.isIncrementalGCInProgress())
         EnqueuePendingParseTasksAfterGC(gc_.rt);
 }
 
@@ -7781,10 +7782,26 @@ NewMemoryInfoObject(JSContext* cx)
         {
             return nullptr;
         }
     }
 
     return obj;
 }
 
+const char*
+StateName(State state)
+{
+    static const char* names[] = {
+        "None",
+        "MarkRoots",
+        "Mark",
+        "Sweep",
+        "Finalize",
+        "Compact"
+    };
+    MOZ_ASSERT(ArrayLength(names) == NUM_STATES);
+    MOZ_ASSERT(state < NUM_STATES);
+    return names[state];
+}
+
 } /* namespace gc */
 } /* namespace js */
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -43,17 +43,19 @@ namespace gc {
 struct FinalizePhase;
 
 enum State {
     NO_INCREMENTAL,
     MARK_ROOTS,
     MARK,
     SWEEP,
     FINALIZE,
-    COMPACT
+    COMPACT,
+
+    NUM_STATES
 };
 
 /* Map from C++ type to alloc kind. JSObject does not have a 1:1 mapping, so must use Arena::thingSize. */
 template <typename T> struct MapTypeToFinalizeKind {};
 template <> struct MapTypeToFinalizeKind<JSScript>          { static const AllocKind kind = AllocKind::SCRIPT; };
 template <> struct MapTypeToFinalizeKind<LazyScript>        { static const AllocKind kind = AllocKind::LAZY_SCRIPT; };
 template <> struct MapTypeToFinalizeKind<Shape>             { static const AllocKind kind = AllocKind::SHAPE; };
 template <> struct MapTypeToFinalizeKind<AccessorShape>     { static const AllocKind kind = AllocKind::ACCESSOR_SHAPE; };
@@ -1284,16 +1286,19 @@ struct MOZ_RAII AutoAssertNoNurseryAlloc
 
   private:
     gc::GCRuntime& gc;
 #else
     explicit AutoAssertNoNurseryAlloc(JSRuntime* rt) {}
 #endif
 };
 
+const char*
+StateName(State state);
+
 } /* namespace gc */
 
 #ifdef DEBUG
 /* Use this to avoid assertions when manipulating the wrapper map. */
 class MOZ_RAII AutoDisableProxyCheck
 {
     gc::GCRuntime& gc;
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -448,17 +448,17 @@ class JSObject : public js::gc::Cell
      * above it before the global object is reached.
      */
 
     /*
      * Get the enclosing scope of an object. When called on non-scope object,
      * this will just be the global (the name "enclosing scope" still applies
      * in this situation because non-scope objects can be on the scope chain).
      */
-    inline JSObject* enclosingScope();
+    inline JSObject* enclosingScope() const;
 
     inline js::GlobalObject& global() const;
     inline bool isOwnGlobal() const;
 
     /*
      * ES5 meta-object properties and operations.
      */
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -126,17 +126,20 @@ Bindings::initWithTemporaryStorage(Exclu
     // JITs when interpreting/compiling aliasedvar ops.)
 
     // Since unaliased variables are, by definition, only accessed by local
     // operations and never through the scope chain, only give shapes to
     // aliased variables. While the debugger may observe any scope object at
     // any time, such accesses are mediated by DebugScopeProxy (see
     // DebugScopeProxy::handleUnaliasedAccess).
     uint32_t nslots = CallObject::RESERVED_SLOTS;
-    uint32_t aliasedBodyLevelLexicalBegin = UINT16_MAX;
+
+    // Unless there are aliased body-level lexical bindings at all, set the
+    // begin index to an impossible slot number.
+    uint32_t aliasedBodyLevelLexicalBegin = LOCALNO_LIMIT;
     for (BindingIter bi(self); bi; bi++) {
         if (bi->aliased()) {
             // Per ES6, lexical bindings cannot be accessed until
             // initialized. Remember the first aliased slot that is a
             // body-level lexical, so that they may be initialized to sentinel
             // magic values.
             if (numBodyLevelLexicals > 0 &&
                 nslots < aliasedBodyLevelLexicalBegin &&
@@ -4276,21 +4279,24 @@ LazyScript::initScript(JSScript* script)
 void
 LazyScript::resetScript()
 {
     MOZ_ASSERT(script_.unbarrieredGet());
     script_.set(nullptr);
 }
 
 void
-LazyScript::setParent(JSObject* enclosingScope, ScriptSourceObject* sourceObject)
+LazyScript::setEnclosingScopeAndSource(JSObject* enclosingScope, ScriptSourceObject* sourceObject)
 {
-    MOZ_ASSERT(!sourceObject_ && !enclosingScope_);
     MOZ_ASSERT_IF(enclosingScope, function_->compartment() == enclosingScope->compartment());
     MOZ_ASSERT(function_->compartment() == sourceObject->compartment());
+    // This method may be called to update the enclosing scope. See comment
+    // above the callsite in BytecodeEmitter::emitFunction.
+    MOZ_ASSERT_IF(sourceObject_, sourceObject_ == sourceObject && enclosingScope_);
+    MOZ_ASSERT_IF(!sourceObject_, !enclosingScope_);
 
     enclosingScope_ = enclosingScope;
     sourceObject_ = sourceObject;
 }
 
 ScriptSourceObject*
 LazyScript::sourceObject() const
 {
@@ -4391,17 +4397,17 @@ LazyScript::Create(ExclusiveContext* cx,
 
     HeapPtrFunction* functions = res->innerFunctions();
     for (i = 0, num = res->numInnerFunctions(); i < num; i++)
         functions[i].init(dummyFun);
 
     // Set the enclosing scope of the lazy function, this would later be
     // used to define the environment when the function would be used.
     MOZ_ASSERT(!res->sourceObject());
-    res->setParent(enclosingScope, &sourceObjectScript->scriptSourceUnwrap());
+    res->setEnclosingScopeAndSource(enclosingScope, &sourceObjectScript->scriptSourceUnwrap());
 
     MOZ_ASSERT(!res->hasScript());
     if (script)
         res->initScript(script);
 
     return res;
 }
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -223,18 +223,18 @@ class Bindings
     template <typename Outer> friend class BindingsOperations;
     template <typename Outer> friend class MutableBindingsOperations;
 
     RelocatablePtrShape callObjShape_;
     uintptr_t bindingArrayAndFlag_;
     uint16_t numArgs_;
     uint16_t numBlockScoped_;
     uint16_t numBodyLevelLexicals_;
-    uint16_t aliasedBodyLevelLexicalBegin_;
     uint16_t numUnaliasedBodyLevelLexicals_;
+    uint32_t aliasedBodyLevelLexicalBegin_;
     uint32_t numVars_;
     uint32_t numUnaliasedVars_;
 
 #if JS_BITS_PER_WORD == 32
     // Bindings is allocated inline inside JSScript, which needs to be
     // gc::Cell aligned.
     uint32_t padding_;
 #endif
@@ -351,16 +351,20 @@ class Bindings
 
     Binding* begin() const { return bindingArray(); }
     Binding* end() const { return bindingArray() + count(); }
 
     static void trace(Bindings* self, JSTracer* trc) { self->trace(trc); }
     void trace(JSTracer* trc);
 };
 
+// If this fails, add/remove padding within Bindings.
+static_assert(sizeof(Bindings) % js::gc::CellSize == 0,
+              "Size of Bindings must be an integral multiple of js::gc::CellSize");
+
 template <class Outer>
 class BindingsOperations
 {
     const Bindings& bindings() const { return static_cast<const Outer*>(this)->get(); }
 
   public:
     // Direct data access to the underlying bindings.
     const RelocatablePtrShape& callObjShape() const {
@@ -433,17 +437,17 @@ class MutableBindingsOperations : public
     void setNumArgs(uint16_t num) { bindings().numArgs_ = num; }
     void setNumVars(uint32_t num) { bindings().numVars_ = num; }
     void setNumBodyLevelLexicals(uint16_t num) { bindings().numBodyLevelLexicals_ = num; }
     void setNumBlockScoped(uint16_t num) { bindings().numBlockScoped_ = num; }
     void setNumUnaliasedVars(uint32_t num) { bindings().numUnaliasedVars_ = num; }
     void setNumUnaliasedBodyLevelLexicals(uint16_t num) {
         bindings().numUnaliasedBodyLevelLexicals_ = num;
     }
-    void setAliasedBodyLevelLexicalBegin(uint16_t offset) {
+    void setAliasedBodyLevelLexicalBegin(uint32_t offset) {
         bindings().aliasedBodyLevelLexicalBegin_ = offset;
     }
     uint8_t* switchToScriptStorage(Binding* permanentStorage) {
         return bindings().switchToScriptStorage(permanentStorage);
     }
 };
 
 template <>
@@ -2267,17 +2271,17 @@ class LazyScript : public gc::TenuredCel
     bool mutedErrors() const {
         return scriptSource()->mutedErrors();
     }
     JSVersion version() const {
         JS_STATIC_ASSERT(JSVERSION_UNKNOWN == -1);
         return (p_.version == JS_BIT(8) - 1) ? JSVERSION_UNKNOWN : JSVersion(p_.version);
     }
 
-    void setParent(JSObject* enclosingScope, ScriptSourceObject* sourceObject);
+    void setEnclosingScopeAndSource(JSObject* enclosingScope, ScriptSourceObject* sourceObject);
 
     uint32_t numFreeVariables() const {
         return p_.numFreeVariables;
     }
     FreeVariable* freeVariables() {
         return (FreeVariable*)table_;
     }
 
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -1892,42 +1892,16 @@ MOZ_ARG_ENABLE_STRING([update-channel],
     MOZ_UPDATE_CHANNEL=`echo $enableval | tr A-Z a-z`)
 
 if test -z "$MOZ_UPDATE_CHANNEL"; then
     MOZ_UPDATE_CHANNEL=default
 fi
 AC_DEFINE_UNQUOTED(MOZ_UPDATE_CHANNEL, $MOZ_UPDATE_CHANNEL)
 AC_SUBST(MOZ_UPDATE_CHANNEL)
 
-
-dnl set GRE_MILESTONE
-dnl ========================================================
-GRE_MILESTONE=`tail -n 1 "$_topsrcdir"/config/milestone.txt 2>/dev/null || tail -1 "$_topsrcdir"/config/milestone.txt`
-AC_SUBST(GRE_MILESTONE)