merge mozilla-inbound to mozilla-central a=merge
authorIris Hsiao <ihsiao@mozilla.com>
Tue, 02 May 2017 11:04:36 +0800
changeset 404053 2e7c10a9b86e30691f67855f6c8f98d984508d7c
parent 404017 5178fedbc8f2decf28bf0173260e85d0f1dc5da7 (current diff)
parent 404052 adabba6c5f74af837c5ea66dfa7086ce6d1d3e69 (diff)
child 404061 7fb7f5cfbd55d711e9e4882ed43d14524bdc09c4
child 404081 e94824b92c00d84910271435ff8d19e256e3f6ee
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
toolkit/xre/nsUpdateDriver.cpp
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4297,36 +4297,55 @@ function BrowserCustomizeToolbar() {
 function updateEditUIVisibility() {
   if (AppConstants.platform == "macosx")
     return;
 
   let editMenuPopupState = document.getElementById("menu_EditPopup").state;
   let contextMenuPopupState = document.getElementById("contentAreaContextMenu").state;
   let placesContextMenuPopupState = document.getElementById("placesContext").state;
 
+  let oldVisible = gEditUIVisible;
+
   // The UI is visible if the Edit menu is opening or open, if the context menu
   // is open, or if the toolbar has been customized to include the Cut, Copy,
   // or Paste toolbar buttons.
   gEditUIVisible = editMenuPopupState == "showing" ||
                    editMenuPopupState == "open" ||
                    contextMenuPopupState == "showing" ||
                    contextMenuPopupState == "open" ||
                    placesContextMenuPopupState == "showing" ||
-                   placesContextMenuPopupState == "open" ||
-                   document.getElementById("edit-controls") ? true : false;
+                   placesContextMenuPopupState == "open";
+  if (!gEditUIVisible) {
+    // Now check the edit-controls toolbar buttons.
+    let placement = CustomizableUI.getPlacementOfWidget("edit-controls");
+    let areaType = placement ? CustomizableUI.getAreaType(placement.area) : "";
+    if (areaType == CustomizableUI.TYPE_MENU_PANEL) {
+      let panelUIMenuPopupState = document.getElementById("PanelUI-popup").state;
+      if (panelUIMenuPopupState == "showing" || panelUIMenuPopupState == "open") {
+        gEditUIVisible = true;
+      }
+    } else if (areaType == CustomizableUI.TYPE_TOOLBAR) {
+      // The edit controls are on a toolbar, so they are visible.
+      gEditUIVisible = true;
+    }
+  }
+
+  // No need to update commands if the edit UI visibility has not changed.
+  if (gEditUIVisible == oldVisible) {
+    return;
+  }
 
   // If UI is visible, update the edit commands' enabled state to reflect
   // whether or not they are actually enabled for the current focus/selection.
-  if (gEditUIVisible)
+  if (gEditUIVisible) {
     goUpdateGlobalEditMenuItems();
-
-  // Otherwise, enable all commands, so that keyboard shortcuts still work,
-  // then lazily determine their actual enabled state when the user presses
-  // a keyboard shortcut.
-  else {
+  } else {
+    // Otherwise, enable all commands, so that keyboard shortcuts still work,
+    // then lazily determine their actual enabled state when the user presses
+    // a keyboard shortcut.
     goSetCommandEnabled("cmd_undo", true);
     goSetCommandEnabled("cmd_redo", true);
     goSetCommandEnabled("cmd_cut", true);
     goSetCommandEnabled("cmd_copy", true);
     goSetCommandEnabled("cmd_paste", true);
     goSetCommandEnabled("cmd_selectAll", true);
     goSetCommandEnabled("cmd_delete", true);
     goSetCommandEnabled("cmd_switchTextDirection", true);
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1060,16 +1060,18 @@
         <parameter name="aForceUpdate"/>
         <body>
           <![CDATA[
             var newBrowser = this.getBrowserAtIndex(this.tabContainer.selectedIndex);
             if (this.mCurrentBrowser == newBrowser && !aForceUpdate)
               return;
 
             if (!aForceUpdate) {
+              document.commandDispatcher.lock();
+
               TelemetryStopwatch.start("FX_TAB_SWITCH_UPDATE_MS");
               if (!gMultiProcessBrowser) {
                 // old way of measuring tab paint which is not valid with e10s.
                 // Waiting until the next MozAfterPaint ensures that we capture
                 // the time it takes to paint, upload the textures to the compositor,
                 // and then composite.
                 if (this._tabSwitchID) {
                   TelemetryStopwatch.cancel("FX_TAB_SWITCH_TOTAL_MS");
@@ -1269,16 +1271,18 @@
             }
 
             updateUserContextUIIndicator();
             gIdentityHandler.updateSharingIndicator();
 
             this.tabContainer._setPositionalAttributes();
 
             if (!gMultiProcessBrowser) {
+              document.commandDispatcher.unlock();
+
               let event = new CustomEvent("TabSwitchDone", {
                 bubbles: true,
                 cancelable: true
               });
               this.dispatchEvent(event);
             }
 
             if (!aForceUpdate)
@@ -3976,16 +3980,18 @@
               let fromBrowser = this.originalTab.linkedBrowser;
               // It's possible that the tab we're switching from closed
               // before we were able to finalize, in which case, fromBrowser
               // doesn't exist.
               if (fromBrowser) {
                 fromBrowser.removeAttribute("primary");
               }
 
+              document.commandDispatcher.unlock();
+
               let event = new CustomEvent("TabSwitchDone", {
                 bubbles: true,
                 cancelable: true
               });
               this.tabbrowser.dispatchEvent(event);
             },
 
             // This function is called after all the main state changes to
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -11,9 +11,10 @@ skip-if = !e10s # Tab spinner is e10s on
 skip-if = !e10s # Tab spinner is e10s only.
 [browser_tabSwitchPrintPreview.js]
 skip-if = os == 'mac'
 [browser_navigatePinnedTab.js]
 [browser_new_web_tab_in_file_process_pref.js]
 skip-if = !e10s # Pref and test only relevant for e10s.
 [browser_opened_file_tab_navigated_to_web.js]
 [browser_reload_deleted_file.js]
+[browser_tabswitch_updatecommands.js]
 [browser_viewsource_of_data_URI_in_file_process.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabs/browser_tabswitch_updatecommands.js
@@ -0,0 +1,21 @@
+// This test ensures that only one command update happens when switching tabs.
+
+"use strict";
+
+add_task(function* () {
+  const uri = "data:text/html,<body><input>";
+  let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
+  let tab2 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, uri);
+
+  let updates = 0;
+  function countUpdates(event) { updates++; }
+  let updater = document.getElementById("editMenuCommandSetAll");
+  updater.addEventListener("commandupdate", countUpdates, true);
+  yield BrowserTestUtils.switchTab(gBrowser, tab1);
+
+  is(updates, 1, "only one command update per tab switch");
+
+  updater.removeEventListener("commandupdate", countUpdates, true);
+  yield BrowserTestUtils.removeTab(tab1);
+  yield BrowserTestUtils.removeTab(tab2);
+});
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -155,21 +155,16 @@ const PanelUI = {
     return new Promise(resolve => {
       this.ensureReady().then(() => {
         if (this.panel.state == "open" ||
             document.documentElement.hasAttribute("customizing")) {
           resolve();
           return;
         }
 
-        let editControlPlacement = CustomizableUI.getPlacementOfWidget("edit-controls");
-        if (editControlPlacement && editControlPlacement.area == CustomizableUI.AREA_PANEL) {
-          updateEditUIVisibility();
-        }
-
         let personalBookmarksPlacement = CustomizableUI.getPlacementOfWidget("personal-bookmarks");
         if (personalBookmarksPlacement &&
             personalBookmarksPlacement.area == CustomizableUI.AREA_PANEL) {
           PlacesToolbarHelper.customizeChange();
         }
 
         let anchor;
         if (!aEvent ||
@@ -287,20 +282,24 @@ const PanelUI = {
     // Ignore context menus and menu button menus showing and hiding:
     if (aEvent.type.startsWith("popup") &&
         aEvent.target != this.panel) {
       return;
     }
     switch (aEvent.type) {
       case "popupshowing":
         this._adjustLabelsForAutoHyphens();
+        updateEditUIVisibility();
         // Fall through
       case "popupshown":
         // Fall through
       case "popuphiding":
+        if (aEvent.type == "popuphiding") {
+          updateEditUIVisibility();
+        }
         // Fall through
       case "popuphidden":
         this._updateNotifications();
         this._updatePanelButton(aEvent.target);
         break;
       case "mousedown":
         if (aEvent.button == 0)
           this.toggle(aEvent);
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -150,8 +150,10 @@ skip-if = os == "mac"
 [browser_customizemode_contextmenu_menubuttonstate.js]
 [browser_exit_background_customize_mode.js]
 [browser_overflow_use_subviews.js]
 [browser_panel_toggle.js]
 [browser_panelUINotifications.js]
 [browser_switch_to_customize_mode.js]
 [browser_synced_tabs_menu.js]
 [browser_check_tooltips_in_navbar.js]
+[browser_editcontrols_update.js]
+subsuite = clipboard
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_editcontrols_update.js
@@ -0,0 +1,162 @@
+// This test checks that the edit command enabled state (cut/paste) is updated
+// properly when the edit controls are on the toolbar, popup and not present.
+// It also verifies that the performance optimiation implemented by
+// updateEditUIVisibility in browser.js is applied.
+
+let isMac = navigator.platform.indexOf("Mac") == 0;
+
+function checkState(allowCut, desc, testWindow = window) {
+  is(testWindow.document.getElementById("cmd_cut").getAttribute("disabled") == "true", !allowCut, desc + " - cut");
+  is(testWindow.document.getElementById("cmd_paste").getAttribute("disabled") == "true", false, desc + " - paste");
+}
+
+// Add a special controller to the urlbar and browser to listen in on when
+// commands are being updated. Return a promise that resolves when 'count'
+// updates have occurred.
+function expectCommandUpdate(count, testWindow = window) {
+  return new Promise((resolve, reject) => {
+    let overrideController = {
+      supportsCommand(cmd) { return cmd == "cmd_delete"; },
+      isCommandEnabled(cmd) {
+        if (!count) {
+          ok(false, "unexpected update");
+          reject();
+        }
+
+        if (!--count) {
+          testWindow.gURLBar.controllers.removeControllerAt(0, overrideController);
+          testWindow.gBrowser.selectedBrowser.controllers.removeControllerAt(0, overrideController);
+          resolve(true);
+        }
+      }
+    };
+
+    if (!count) {
+      SimpleTest.executeSoon(() => {
+        testWindow.gURLBar.controllers.removeControllerAt(0, overrideController);
+        testWindow.gBrowser.selectedBrowser.controllers.removeControllerAt(0, overrideController);
+        resolve(false);
+      });
+    }
+
+    testWindow.gURLBar.controllers.insertControllerAt(0, overrideController);
+    testWindow.gBrowser.selectedBrowser.controllers.insertControllerAt(0, overrideController);
+  });
+}
+
+add_task(function* test_init() {
+  // Put something on the clipboard to verify that the paste button is properly enabled during the test.
+  let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
+  yield new Promise(resolve => {
+    SimpleTest.waitForClipboard("Sample", function() { clipboardHelper.copyString("Sample"); }, resolve);
+  });
+
+  // Open and close the panel first so that it is fully initialized.
+  yield PanelUI.show();
+  let hiddenPromise = promisePanelHidden(window);
+  PanelUI.hide();
+  yield hiddenPromise;
+});
+
+// Test updating when the panel is open with the edit-controls on the panel.
+// Updates should occur.
+add_task(function* test_panelui_opened() {
+  gURLBar.focus();
+  gURLBar.value = "test";
+
+  yield PanelUI.show();
+
+  checkState(false, "Update when edit-controls is on panel and visible");
+
+  let overridePromise = expectCommandUpdate(1);
+  gURLBar.select();
+  yield overridePromise;
+
+  checkState(true, "Update when edit-controls is on panel and selection changed");
+
+  overridePromise = expectCommandUpdate(0);
+  let hiddenPromise = promisePanelHidden(window);
+  PanelUI.hide();
+  yield hiddenPromise;
+  yield overridePromise;
+
+  // Check that updates do not occur after the panel has been closed.
+  checkState(true, "Update when edit-controls is on panel and hidden");
+
+  // Mac will update the enabled st1ate even when the panel is closed so that
+  // main menubar shortcuts will work properly.
+  overridePromise = expectCommandUpdate(isMac ? 1 : 0);
+  gURLBar.select();
+  yield overridePromise;
+  checkState(true, "Update when edit-controls is on panel, hidden and selection changed");
+});
+
+// Test updating when the edit-controls are moved to the toolbar.
+add_task(function* test_panelui_customize_to_toolbar() {
+  yield startCustomizing();
+  let navbar = document.getElementById("nav-bar").customizationTarget;
+  simulateItemDrag(document.getElementById("edit-controls"), navbar);
+  yield endCustomizing();
+
+  // updateEditUIVisibility should be called when customization ends but isn't. See bug 1359790.
+  updateEditUIVisibility();
+
+  let overridePromise = expectCommandUpdate(1);
+  gURLBar.select();
+  gURLBar.focus();
+  gURLBar.value = "other";
+  yield overridePromise;
+  checkState(false, "Update when edit-controls on toolbar and focused");
+
+  overridePromise = expectCommandUpdate(1);
+  gURLBar.select();
+  yield overridePromise;
+  checkState(true, "Update when edit-controls on toolbar and selection changed");
+});
+
+// Test updating when the edit-controls are moved to the palette.
+add_task(function* test_panelui_customize_to_palette() {
+  yield startCustomizing();
+  let palette = document.getElementById("customization-palette");
+  simulateItemDrag(document.getElementById("edit-controls"), palette);
+  yield endCustomizing();
+
+  // updateEditUIVisibility should be called when customization ends but isn't. See bug 1359790.
+  updateEditUIVisibility();
+
+  let overridePromise = expectCommandUpdate(isMac ? 1 : 0);
+  gURLBar.focus();
+  gURLBar.value = "other";
+  gURLBar.select();
+  yield overridePromise;
+
+  // If the UI isn't found, the command is set to be enabled.
+  checkState(true, "Update when edit-controls is on palette, hidden and selection changed");
+});
+
+add_task(function* finish() {
+  yield resetCustomization();
+});
+
+// Test updating in the initial state when the edit-controls are on the panel but
+// have not yet been created. This needs to be done in a new window to ensure that
+// other tests haven't opened the panel.
+add_task(function* test_initial_state() {
+  let testWindow = yield BrowserTestUtils.openNewBrowserWindow();
+  yield SimpleTest.promiseFocus(testWindow);
+
+  let overridePromise = expectCommandUpdate(isMac, testWindow);
+
+  testWindow.gURLBar.focus();
+  testWindow.gURLBar.value = "test";
+
+  yield overridePromise;
+
+  // Commands won't update when no edit UI is present. They default to being
+  // enabled so that keyboard shortcuts will work. The real enabled state will
+  // be checked when shortcut is pressed.
+  checkState(!isMac, "No update when edit-controls is on panel and not visible", testWindow);
+
+  yield BrowserTestUtils.closeWindow(testWindow);
+  yield SimpleTest.promiseFocus(window);
+});
--- a/browser/config/mozconfigs/linux32/devedition
+++ b/browser/config/mozconfigs/linux32/devedition
@@ -7,10 +7,12 @@ ac_add_options --enable-verify-mar
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 ac_add_options --with-branding=browser/branding/aurora
 
+mk_add_options MOZ_PGO=1
+
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/linux64/devedition
+++ b/browser/config/mozconfigs/linux64/devedition
@@ -7,10 +7,12 @@ ac_add_options --enable-verify-mar
 
 # This will overwrite the default of stripping everything and keep the symbol table.
 # This is useful for profiling and debugging and only increases the package size
 # by 2 MBs.
 STRIP_FLAGS="--strip-debug"
 
 ac_add_options --with-branding=browser/branding/aurora
 
+mk_add_options MOZ_PGO=1
+
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win32/devedition
+++ b/browser/config/mozconfigs/win32/devedition
@@ -3,10 +3,12 @@
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
 
 ac_add_options --enable-verify-mar
 
 ac_add_options --with-branding=browser/branding/aurora
 
+mk_add_options MOZ_PGO=1
+
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.cache"
--- a/browser/config/mozconfigs/win64/devedition
+++ b/browser/config/mozconfigs/win64/devedition
@@ -4,10 +4,12 @@
 
 # Add-on signing is not required for DevEdition
 MOZ_REQUIRE_SIGNING=0
 
 ac_add_options --enable-verify-mar
 
 ac_add_options --with-branding=browser/branding/aurora
 
+mk_add_options MOZ_PGO=1
+
 . "$topsrcdir/build/mozconfig.common.override"
 . "$topsrcdir/build/mozconfig.cache"
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-cond.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-cond.js
@@ -8,16 +8,18 @@ function findBreakpoint(dbg, url, line) 
 }
 
 function setConditionalBreakpoint(dbg, index, condition) {
   return Task.spawn(function* () {
     rightClickElement(dbg, "gutter", index);
     selectMenuItem(dbg, 2);
     yield waitForElement(dbg, ".conditional-breakpoint-panel input");
     findElementWithSelector(dbg, ".conditional-breakpoint-panel input").focus();
+    // Position cursor reliably at the end of the text.
+    pressKey(dbg, "End")
     type(dbg, condition);
     pressKey(dbg, "Enter");
   });
 }
 
 add_task(function* () {
   const dbg = yield initDebugger("doc-scripts.html");
   yield selectSource(dbg, "simple2");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
@@ -27,16 +27,18 @@ async function addExpression(dbg, input)
   pressKey(dbg, "Enter");
 
   await waitForDispatch(dbg, "EVALUATE_EXPRESSION");
 }
 
 async function editExpression(dbg, input) {
   info("updating the expression");
   dblClickElement(dbg, "expressionNode", 1);
+  // Position cursor reliably at the end of the text.
+  pressKey(dbg, "End")
   type(dbg, input);
   pressKey(dbg, "Enter");
   await waitForDispatch(dbg, "EVALUATE_EXPRESSION");
 }
 
 add_task(function*() {
   const dbg = yield initDebugger("doc-script-switching.html");
 
--- a/devtools/client/debugger/new/test/mochitest/head.js
+++ b/devtools/client/debugger/new/test/mochitest/head.js
@@ -555,16 +555,20 @@ function invokeInTab(fnc) {
 const isLinux = Services.appinfo.OS === "Linux";
 const cmdOrCtrl = isLinux ? { ctrlKey: true } : { metaKey: true };
 const keyMappings = {
   sourceSearch: { code: "p", modifiers: cmdOrCtrl },
   fileSearch: { code: "f", modifiers: cmdOrCtrl },
   Enter: { code: "VK_RETURN" },
   Up: { code: "VK_UP" },
   Down: { code: "VK_DOWN" },
+  Right: { code: "VK_RIGHT" },
+  Left: { code: "VK_LEFT" },
+  End: { code: "VK_RIGHT", modifiers: cmdOrCtrl },
+  Start: { code: "VK_LEFT", modifiers: cmdOrCtrl },
   Tab: { code: "VK_TAB" },
   Escape: { code: "VK_ESCAPE" },
   pauseKey: { code: "VK_F8" },
   resumeKey: { code: "VK_F8" },
   stepOverKey: { code: "VK_F10" },
   stepInKey: { code: "VK_F11", modifiers: { ctrlKey: isLinux } },
   stepOutKey: {
     code: "VK_F11",
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -292,16 +292,17 @@ bool nsContentUtils::sIsExperimentalAuto
 bool nsContentUtils::sIsWebComponentsEnabled = false;
 bool nsContentUtils::sIsCustomElementsEnabled = false;
 bool nsContentUtils::sPrivacyResistFingerprinting = false;
 bool nsContentUtils::sSendPerformanceTimingNotifications = false;
 bool nsContentUtils::sUseActivityCursor = false;
 bool nsContentUtils::sAnimationsAPICoreEnabled = false;
 bool nsContentUtils::sAnimationsAPIElementAnimateEnabled = false;
 bool nsContentUtils::sGetBoxQuadsEnabled = false;
+bool nsContentUtils::sSkipCursorMoveForSameValueSet = false;
 
 int32_t nsContentUtils::sPrivacyMaxInnerWidth = 1000;
 int32_t nsContentUtils::sPrivacyMaxInnerHeight = 1000;
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
 uint32_t nsContentUtils::sCookiesLifetimePolicy = nsICookieService::ACCEPT_NORMALLY;
 uint32_t nsContentUtils::sCookiesBehavior = nsICookieService::BEHAVIOR_ACCEPT;
@@ -640,16 +641,20 @@ nsContentUtils::Init()
                                "dom.animations-api.core.enabled", false);
 
   Preferences::AddBoolVarCache(&sAnimationsAPIElementAnimateEnabled,
                                "dom.animations-api.element-animate.enabled", false);
 
   Preferences::AddBoolVarCache(&sGetBoxQuadsEnabled,
                                "layout.css.getBoxQuads.enabled", false);
 
+  Preferences::AddBoolVarCache(&sSkipCursorMoveForSameValueSet,
+                               "dom.input.skip_cursor_move_for_same_value_set",
+                               true);
+
   Element::InitCCCallbacks();
 
   nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
     do_GetService("@mozilla.org/uuid-generator;1", &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
   uuidGenerator.forget(&sUUIDGenerator);
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2883,16 +2883,23 @@ public:
   static bool
   IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }
 
   /**
    * Compose a tab id with process id and a serial number.
    */
   static uint64_t GenerateTabId();
 
+  /**
+   * Check whether we should skip moving the cursor for a same-value .value set
+   * on a text input or textarea.
+   */
+  static bool
+  SkipCursorMoveForSameValueSet() { return sSkipCursorMoveForSameValueSet; }
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
@@ -3007,16 +3014,17 @@ private:
   static bool sIsWebComponentsEnabled;
   static bool sIsCustomElementsEnabled;
   static bool sPrivacyResistFingerprinting;
   static bool sSendPerformanceTimingNotifications;
   static bool sUseActivityCursor;
   static bool sAnimationsAPICoreEnabled;
   static bool sAnimationsAPIElementAnimateEnabled;
   static bool sGetBoxQuadsEnabled;
+  static bool sSkipCursorMoveForSameValueSet;
   static uint32_t sCookiesLifetimePolicy;
   static uint32_t sCookiesBehavior;
 
   static int32_t sPrivacyMaxInnerWidth;
   static int32_t sPrivacyMaxInnerHeight;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
   static nsIParser* sXMLFragmentParser;
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -568,17 +568,20 @@ class IDLExternalInterface(IDLObjectWith
 
     def isInterface(self):
         return True
 
     def isConsequential(self):
         return False
 
     def addExtendedAttributes(self, attrs):
-        assert len(attrs) == 0
+        if len(attrs) != 0:
+            raise WebIDLError("There are no extended attributes that are "
+                              "allowed on external interfaces",
+                              [attrs[0].location, self.location])
 
     def resolve(self, parentScope):
         pass
 
     def getJSImplementation(self):
         return None
 
     def isJSImplemented(self):
@@ -1927,17 +1930,20 @@ class IDLDictionary(IDLObjectWithScope):
                                   [member.location])
             (contains, locations) = typeContainsDictionary(member.type, self)
             if contains:
                 raise WebIDLError("Dictionary %s has member with itself as type." %
                                   self.identifier.name,
                                   [member.location] + locations)
 
     def addExtendedAttributes(self, attrs):
-        assert len(attrs) == 0
+        if len(attrs) != 0:
+            raise WebIDLError("There are no extended attributes that are "
+                              "allowed on dictionaries",
+                              [attrs[0].location, self.location])
 
     def _getDependentObjects(self):
         deps = set(self.members)
         if (self.parent):
             deps.add(self.parent)
         return deps
 
 
@@ -1961,17 +1967,20 @@ class IDLEnum(IDLObjectWithIdentifier):
 
     def validate(self):
         pass
 
     def isEnum(self):
         return True
 
     def addExtendedAttributes(self, attrs):
-        assert len(attrs) == 0
+        if len(attrs) != 0:
+            raise WebIDLError("There are no extended attributes that are "
+                              "allowed on enums",
+                              [attrs[0].location, self.location])
 
     def _getDependentObjects(self):
         return set()
 
 
 class IDLType(IDLObject):
     Tags = enum(
         # The integer types
@@ -2134,17 +2143,21 @@ class IDLType(IDLObject):
         assert self.tag() == IDLType.Tags.callback
         return self.nullable() and self.inner.callback._treatNonCallableAsNull
 
     def treatNonObjectAsNull(self):
         assert self.tag() == IDLType.Tags.callback
         return self.nullable() and self.inner.callback._treatNonObjectAsNull
 
     def addExtendedAttributes(self, attrs):
-        assert len(attrs) == 0
+        if len(attrs) != 0:
+            raise WebIDLError("There are no extended attributes that are "
+                              "allowed on types, for now (but this is "
+                              "changing; see bug 1359269)",
+                              [attrs[0].location, self.location])
 
     def resolveType(self, parentScope):
         pass
 
     def unroll(self):
         return self
 
     def isDistinguishableFrom(self, other):
@@ -2702,17 +2715,20 @@ class IDLTypedef(IDLObjectWithIdentifier
 
     def validate(self):
         pass
 
     def isTypedef(self):
         return True
 
     def addExtendedAttributes(self, attrs):
-        assert len(attrs) == 0
+        if len(attrs) != 0:
+            raise WebIDLError("There are no extended attributes that are "
+                              "allowed on typedefs",
+                              [attrs[0].location, self.location])
 
     def _getDependentObjects(self):
         return self.innerType._getDependentObjects()
 
 
 class IDLWrapperType(IDLType):
     def __init__(self, location, inner):
         IDLType.__init__(self, location, inner.identifier.name)
@@ -5103,17 +5119,20 @@ class IDLImplementsStatement(IDLObject):
         implementor.addImplementedInterface(implementee)
         self.implementor = implementor
         self.implementee = implementee
 
     def validate(self):
         pass
 
     def addExtendedAttributes(self, attrs):
-        assert len(attrs) == 0
+        if len(attrs) != 0:
+            raise WebIDLError("There are no extended attributes that are "
+                              "allowed on implements statements",
+                              [attrs[0].location, self.location])
 
 
 class IDLExtendedAttribute(IDLObject):
     """
     A class to represent IDL extended attributes so we can give them locations
     """
     def __init__(self, location, tuple):
         IDLObject.__init__(self, location)
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -1969,32 +1969,34 @@ HTMLInputElement::SetValue(const nsAStri
       // element will not fire any event because of the script interaction.
       //
       // NOTE: this is currently quite expensive work (too much string
       // manipulation). We should probably optimize that.
       nsAutoString currentValue;
       GetValue(currentValue, aCallerType);
 
       nsresult rv =
-        SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
-                                 nsTextEditorState::eSetValue_Notify |
-                                 nsTextEditorState::eSetValue_MoveCursorToEnd);
+        SetValueInternal(aValue,
+          nsTextEditorState::eSetValue_ByContent |
+          nsTextEditorState::eSetValue_Notify |
+          nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
       if (NS_FAILED(rv)) {
         aRv.Throw(rv);
         return;
       }
 
       if (mFocusedValue.Equals(currentValue)) {
         GetValue(mFocusedValue, aCallerType);
       }
     } else {
       nsresult rv =
-        SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
-                                 nsTextEditorState::eSetValue_Notify |
-                                 nsTextEditorState::eSetValue_MoveCursorToEnd);
+        SetValueInternal(aValue,
+          nsTextEditorState::eSetValue_ByContent |
+          nsTextEditorState::eSetValue_Notify |
+          nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
       if (NS_FAILED(rv)) {
         aRv.Throw(rv);
         return;
       }
     }
   }
 }
 
@@ -2838,19 +2840,19 @@ HTMLInputElement::SetUserInput(const nsA
     }
 
     ErrorResult rv;
     MozSetFileNameArray(list, rv);
     return rv.StealNSResult();
   } else {
     nsresult rv =
       SetValueInternal(aValue,
-                       nsTextEditorState::eSetValue_BySetUserInput |
-                       nsTextEditorState::eSetValue_Notify|
-                       nsTextEditorState::eSetValue_MoveCursorToEnd);
+        nsTextEditorState::eSetValue_BySetUserInput |
+        nsTextEditorState::eSetValue_Notify|
+        nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
                                        static_cast<nsIDOMHTMLInputElement*>(this),
                                        NS_LITERAL_STRING("input"), true,
                                        true);
 
--- a/dom/html/HTMLTextAreaElement.cpp
+++ b/dom/html/HTMLTextAreaElement.cpp
@@ -399,35 +399,36 @@ HTMLTextAreaElement::SetValue(const nsAS
   // element will not fire any event because of the script interaction.
   //
   // NOTE: this is currently quite expensive work (too much string
   // manipulation). We should probably optimize that.
   nsAutoString currentValue;
   GetValueInternal(currentValue, true);
 
   nsresult rv =
-    SetValueInternal(aValue, nsTextEditorState::eSetValue_ByContent |
-                             nsTextEditorState::eSetValue_Notify |
-                             nsTextEditorState::eSetValue_MoveCursorToEnd);
+    SetValueInternal(aValue,
+      nsTextEditorState::eSetValue_ByContent |
+      nsTextEditorState::eSetValue_Notify |
+      nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mFocusedValue.Equals(currentValue)) {
     GetValueInternal(mFocusedValue, true);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
 {
   return SetValueInternal(aValue,
-                          nsTextEditorState::eSetValue_BySetUserInput |
-                          nsTextEditorState::eSetValue_Notify|
-                          nsTextEditorState::eSetValue_MoveCursorToEnd);
+    nsTextEditorState::eSetValue_BySetUserInput |
+    nsTextEditorState::eSetValue_Notify|
+    nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
 }
 
 NS_IMETHODIMP
 HTMLTextAreaElement::SetValueChanged(bool aValueChanged)
 {
   bool previousValue = mValueChanged;
 
   mValueChanged = aValueChanged;
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -2498,16 +2498,22 @@ nsTextEditorState::SetValue(const nsAStr
         }
       } else {
         NS_WARNING("SetValue() is called when there is composition but "
                    "it's not safe to request to commit the composition");
       }
     }
   }
 
+  // \r is an illegal character in the dom, but people use them,
+  // so convert windows and mac platform linebreaks to \n:
+  if (!nsContentUtils::PlatformToDOMLineBreaks(newValue, fallible)) {
+    return false;
+  }
+
   if (mEditor && mBoundFrame) {
     // The InsertText call below might flush pending notifications, which
     // could lead into a scheduled PrepareEditor to be called.  That will
     // lead to crashes (or worse) because we'd be initializing the editor
     // before InsertText returns.  This script blocker makes sure that
     // PrepareEditor cannot be called prematurely.
     nsAutoScriptBlocker scriptBlocker;
 
@@ -2523,24 +2529,16 @@ nsTextEditorState::SetValue(const nsAStr
 
     AutoWeakFrame weakFrame(mBoundFrame);
 
     // this is necessary to avoid infinite recursion
     if (!currentValue.Equals(newValue))
     {
       ValueSetter valueSetter(mEditor);
 
-      // \r is an illegal character in the dom, but people use them,
-      // so convert windows and mac platform linebreaks to \n:
-      if (newValue.FindChar(char16_t('\r')) != -1) {
-        if (!nsContentUtils::PlatformToDOMLineBreaks(newValue, fallible)) {
-          return false;
-        }
-      }
-
       nsCOMPtr<nsIDOMDocument> domDoc;
       mEditor->GetDocument(getter_AddRefs(domDoc));
       if (!domDoc) {
         NS_WARNING("Why don't we have a document?");
         return true;
       }
 
       // Time to mess with our security context... See comments in GetValue()
@@ -2633,43 +2631,52 @@ nsTextEditorState::SetValue(const nsAStr
         if (selPriv)
           selPriv->EndBatchChanges();
       }
     }
   } else {
     if (!mValue) {
       mValue.emplace();
     }
-    nsString value;
-    if (!value.Assign(newValue, fallible)) {
-      return false;
-    }
-    if (!nsContentUtils::PlatformToDOMLineBreaks(value, fallible)) {
-      return false;
-    }
-    if (!mValue->Assign(value, fallible)) {
-      return false;
-    }
-
-    // Since we have no editor we presumably have cached selection state.
-    if (IsSelectionCached()) {
-      SelectionProperties& props = GetSelectionProperties();
-      if (aFlags & eSetValue_MoveCursorToEnd) {
-        props.SetStart(value.Length());
-        props.SetEnd(value.Length());
-      } else {
-        // Make sure our cached selection position is not outside the new value.
-        props.SetStart(std::min(props.GetStart(), value.Length()));
-        props.SetEnd(std::min(props.GetEnd(), value.Length()));
+
+    // We can't just early-return here if mValue->Equals(newValue), because
+    // ValueWasChanged and OnValueChanged below still need to be called.
+    if (!mValue->Equals(newValue) ||
+        !nsContentUtils::SkipCursorMoveForSameValueSet()) {
+      if (!mValue->Assign(newValue, fallible)) {
+        return false;
       }
-    }
-
-    // Update the frame display if needed
-    if (mBoundFrame) {
-      mBoundFrame->UpdateValueDisplay(true);
+
+      // Since we have no editor we presumably have cached selection state.
+      if (IsSelectionCached()) {
+        SelectionProperties& props = GetSelectionProperties();
+        if (aFlags & eSetValue_MoveCursorToEndIfValueChanged) {
+          props.SetStart(newValue.Length());
+          props.SetEnd(newValue.Length());
+          props.SetDirection(nsITextControlFrame::eForward);
+        } else {
+          // Make sure our cached selection position is not outside the new value.
+          props.SetStart(std::min(props.GetStart(), newValue.Length()));
+          props.SetEnd(std::min(props.GetEnd(), newValue.Length()));
+        }
+      }
+
+      // Update the frame display if needed
+      if (mBoundFrame) {
+        mBoundFrame->UpdateValueDisplay(true);
+      }
+    } else {
+      // Even if our value is not actually changing, apparently we need to mark
+      // our SelectionProperties dirty to make accessibility tests happy.
+      // Probably because they depend on the SetSelectionRange() call we make on
+      // our frame in RestoreSelectionState, but I have no idea why they do.
+      if (IsSelectionCached()) {
+        SelectionProperties& props = GetSelectionProperties();
+        props.SetIsDirty();
+      }
     }
   }
 
   // If we've reached the point where the root node has been created, we
   // can assume that it's safe to notify.
   ValueWasChanged(!!mRootNode);
 
   mTextCtrlElement->OnValueChanged(/* aNotify = */ !!mRootNode,
--- a/dom/html/nsTextEditorState.h
+++ b/dom/html/nsTextEditorState.h
@@ -168,19 +168,21 @@ public:
     // The value is changed by a call of setUserInput() from chrome.
     eSetValue_BySetUserInput        = 1 << 0,
     // The value is changed by changing value attribute of the element or
     // something like setRangeText().
     eSetValue_ByContent             = 1 << 1,
     // Whether the value change should be notified to the frame/contet nor not.
     eSetValue_Notify                = 1 << 2,
     // Whether to move the cursor to end of the value (in the case when we have
-    // cached selection offsets).  If this is not set, the cached selection
-    // offsets will simply be clamped to be within the length of the new value.
-    eSetValue_MoveCursorToEnd       = 1 << 3,
+    // cached selection offsets), in the case when the value has changed.  If
+    // this is not set, the cached selection offsets will simply be clamped to
+    // be within the length of the new value.  In either case, if the value has
+    // not changed the cursor won't move.
+    eSetValue_MoveCursorToEndIfValueChanged = 1 << 3,
   };
   MOZ_MUST_USE bool SetValue(const nsAString& aValue, uint32_t aFlags);
   void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
   void EmptyValue() { if (mValue) mValue->Truncate(); }
   bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
 
   nsresult CreatePlaceholderNode();
   nsresult CreatePreviewNode();
@@ -275,21 +277,26 @@ public:
       {
         return mDirection;
       }
       void SetDirection(nsITextControlFrame::SelectionDirection value)
       {
         mIsDirty = true;
         mDirection = value;
       }
-      // return true only if mStart, mEnd, or mDirection have been modified
+      // return true only if mStart, mEnd, or mDirection have been modified,
+      // or if SetIsDirty() was explicitly called.
       bool IsDirty() const
       {
         return mIsDirty;
       }
+      void SetIsDirty()
+      {
+        mIsDirty = true;
+      }
     private:
       uint32_t mStart, mEnd;
       bool mIsDirty = false;
       nsITextControlFrame::SelectionDirection mDirection;
   };
 
   bool IsSelectionCached() const;
   SelectionProperties& GetSelectionProperties();
--- a/dom/interfaces/xul/nsIDOMXULCommandDispatcher.idl
+++ b/dom/interfaces/xul/nsIDOMXULCommandDispatcher.idl
@@ -26,9 +26,14 @@ interface nsIDOMXULCommandDispatcher : n
 
   nsIController             getControllerForCommand(in string command);
   nsIControllers            getControllers();
 
   void advanceFocus();
   void rewindFocus();
   void advanceFocusIntoSubtree(in nsIDOMElement elt);
   attribute boolean suppressFocusScroll;
+
+  // When locked, command updating is batched until unlocked. Always ensure that
+  // lock and unlock is called in a pair.
+  void lock();
+  void unlock();
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -5050,17 +5050,17 @@ ContentParent::ForceTabPaint(TabParent* 
 {
   if (!mHangMonitorActor) {
     return;
   }
   ProcessHangMonitor::ForcePaint(mHangMonitorActor, aTabParent, aLayerObserverEpoch);
 }
 
 nsresult
-ContentParent::AboutToLoadDocumentForChild(nsIChannel* aChannel)
+ContentParent::AboutToLoadHttpFtpWyciwygDocumentForChild(nsIChannel* aChannel)
 {
   MOZ_ASSERT(aChannel);
 
   nsresult rv;
   if (!aChannel->IsDocument()) {
     return NS_OK;
   }
 
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -651,17 +651,17 @@ public:
 
   // Use the PHangMonitor channel to ask the child to repaint a tab.
   void ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch);
 
   // This function is called when we are about to load a document from an
   // HTTP(S), FTP or wyciwyg channel for a content process.  It is a useful
   // place to start to kick off work as early as possible in response to such
   // document loads.
-  nsresult AboutToLoadDocumentForChild(nsIChannel* aChannel);
+  nsresult AboutToLoadHttpFtpWyciwygDocumentForChild(nsIChannel* aChannel);
 
   nsresult TransmitPermissionsForPrincipal(nsIPrincipal* aPrincipal);
 
 protected:
   void OnChannelConnected(int32_t pid) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -936,16 +936,20 @@ TabParent::RecvPDocAccessibleConstructor
       return IPC_FAIL_NO_REASON(this);
     }
 
     doc->SetTopLevel();
     a11y::DocManager::RemoteDocAdded(doc);
 #ifdef XP_WIN
     a11y::WrapperFor(doc)->SetID(aMsaaID);
     MOZ_ASSERT(!aDocCOMProxy.IsNull());
+    if (aDocCOMProxy.IsNull()) {
+      return IPC_FAIL(this, "Constructing a top-level PDocAccessible with null COM proxy");
+    }
+
     RefPtr<IAccessible> proxy(aDocCOMProxy.Get());
     doc->SetCOMInterface(proxy);
     doc->MaybeInitWindowEmulation();
     doc->SendParentCOMProxy();
 #endif
   }
 #endif
   return IPC_OK();
--- a/dom/xul/nsXULCommandDispatcher.cpp
+++ b/dom/xul/nsXULCommandDispatcher.cpp
@@ -37,17 +37,17 @@
 
 using namespace mozilla;
 
 static LazyLogModule gCommandLog("nsXULCommandDispatcher");
 
 ////////////////////////////////////////////////////////////////////////
 
 nsXULCommandDispatcher::nsXULCommandDispatcher(nsIDocument* aDocument)
-    : mDocument(aDocument), mUpdaters(nullptr)
+    : mDocument(aDocument), mUpdaters(nullptr), mLocked(false)
 {
 }
 
 nsXULCommandDispatcher::~nsXULCommandDispatcher()
 {
   Disconnect();
 }
 
@@ -345,16 +345,24 @@ nsXULCommandDispatcher::RemoveCommandUpd
 
   // Hmm. Not found. Oh well.
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXULCommandDispatcher::UpdateCommands(const nsAString& aEventName)
 {
+  if (mLocked) {
+    if (!mPendingUpdates.Contains(aEventName)) {
+      mPendingUpdates.AppendElement(aEventName);
+    }
+
+    return NS_OK;
+  }
+
   nsAutoString id;
   nsCOMPtr<nsIDOMElement> element;
   GetFocusedElement(getter_AddRefs(element));
   if (element) {
     nsresult rv = element->GetAttribute(NS_LITERAL_STRING("id"), id);
     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get element's id");
     if (NS_FAILED(rv)) return rv;
   }
@@ -452,8 +460,35 @@ nsXULCommandDispatcher::GetSuppressFocus
 }
 
 NS_IMETHODIMP
 nsXULCommandDispatcher::SetSuppressFocusScroll(bool aSuppressFocusScroll)
 {
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsXULCommandDispatcher::Lock()
+{
+  // Since locking is used only as a performance optimization, we don't worry
+  // about nested lock calls. If that does happen, it just means we will unlock
+  // and process updates earlier.
+  mLocked = true;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULCommandDispatcher::Unlock()
+{
+  if (mLocked) {
+    mLocked = false;
+
+    // Handle any pending updates one at a time. In the unlikely case where a
+    // lock is added during the update, break out.
+    while (!mLocked && mPendingUpdates.Length() > 0) {
+      nsString name = mPendingUpdates.ElementAt(0);
+      mPendingUpdates.RemoveElementAt(0);
+      UpdateCommands(name);
+    }
+  }
+
+  return NS_OK;
+}
--- a/dom/xul/nsXULCommandDispatcher.h
+++ b/dom/xul/nsXULCommandDispatcher.h
@@ -63,11 +63,14 @@ protected:
       nsString                mTargets;
       Updater*                mNext;
     };
 
     Updater* mUpdaters;
 
     bool Matches(const nsString& aList, 
                    const nsAString& aElement);
+
+    bool mLocked;
+    nsTArray<nsString> mPendingUpdates;
 };
 
 #endif // nsXULCommandDispatcher_h__
--- a/gfx/skia/skia/src/core/SkBitmapProcState.cpp
+++ b/gfx/skia/skia/src/core/SkBitmapProcState.cpp
@@ -295,17 +295,17 @@ bool SkBitmapProcState::chooseScanlinePr
                 index |= 40;
                 fPaintPMColor = SkPreMultiplyColor(fPaintColor);
                 break;
             default:
                 // TODO(dominikg): Should we ever get here? SkASSERT(false) instead?
                 return false;
         }
 
-#if !defined(SK_ARM_HAS_NEON)
+#if !defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON)
         static const SampleProc32 gSkBitmapProcStateSample32[] = {
             S32_opaque_D32_nofilter_DXDY,
             S32_alpha_D32_nofilter_DXDY,
             S32_opaque_D32_nofilter_DX,
             S32_alpha_D32_nofilter_DX,
             S32_opaque_D32_filter_DXDY,
             S32_alpha_D32_filter_DXDY,
             S32_opaque_D32_filter_DX,
--- a/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp
+++ b/gfx/skia/skia/src/core/SkBitmapProcState_matrixProcs.cpp
@@ -51,17 +51,17 @@ void decal_filter_scale(uint32_t dst[], 
 
 // These are defined in src/opts/SkBitmapProcState_matrixProcs_neon.cpp
 extern const SkBitmapProcState::MatrixProc ClampX_ClampY_Procs_neon[];
 extern const SkBitmapProcState::MatrixProc RepeatX_RepeatY_Procs_neon[];
 
 #endif // defined(SK_ARM_HAS_NEON)
 
 // Compile non-neon code path if needed
-#if !defined(SK_ARM_HAS_NEON)
+#if !defined(SK_ARM_HAS_NEON) || defined(SK_ARM_HAS_OPTIONAL_NEON)
 #define MAKENAME(suffix)        ClampX_ClampY ## suffix
 #define TILEX_PROCF(fx, max)    SkClampMax((fx) >> 16, max)
 #define TILEY_PROCF(fy, max)    SkClampMax((fy) >> 16, max)
 #define TILEX_LOW_BITS(fx, max) (((fx) >> 12) & 0xF)
 #define TILEY_LOW_BITS(fy, max) (((fy) >> 12) & 0xF)
 #define CHECK_FOR_DECAL
 #include "SkBitmapProcState_matrix.h"
 
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -1212,18 +1212,18 @@ gfxFT2FontList::FindFonts()
             FinalizeFamilyMemberList(key, family, /* aSortFaces */ false);
         }
         for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
             nsStringHashKey::KeyType key = iter.Key();
             RefPtr<gfxFontFamily>& family = iter.Data();
             FinalizeFamilyMemberList(key, family, /* aSortFaces */ false );
         }
 
-        LOG(("got font list from chrome process: %d faces in %d families "
-             "and %d in hidden families",
+        LOG(("got font list from chrome process: %" PRIdPTR " faces in %"
+             PRIu32 " families and %" PRIu32 " in hidden families",
             fonts.Length(), mFontFamilies.Count(),
             mHiddenFontFamilies.Count()));
         return;
     }
 
     // Chrome process: get the cached list (if any)
     if (!mFontNameCache) {
         mFontNameCache = MakeUnique<FontNameCache>();
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1547,23 +1547,29 @@ class MOZ_STACK_CLASS TryEmitter
 
     // Track jumps-over-catches and gosubs-to-finally for later fixup.
     //
     // When a finally block is active, non-local jumps (including
     // jumps-over-catches) result in a GOSUB being written into the bytecode
     // stream and fixed-up later.
     //
     // If ShouldUseControl is DontUseControl, all that handling is skipped.
-    // DontUseControl is used by yield*, that matches to the following:
-    //   * has only one catch block
-    //   * has no catch guard
-    //   * has JSOP_GOTO at the end of catch-block
-    //   * has no non-local-jump
-    //   * doesn't use finally block for normal completion of try-block and
+    // DontUseControl is used by yield* and the internal try-catch around
+    // IteratorClose. These internal uses must:
+    //   * have only one catch block
+    //   * have no catch guard
+    //   * have JSOP_GOTO at the end of catch-block
+    //   * have no non-local-jump
+    //   * don't use finally block for normal completion of try-block and
     //     catch-block
+    //
+    // Additionally, a finally block may be emitted when ShouldUseControl is
+    // DontUseControl, even if the kind is not TryCatchFinally or TryFinally,
+    // because GOSUBs are not emitted. This internal use shares the
+    // requirements as above.
     Maybe<TryFinallyControl> controlInfo_;
 
     int depth_;
     unsigned noteIndex_;
     ptrdiff_t tryStart_;
     JumpList catchAndFinallyJump_;
     JumpTarget tryEnd_;
     JumpTarget finallyStart_;
@@ -1721,17 +1727,27 @@ class MOZ_STACK_CLASS TryEmitter
             }
         }
 
         return true;
     }
 
   public:
     bool emitFinally(const Maybe<uint32_t>& finallyPos = Nothing()) {
-        MOZ_ASSERT(hasFinally());
+        // If we are using controlInfo_ (i.e., emitting a syntactic try
+        // blocks), we must have specified up front if there will be a finally
+        // close. For internal try blocks, like those emitted for yield* and
+        // IteratorClose inside for-of loops, we can emitFinally even without
+        // specifying up front, since the internal try blocks emit no GOSUBs.
+        if (!controlInfo_) {
+            if (kind_ == TryCatch)
+                kind_ = TryCatchFinally;
+        } else {
+            MOZ_ASSERT(hasFinally());
+        }
 
         if (state_ == Try) {
             if (!emitTryEnd())
                 return false;
         } else {
             MOZ_ASSERT(state_ == Catch);
             if (!emitCatchEnd(false))
                 return false;
@@ -2017,35 +2033,45 @@ class ForOfLoopControl : public LoopCont
     //       // Just throw again when iterator is cleared by non-local jump.
     //       if (iterator === undefined)
     //         throw e;
     //       IteratorClose(iterator, { throw, e });
     //     }
     //   }
     Maybe<TryEmitter> tryCatch_;
 
+    // Used to track if any yields were emitted between calls to to
+    // emitBeginCodeNeedingIteratorClose and emitEndCodeNeedingIteratorClose.
+    uint32_t numYieldsAtBeginCodeNeedingIterClose_;
+
     bool allowSelfHosted_;
 
     IteratorKind iterKind_;
 
   public:
     ForOfLoopControl(BytecodeEmitter* bce, int32_t iterDepth, bool allowSelfHosted,
                      IteratorKind iterKind)
       : LoopControl(bce, StatementKind::ForOfLoop),
         iterDepth_(iterDepth),
+        numYieldsAtBeginCodeNeedingIterClose_(UINT32_MAX),
         allowSelfHosted_(allowSelfHosted),
         iterKind_(iterKind)
     {
     }
 
     bool emitBeginCodeNeedingIteratorClose(BytecodeEmitter* bce) {
-        tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal);
+        tryCatch_.emplace(bce, TryEmitter::TryCatch, TryEmitter::DontUseRetVal,
+                          TryEmitter::DontUseControl);
 
         if (!tryCatch_->emitTry())
             return false;
+
+        MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
+        numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
+
         return true;
     }
 
     bool emitEndCodeNeedingIteratorClose(BytecodeEmitter* bce) {
         if (!tryCatch_->emitCatch())              // ITER ...
             return false;
 
         if (!bce->emit1(JSOP_EXCEPTION))          // ITER ... EXCEPTION
@@ -2073,20 +2099,43 @@ class ForOfLoopControl : public LoopCont
             return false;
 
         if (!ifIteratorIsNotClosed.emitEnd())     // ITER ... EXCEPTION
             return false;
 
         if (!bce->emit1(JSOP_THROW))              // ITER ...
             return false;
 
+        // If any yields were emitted, then this for-of loop is inside a star
+        // generator and must handle the case of Generator.return. Like in
+        // yield*, it is handled with a finally block.
+        uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
+        if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
+            if (!tryCatch_->emitFinally())
+                return false;
+
+            IfThenElseEmitter ifGeneratorClosing(bce);
+            if (!bce->emit1(JSOP_ISGENCLOSING))   // ITER ... FTYPE FVALUE CLOSING
+                return false;
+            if (!ifGeneratorClosing.emitIf())     // ITER ... FTYPE FVALUE
+                return false;
+            if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
+                return false;
+            if (!emitIteratorClose(bce, CompletionKind::Normal)) // ITER ... FTYPE FVALUE
+                return false;
+            if (!ifGeneratorClosing.emitEnd())    // ITER ... FTYPE FVALUE
+                return false;
+        }
+
         if (!tryCatch_->emitEnd())
             return false;
 
         tryCatch_.reset();
+        numYieldsAtBeginCodeNeedingIterClose_ = UINT32_MAX;
+
         return true;
     }
 
     bool emitIteratorClose(BytecodeEmitter* bce,
                            CompletionKind completionKind = CompletionKind::Normal) {
         ptrdiff_t start = bce->offset();
         if (!bce->emitIteratorClose(iterKind_, completionKind, allowSelfHosted_))
             return false;
@@ -4824,16 +4873,21 @@ BytecodeEmitter::emitYieldOp(JSOp op)
         return false;
 
     uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
     if (yieldAndAwaitIndex >= JS_BIT(24)) {
         reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
         return false;
     }
 
+    if (op == JSOP_AWAIT)
+        yieldAndAwaitOffsetList.numAwaits++;
+    else
+        yieldAndAwaitOffsetList.numYields++;
+
     SET_UINT24(code(off), yieldAndAwaitIndex);
 
     if (!yieldAndAwaitOffsetList.append(offset()))
         return false;
 
     return emit1(JSOP_DEBUGAFTERYIELD);
 }
 
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -96,17 +96,19 @@ struct CGScopeNoteList {
                              uint32_t parent);
     void recordEnd(uint32_t index, uint32_t offset, bool inPrologue);
     size_t length() const { return list.length(); }
     void finish(ScopeNoteArray* array, uint32_t prologueLength);
 };
 
 struct CGYieldAndAwaitOffsetList {
     Vector<uint32_t> list;
-    explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx) {}
+    uint32_t numYields;
+    uint32_t numAwaits;
+    explicit CGYieldAndAwaitOffsetList(JSContext* cx) : list(cx), numYields(0), numAwaits(0) {}
 
     MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
     size_t length() const { return list.length(); }
     void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
 };
 
 // Use zero inline elements because these go on the stack and affect how many
 // nested functions are possible.
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -1272,22 +1272,22 @@ CacheIRCompiler::emitGuardIsInt32Index()
     Register output = allocator.defineRegister(masm, reader.int32OperandId());
 
     if (allocator.knownType(inputId) == JSVAL_TYPE_INT32) {
         Register input = allocator.useRegister(masm, Int32OperandId(inputId.id()));
         masm.move32(input, output);
         return true;
     }
 
+    ValueOperand input = allocator.useValueRegister(masm, inputId);
+
     FailurePath* failure;
     if (!addFailurePath(&failure))
         return false;
 
-    ValueOperand input = allocator.useValueRegister(masm, inputId);
-
     Label notInt32, done;
     masm.branchTestInt32(Assembler::NotEqual, input, &notInt32);
     masm.unboxInt32(input, output);
     masm.jump(&done);
 
     masm.bind(&notInt32);
 
     if (cx_->runtime()->jitSupportsFloatingPoint) {
--- a/js/src/jsapi-tests/testGCAllocator.cpp
+++ b/js/src/jsapi-tests/testGCAllocator.cpp
@@ -310,17 +310,17 @@ void unmapPages(void* p, size_t size) { 
 #elif defined(XP_UNIX)
 
 void*
 mapMemoryAt(void* desired, size_t length)
 {
 
 #if defined(__ia64__) || defined(__aarch64__) || \
     (defined(__sparc__) && defined(__arch64__) && (defined(__NetBSD__) || defined(__linux__)))
-    MOZ_RELEASE_ASSERT(0xffff800000000000ULL & (uintptr_t(desired) + length - 1) == 0);
+    MOZ_RELEASE_ASSERT((0xffff800000000000ULL & (uintptr_t(desired) + length - 1)) == 0);
 #endif
     void* region = mmap(desired, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     if (region == MAP_FAILED)
         return nullptr;
     if (region != desired) {
         if (munmap(region, length))
             MOZ_RELEASE_ASSERT(errno == ENOMEM);
         return nullptr;
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -61,16 +61,18 @@
 # include <sys/syscall.h> // For SYS_getrandom.
 
 // Older glibc versions don't define SYS_getrandom, so we define it here if
 // it's not available. See bug 995069.
 # if defined(__x86_64__)
 #  define GETRANDOM_NR 318
 # elif defined(__i386__)
 #  define GETRANDOM_NR 355
+# elif defined(__aarch64__)
+#  define GETRANDOM_NR 278
 # elif defined(__arm__)
 #  define GETRANDOM_NR 384
 // Added other architectures:
 # elif defined(__ppc64le__)
 #  define GETRANDOM_NR 359
 # elif defined(__PPC64LE__)
 #  define GETRANDOM_NR 359
 # elif defined(__ppc64__)
--- a/js/src/jsnativestack.cpp
+++ b/js/src/jsnativestack.cpp
@@ -11,17 +11,17 @@
 
 #elif defined(XP_DARWIN) || defined(DARWIN) || defined(XP_UNIX)
 # include <pthread.h>
 
 # if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
 #  include <pthread_np.h>
 # endif
 
-# if defined(ANDROID)
+# if defined(ANDROID) && !defined(__aarch64__)
 #  include <sys/types.h>
 #  include <unistd.h>
 # endif
 
 #else
 # error "Unsupported platform"
 
 #endif
@@ -115,21 +115,21 @@ js::GetNativeStackBaseImpl()
 
     void* stackBase = 0;
     size_t stackSize = 0;
     int rc;
 # if defined(__OpenBSD__)
     rc = pthread_stackseg_np(pthread_self(), &ss);
     stackBase = (void*)((size_t) ss.ss_sp - ss.ss_size);
     stackSize = ss.ss_size;
-# elif defined(ANDROID)
+# elif defined(ANDROID) && !defined(__aarch64__)
     if (gettid() == getpid()) {
-        // bionic's pthread_attr_getstack doesn't tell the truth for the main
-        // thread (see bug 846670). So we scan /proc/self/maps to find the
-        // segment which contains the stack.
+        // bionic's pthread_attr_getstack prior to API 21 doesn't tell the truth
+        // for the main thread (see bug 846670). So we scan /proc/self/maps to
+        // find the segment which contains the stack.
         rc = -1;
 
         // Put the string on the stack, otherwise there is the danger that it
         // has not been decompressed by the the on-demand linker. Bug 1165460.
         //
         // The volatile keyword should stop the compiler from trying to omit
         // the stack copy in the future (hopefully).
         volatile char path[] = "/proc/self/maps";
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/yield-iterator-close.js
@@ -0,0 +1,58 @@
+// Test that IteratorClose is called when a Generator is abruptly completed by
+// Generator.return.
+
+var returnCalled = 0;
+function* wrapNoThrow() {
+  let iter = {
+    [Symbol.iterator]() {
+      return this;
+    },
+    next() {
+      return { value: 10, done: false };
+    },
+    return() {
+      returnCalled++;
+      return {};
+    }
+  };
+  for (const i of iter) {
+    yield i;
+  }
+}
+
+// Breaking calls Generator.return, which causes the yield above to resume with
+// an abrupt completion of kind "return", which then calls
+// iter.return.
+for (const i of wrapNoThrow()) {
+  break;
+}
+assertEq(returnCalled, 1);
+
+function* wrapThrow() {
+  let iter = {
+    [Symbol.iterator]() {
+      return this;
+    },
+    next() {
+      return { value: 10, done: false };
+    },
+    return() {
+      throw 42;
+    }
+  };
+  for (const i of iter) {
+    yield i;
+  }
+}
+
+// Breaking calls Generator.return, which, like above, calls iter.return. If
+// iter.return throws, since the yield is resuming with an abrupt completion of
+// kind "return", the newly thrown value takes precedence over returning.
+assertThrowsValue(() => {
+  for (const i of wrapThrow()) {
+    break;
+  }
+}, 42);
+
+if (typeof reportCompare === "function")
+  reportCompare(0, 0);
--- a/js/src/vm/TraceLogging.cpp
+++ b/js/src/vm/TraceLogging.cpp
@@ -56,17 +56,17 @@ rdtsc(void)
             );
     result = upper;
     result = result<<32;
     result = result|lower;
 
     return result;
 
 }
-#elif defined(__arm__)
+#elif defined(__arm__) || defined(__aarch64__)
 
 #include <sys/time.h>
 
 static __inline__ uint64_t
 rdtsc(void)
 {
     struct timeval tv;
     gettimeofday(&tv, NULL);
--- a/js/src/wasm/WasmSignalHandlers.cpp
+++ b/js/src/wasm/WasmSignalHandlers.cpp
@@ -1369,27 +1369,29 @@ static bool
 ProcessHasSignalHandlers()
 {
     // We assume that there are no races creating the first JSRuntime of the process.
     if (sTriedInstallSignalHandlers)
         return sHaveSignalHandlers;
     sTriedInstallSignalHandlers = true;
 
 #if defined(ANDROID)
+# if !defined(__aarch64__)
     // Before Android 4.4 (SDK version 19), there is a bug
     //   https://android-review.googlesource.com/#/c/52333
     // in Bionic's pthread_join which causes pthread_join to return early when
     // pthread_kill is used (on any thread). Nobody expects the pthread_cond_wait
     // EINTRquisition.
     char version_string[PROP_VALUE_MAX];
     PodArrayZero(version_string);
     if (__system_property_get("ro.build.version.sdk", version_string) > 0) {
         if (atol(version_string) < 19)
             return false;
     }
+# endif
 # if defined(MOZ_LINKER)
     // Signal handling is broken on some android systems.
     if (IsSignalHandlingBroken())
         return false;
 # endif
 #endif
 
     // The interrupt handler allows the active thread to be paused from another
--- a/media/omx-plugin/OmxPlugin.cpp
+++ b/media/omx-plugin/OmxPlugin.cpp
@@ -498,17 +498,17 @@ bool OmxDecoder::Init()
     status_t status = videoSource->start();
     if (status != OK) {
       LOG("videoSource->start() failed with status %#x", status);
       return false;
     }
     int64_t durationUs;
     if (videoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
       if (durationUs < 0)
-        LOG("video duration %lld should be nonnegative", durationUs);
+        LOG("video duration %" PRId64 " should be nonnegative", durationUs);
       if (durationUs > totalDurationUs)
         totalDurationUs = durationUs;
     }
   }
 
   sp<MediaSource> audioTrack;
   sp<MediaSource> audioSource;
   if (audioTrackIndex != -1 && (audioTrack = extractor->getTrack(audioTrackIndex)) != nullptr)
@@ -531,17 +531,17 @@ bool OmxDecoder::Init()
     if (status != OK) {
       LOG("audioSource->start() failed with status %#x", status);
       return false;
     }
 
     int64_t durationUs;
     if (audioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
       if (durationUs < 0)
-        LOG("audio duration %lld should be nonnegative", durationUs);
+        LOG("audio duration %" PRId64 " should be nonnegative", durationUs);
       if (durationUs > totalDurationUs)
         totalDurationUs = durationUs;
     }
   }
 
   // set decoder state
   mVideoTrack = videoTrack;
   mVideoSource = videoSource;
@@ -908,17 +908,17 @@ bool OmxDecoder::ReadVideo(VideoFrame *a
     int32_t keyFrame;
 
     if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) {
       LOG("no frame time");
       return false;
     }
 
     if (timeUs < 0) {
-      LOG("frame time %lld must be nonnegative", timeUs);
+      LOG("frame time %" PRId64 " must be nonnegative", timeUs);
       return false;
     }
 
     if (!mVideoBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) {
        keyFrame = 0;
     }
 
     char *data = reinterpret_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
@@ -972,17 +972,17 @@ bool OmxDecoder::ReadAudio(AudioFrame *a
   if (err == OK && mAudioBuffer->range_length() != 0) {
     int64_t timeUs;
     if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
       LOG("no frame time");
       return false;
     }
 
     if (timeUs < 0) {
-      LOG("frame time %lld must be nonnegative", timeUs);
+      LOG("frame time %" PRId64 " must be nonnegative", timeUs);
       return false;
     }
 
     return ToAudioFrame(aFrame, timeUs,
                         mAudioBuffer->data(),
                         mAudioBuffer->range_offset(),
                         mAudioBuffer->range_length(),
                         mAudioChannels, mAudioSampleRate);
--- a/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp
@@ -1150,20 +1150,20 @@ int32_t WebrtcMediaCodecVP8VideoDecoder:
 
 int32_t WebrtcMediaCodecVP8VideoDecoder::Decode(
     const webrtc::EncodedImage& inputImage,
     bool missingFrames,
     const webrtc::RTPFragmentationHeader* fragmentation,
     const webrtc::CodecSpecificInfo* codecSpecificInfo,
     int64_t renderTimeMs) {
 
-  CSFLogDebug(logTag,  "%s, renderTimeMs = %lld ", __FUNCTION__, renderTimeMs);
+  CSFLogDebug(logTag,  "%s, renderTimeMs = %" PRId64, __FUNCTION__, renderTimeMs);
 
   if (inputImage._length== 0 || !inputImage._buffer) {
-    CSFLogDebug(logTag,  "%s, input Image invalid. length = %d", __FUNCTION__, inputImage._length);
+    CSFLogDebug(logTag,  "%s, input Image invalid. length = %" PRIdPTR, __FUNCTION__, inputImage._length);
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   if (inputImage._frameType == webrtc::kVideoFrameKey) {
     CSFLogDebug(logTag,  "%s, inputImage is Golden frame",
                   __FUNCTION__);
     mFrameWidth = inputImage._encodedWidth;
     mFrameHeight = inputImage._encodedHeight;
--- a/mfbt/IntegerPrintfMacros.h
+++ b/mfbt/IntegerPrintfMacros.h
@@ -44,9 +44,41 @@
 #  undef  PRIuPTR      /* uintptr_t */
 #  define PRIuPTR "u"  /* uintptr_t */
 #  undef  PRIxPTR      /* uintptr_t */
 #  define PRIxPTR "x"  /* uintptr_t */
 #  undef  PRIXPTR      /* uintptr_t */
 #  define PRIXPTR "X"  /* uintptr_t */
 #endif
 
+/*
+ * Fix up Android's broken macros for [u]int_fastN_t. On ARM64, Android's
+ * PRI*FAST16/32 macros are defined as "d", but the types themselves are defined
+ * as long and unsigned long.
+ */
+#if defined(ANDROID) && defined(__LP64__)
+#  undef  PRIdFAST16         /* int_fast16_t */
+#  define PRIdFAST16 PRId64  /* int_fast16_t */
+#  undef  PRIiFAST16         /* int_fast16_t */
+#  define PRIiFAST16 PRIi64  /* int_fast16_t */
+#  undef  PRIoFAST16         /* uint_fast16_t */
+#  define PRIoFAST16 PRIo64  /* uint_fast16_t */
+#  undef  PRIuFAST16         /* uint_fast16_t */
+#  define PRIuFAST16 PRIu64  /* uint_fast16_t */
+#  undef  PRIxFAST16         /* uint_fast16_t */
+#  define PRIxFAST16 PRIx64  /* uint_fast16_t */
+#  undef  PRIXFAST16         /* uint_fast16_t */
+#  define PRIXFAST16 PRIX64  /* uint_fast16_t */
+#  undef  PRIdFAST32         /* int_fast32_t */
+#  define PRIdFAST32 PRId64  /* int_fast32_t */
+#  undef  PRIiFAST32         /* int_fast32_t */
+#  define PRIiFAST32 PRIi64  /* int_fast32_t */
+#  undef  PRIoFAST32         /* uint_fast32_t */
+#  define PRIoFAST32 PRIo64  /* uint_fast32_t */
+#  undef  PRIuFAST32         /* uint_fast32_t */
+#  define PRIuFAST32 PRIu64  /* uint_fast32_t */
+#  undef  PRIxFAST32         /* uint_fast32_t */
+#  define PRIxFAST32 PRIx64  /* uint_fast32_t */
+#  undef  PRIXFAST32         /* uint_fast32_t */
+#  define PRIXFAST32 PRIX64  /* uint_fast32_t */
+#endif
+
 #endif  /* mozilla_IntegerPrintfMacros_h_ */
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -916,8 +916,12 @@ pref("dom.audiochannel.mediaControl", tr
 
 // Space separated list of URLS that are allowed to send objects (instead of
 // only strings) through webchannels. This list is duplicated in browser/app/profile/firefox.js
 pref("webchannel.allowObject.urlWhitelist", "https://accounts.firefox.com https://content.cdn.mozilla.net https://input.mozilla.org https://support.mozilla.org https://install.mozilla.org");
 
 pref("media.openUnsupportedTypeWithExternalApp", true);
 
 pref("dom.keyboardevent.dispatch_during_composition", true);
+
+#if CPU_ARCH == aarch64
+pref("javascript.options.native_regexp", false);
+#endif
--- a/mobile/android/app/moz.build
+++ b/mobile/android/app/moz.build
@@ -29,17 +29,17 @@ with Files('src/androidTest/**'):
     BUG_COMPONENT = ('Firefox for Android', 'Testing')
 
 with Files('src/test/**'):
     BUG_COMPONENT = ('Firefox for Android', 'Build Config & IDE Support')
 
 for var in ('APP_NAME', 'APP_VERSION'):
     DEFINES[var] = CONFIG['MOZ_%s' % var]
 
-for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME', 'ANDROID_PACKAGE_NAME'):
+for var in ('MOZ_UPDATER', 'MOZ_APP_UA_NAME', 'ANDROID_PACKAGE_NAME', 'CPU_ARCH'):
     DEFINES[var] = CONFIG[var]
 
 for var in ('MOZ_ANDROID_GCM', ):
     if CONFIG[var]:
         DEFINES[var] = 1
 
 for var in ('MOZ_ANDROID_GCM_SENDERID', ):
     if CONFIG[var]:
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1246,16 +1246,20 @@ pref("dom.forms.select.customstyling", f
 #else
 pref("dom.forms.select.customstyling", true);
 #endif
 pref("dom.select_popup_in_parent.enabled", false);
 
 // Enable Directory API. By default, disabled.
 pref("dom.input.dirpicker", false);
 
+// Enable not moving the cursor to end when a text input or textarea has .value
+// set to the value it already has.  By default, enabled.
+pref("dom.input.skip_cursor_move_for_same_value_set", false);
+
 // Enables system messages and activities
 pref("dom.sysmsg.enabled", false);
 
 // Enable pre-installed applications.
 pref("dom.webapps.useCurrentProfile", false);
 
 pref("dom.cycle_collector.incremental", true);
 
--- a/mozglue/misc/StackWalk.cpp
+++ b/mozglue/misc/StackWalk.cpp
@@ -243,16 +243,27 @@ PrintError(const char* aPrefix)
     nullptr
   );
   fprintf(stderr, "### ERROR: %s: %s",
           aPrefix, lpMsgBuf ? lpMsgBuf : "(null)\n");
   fflush(stderr);
   LocalFree(lpMsgBuf);
 }
 
+static void
+InitializeDbgHelpCriticalSection()
+{
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  ::InitializeCriticalSection(&gDbgHelpCS);
+  initialized = true;
+}
+
 static unsigned int WINAPI WalkStackThread(void* aData);
 
 static bool
 EnsureWalkThreadReady()
 {
   static bool walkThreadReady = false;
   static HANDLE stackWalkThread = nullptr;
   static HANDLE readyEvent = nullptr;
@@ -295,18 +306,17 @@ EnsureWalkThreadReady()
     // have signalled the event. If that is the case, give up for now and
     // try again next time we're called.
     return false;
   }
   ::CloseHandle(readyEvent);
   stackWalkThread = nullptr;
   readyEvent = nullptr;
 
-
-  ::InitializeCriticalSection(&gDbgHelpCS);
+  InitializeDbgHelpCriticalSection();
 
   return walkThreadReady = true;
 }
 
 static void
 WalkStackMain64(struct WalkStackData* aData)
 {
   // Get a context for the specified thread.
@@ -846,19 +856,17 @@ EnsureSymInitialized()
 {
   static bool gInitialized = false;
   bool retStat;
 
   if (gInitialized) {
     return gInitialized;
   }
 
-  if (!EnsureWalkThreadReady()) {
-    return false;
-  }
+  InitializeDbgHelpCriticalSection();
 
   SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
   retStat = SymInitialize(GetCurrentProcess(), nullptr, TRUE);
   if (!retStat) {
     PrintError("SymInitialize");
   }
 
   gInitialized = retStat;
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -457,17 +457,17 @@ FTPChannelParent::OnStartRequest(nsIRequ
   nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest);
   MOZ_ASSERT(chan);
   NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
 
   // Send down any permissions which are relevant to this URL if we are
   // performing a document load.
   PContentParent* pcp = Manager()->Manager();
   DebugOnly<nsresult> rv =
-    static_cast<ContentParent*>(pcp)->AboutToLoadDocumentForChild(chan);
+    static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   int64_t contentLength;
   chan->GetContentLength(&contentLength);
   nsCString contentType;
   chan->GetContentType(contentType);
 
   nsCString entityID;
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -1143,17 +1143,17 @@ HttpChannelParent::OnStartRequest(nsIReq
              "HttpChannelParent getting OnStartRequest from a different nsHttpChannel instance");
 
   // Send down any permissions which are relevant to this URL if we are
   // performing a document load. We can't do that is mIPCClosed is set.
   if (!mIPCClosed) {
     PContentParent* pcp = Manager()->Manager();
     MOZ_ASSERT(pcp, "We should have a manager if our IPC isn't closed");
     DebugOnly<nsresult> rv =
-      static_cast<ContentParent*>(pcp)->AboutToLoadDocumentForChild(chan);
+      static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   nsHttpResponseHead *responseHead = chan->GetResponseHead();
   nsHttpRequestHead  *requestHead = chan->GetRequestHead();
   bool isFromCache = false;
   chan->IsFromCache(&isFromCache);
   uint32_t expirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -321,17 +321,17 @@ WyciwygChannelParent::OnStartRequest(nsI
   nsresult rv;
 
   nsCOMPtr<nsIWyciwygChannel> chan = do_QueryInterface(aRequest, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Send down any permissions which are relevant to this URL if we are
   // performing a document load.
   PContentParent* pcp = Manager()->Manager();
-  rv = static_cast<ContentParent*>(pcp)->AboutToLoadDocumentForChild(chan);
+  rv = static_cast<ContentParent*>(pcp)->AboutToLoadHttpFtpWyciwygDocumentForChild(chan);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   nsresult status;
   chan->GetStatus(&status);
 
   int64_t contentLength = -1;
   chan->GetContentLength(&contentLength);
 
--- a/taskcluster/ci/build/linux.yml
+++ b/taskcluster/ci/build/linux.yml
@@ -72,17 +72,17 @@ linux64/debug:
 
 linux64-devedition/opt:
     description: "Linux64 devedition Opt"
     index:
         product: devedition
         job-name: linux64-opt
     treeherder:
         platform: linux64-devedition/opt
-        symbol: tc(DE)
+        symbol: tc(B)
     worker-type: aws-provisioner-v1/gecko-{level}-b-linux
     worker:
         implementation: docker-worker
         max-run-time: 36000
     run:
         using: mozharness
         actions: [get-secrets build check-test generate-build-stats update]
         config:
@@ -171,17 +171,17 @@ linux/pgo:
 
 linux-devedition/opt:
     description: "Linux32 devedition Opt"
     index:
         product: devedition
         job-name: linux-opt
     treeherder:
         platform: linux32-devedition/opt
-        symbol: tc(DE)
+        symbol: tc(B)
     worker-type: aws-provisioner-v1/gecko-{level}-b-linux
     worker:
         implementation: docker-worker
         max-run-time: 36000
     run:
         using: mozharness
         actions: [get-secrets build check-test generate-build-stats update]
         config:
--- a/taskcluster/ci/build/macosx.yml
+++ b/taskcluster/ci/build/macosx.yml
@@ -1,17 +1,17 @@
 macosx64/debug:
     description: "MacOS X x64 Cross-compile"
     index:
         product: firefox
         job-name: macosx64-debug
     treeherder:
         platform: osx-10-7/debug
         symbol: tc(B)
-        tier: 2
+        tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-macosx64
     worker:
         implementation: docker-worker
         max-run-time: 36000
     run:
         using: mozharness
         actions: [get-secrets build generate-build-stats update]
         config:
--- a/taskcluster/taskgraph/target_tasks.py
+++ b/taskcluster/taskgraph/target_tasks.py
@@ -233,19 +233,19 @@ def target_tasks_mozilla_beta(full_task_
     of builds and signing, but does not include beetmover or balrog jobs."""
 
     def filter(task):
         if not standard_filter(task, parameters):
             return False
         platform = task.attributes.get('build_platform')
         if platform in ('linux64-pgo', 'linux-pgo', 'win32-pgo', 'win64-pgo',
                         'android-api-15-nightly', 'android-x86-nightly',
-                        'win32', 'win64', 'macosx64'):
+                        'win32', 'win64'):
             return False
-        if platform in ('linux64', 'linux'):
+        if platform in ('linux64', 'linux', 'macosx64'):
             if task.attributes['build_type'] == 'opt':
                 return False
         # skip l10n, beetmover, balrog
         if task.kind in [
             'balrog', 'beetmover', 'beetmover-checksums', 'beetmover-l10n',
             'checksums-signing', 'nightly-l10n', 'nightly-l10n-signing',
             'push-apk', 'push-apk-breakpoint',
         ]:
--- a/testing/mozharness/configs/builds/releng_sub_mac_configs/64_devedition.py
+++ b/testing/mozharness/configs/builds/releng_sub_mac_configs/64_devedition.py
@@ -1,4 +1,6 @@
 config = {
+    'src_mozconfig': 'browser/config/mozconfigs/macosx64/devedition',
     'force_clobber': True,
     'stage_platform': 'macosx64-devedition',
+    'stage_product': 'devedition',
 }
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/32_devedition.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/32_devedition.py
@@ -1,4 +1,6 @@
 config = {
+    'src_mozconfig': 'browser/config/mozconfigs/win32/devedition',
     'force_clobber': True,
     'stage_platform': 'win32-devedition',
+    'stage_product': 'devedition',
 }
--- a/testing/mozharness/configs/builds/releng_sub_windows_configs/64_devedition.py
+++ b/testing/mozharness/configs/builds/releng_sub_windows_configs/64_devedition.py
@@ -1,4 +1,6 @@
 config = {
+    'src_mozconfig': 'browser/config/mozconfigs/win64/devedition',
     'force_clobber': True,
     'stage_platform': 'win64-devedition',
+    'stage_product': 'devedition',
 }
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -2039,19 +2039,18 @@ CreateJSHangHistogram(JSContext* cx, con
       !JS_DefineProperty(cx, ret, "stack", stack, JSPROP_ENUMERATE) ||
       !JS_DefineProperty(cx, ret, "histogram", time, JSPROP_ENUMERATE) ||
       (!hangAnnotations.empty() && // <-- Only define annotations when nonempty
         !JS_DefineProperty(cx, ret, "annotations", annotations, JSPROP_ENUMERATE))) {
     return nullptr;
   }
 
   if (!hang.GetNativeStack().empty()) {
-    const Telemetry::HangStack& stack = hang.GetNativeStack();
-    const std::vector<uintptr_t>& frames = stack.GetNativeFrames();
-    Telemetry::ProcessedStack processed = Telemetry::GetStackAndModules(frames);
+    const Telemetry::NativeHangStack& stack = hang.GetNativeStack();
+    Telemetry::ProcessedStack processed = Telemetry::GetStackAndModules(stack);
 
     CombinedStacks singleStack;
     singleStack.AddStack(processed);
     JS::RootedObject fullReportObj(cx, CreateJSStackObject(cx, singleStack));
     if (!fullReportObj) {
       return nullptr;
     }
 
--- a/toolkit/components/telemetry/ThreadHangStats.h
+++ b/toolkit/components/telemetry/ThreadHangStats.h
@@ -40,47 +40,54 @@ public:
   // Get maximum (inclusive) range of bucket in milliseconds
   uint32_t GetBucketMax(size_t aBucket) const {
     MOZ_ASSERT(aBucket < ArrayLength(*this));
     return (1u << (aBucket + 1u)) - 1u;
   }
   void Add(PRIntervalTime aTime);
 };
 
+/* A native stack is a simple list of pointers, so rather than building a
+   wrapper type, we typdef the type here. */
+typedef std::vector<uintptr_t> NativeHangStack;
+
 /* HangStack stores an array of const char pointers,
    with optional internal storage for strings. */
 class HangStack
 {
 public:
   static const size_t sMaxInlineStorage = 8;
+
   // The maximum depth for the native stack frames that we might collect.
+  // XXX: Consider moving this to a different object?
   static const size_t sMaxNativeFrames = 25;
 
 private:
   typedef mozilla::Vector<const char*, sMaxInlineStorage> Impl;
   Impl mImpl;
 
   // Stack entries can either be a static const char*
   // or a pointer to within this buffer.
   mozilla::Vector<char, 0> mBuffer;
-  // When a native stack is gathered, this vector holds the raw program counter
-  // values that MozStackWalk will return to us after it walks the stack.
-  // When gathering the Telemetry payload, Telemetry will take care of mapping
-  // these program counters to proper addresses within modules.
-  std::vector<uintptr_t> mNativeFrames;
 
 public:
   HangStack() {}
 
   HangStack(HangStack&& aOther)
     : mImpl(mozilla::Move(aOther.mImpl))
     , mBuffer(mozilla::Move(aOther.mBuffer))
   {
   }
 
+  HangStack& operator=(HangStack&& aOther) {
+    mImpl = mozilla::Move(aOther.mImpl);
+    mBuffer = mozilla::Move(aOther.mBuffer);
+    return *this;
+  }
+
   bool operator==(const HangStack& aOther) const {
     for (size_t i = 0; i < length(); i++) {
       if (!IsSameAsEntry(operator[](i), aOther[i])) {
         return false;
       }
     }
     return true;
   }
@@ -113,17 +120,16 @@ public:
   void erase(const char** aEntry) { mImpl.erase(aEntry); }
   void erase(const char** aBegin, const char** aEnd) {
     mImpl.erase(aBegin, aEnd);
   }
 
   void clear() {
     mImpl.clear();
     mBuffer.clear();
-    mNativeFrames.clear();
   }
 
   bool IsInBuffer(const char* aEntry) const {
     return aEntry >= mBuffer.begin() && aEntry < mBuffer.end();
   }
 
   bool IsSameAsEntry(const char* aEntry, const char* aOther) const {
     // If the entry came from the buffer, we need to compare its content;
@@ -139,74 +145,68 @@ public:
     // aCapacity is the minimal capacity and Vector may make the actual
     // capacity larger, in which case we want to use up all the space.
     return mBuffer.reserve(aCapacity) &&
            mBuffer.reserve(mBuffer.capacity());
   }
 
   const char* InfallibleAppendViaBuffer(const char* aText, size_t aLength);
   const char* AppendViaBuffer(const char* aText, size_t aLength);
-
-  void EnsureNativeFrameCapacity(size_t aCapacity) {
-    mNativeFrames.reserve(aCapacity);
-  }
-
-  void AppendNativeFrame(uintptr_t aPc) {
-    MOZ_ASSERT(mNativeFrames.size() <= sMaxNativeFrames);
-    if (mNativeFrames.size() < sMaxNativeFrames) {
-      mNativeFrames.push_back(aPc);
-    }
-  }
-
-  const std::vector<uintptr_t>& GetNativeFrames() const {
-    return mNativeFrames;
-  }
 };
 
 /* A hang histogram consists of a stack associated with the
    hang, along with a time histogram of the hang times. */
 class HangHistogram : public TimeHistogram
 {
 private:
   static uint32_t GetHash(const HangStack& aStack);
 
   HangStack mStack;
   // Native stack that corresponds to the pseudostack in mStack
-  HangStack mNativeStack;
+  NativeHangStack mNativeStack;
   // Use a hash to speed comparisons
   const uint32_t mHash;
   // Annotations attributed to this stack
   HangMonitor::HangAnnotationsVector mAnnotations;
 
 public:
   explicit HangHistogram(HangStack&& aStack)
     : mStack(mozilla::Move(aStack))
     , mHash(GetHash(mStack))
   {
   }
+
+  explicit HangHistogram(HangStack&& aStack,
+                         NativeHangStack&& aNativeStack)
+    : mStack(mozilla::Move(aStack))
+    , mNativeStack(mozilla::Move(aNativeStack))
+    , mHash(GetHash(mStack))
+  {
+  }
+
   HangHistogram(HangHistogram&& aOther)
     : TimeHistogram(mozilla::Move(aOther))
     , mStack(mozilla::Move(aOther.mStack))
     , mNativeStack(mozilla::Move(aOther.mNativeStack))
     , mHash(mozilla::Move(aOther.mHash))
     , mAnnotations(mozilla::Move(aOther.mAnnotations))
   {
   }
   bool operator==(const HangHistogram& aOther) const;
   bool operator!=(const HangHistogram& aOther) const
   {
     return !operator==(aOther);
   }
   const HangStack& GetStack() const {
     return mStack;
   }
-  HangStack& GetNativeStack() {
+  NativeHangStack& GetNativeStack() {
     return mNativeStack;
   }
-  const HangStack& GetNativeStack() const {
+  const NativeHangStack& GetNativeStack() const {
     return mNativeStack;
   }
   const HangMonitor::HangAnnotationsVector& GetAnnotations() const {
     return mAnnotations;
   }
   void Add(PRIntervalTime aTime, HangMonitor::HangAnnotationsPtr aAnnotations) {
     TimeHistogram::Add(aTime);
     if (aAnnotations) {
@@ -226,26 +226,30 @@ public:
 class ThreadHangStats
 {
 private:
   nsCString mName;
 
 public:
   TimeHistogram mActivity;
   mozilla::Vector<HangHistogram, 4> mHangs;
+  uint32_t mNativeStackCnt;
 
   explicit ThreadHangStats(const char* aName)
     : mName(aName)
+    , mNativeStackCnt(0)
   {
   }
   ThreadHangStats(ThreadHangStats&& aOther)
     : mName(mozilla::Move(aOther.mName))
     , mActivity(mozilla::Move(aOther.mActivity))
     , mHangs(mozilla::Move(aOther.mHangs))
+    , mNativeStackCnt(aOther.mNativeStackCnt)
   {
+    aOther.mNativeStackCnt = 0;
   }
   const char* GetName() const {
     return mName.get();
   }
 };
 
 } // namespace Telemetry
 } // namespace mozilla
--- a/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js
+++ b/toolkit/components/telemetry/tests/unit/test_ThreadHangStats.js
@@ -79,18 +79,18 @@ function run_test() {
 
       ok(Array.isArray(endHangs.hangs));
       notEqual(endHangs.hangs.length, 0);
 
       ok(Array.isArray(endHangs.hangs[0].stack));
       notEqual(endHangs.hangs[0].stack.length, 0);
       equal(typeof endHangs.hangs[0].stack[0], "string");
 
-      // Native stack gathering is only enabled on Windows.
-      if (mozinfo.os == "win") {
+      // Native stack gathering is only enabled on Windows x86.
+      if (mozinfo.os == "win" && mozinfo.bits == 32) {
         // Make sure one of the hangs is a permanent
         // hang containing a native stack.
         ok(endHangs.hangs.some((hang) => (
           hang.nativeStack &&
           Array.isArray(hang.nativeStack.memoryMap) &&
           Array.isArray(hang.nativeStack.stacks)
         )));
       }
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -696,26 +696,37 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
   } else {
     // Launch the updater to either stage or apply an update.
     if (!WinLaunchChild(updaterPathW.get(), argc, argv, nullptr, outpid)) {
       return;
     }
   }
 #elif defined(XP_MACOSX)
   UpdateDriverSetupMacCommandLine(argc, argv, restart);
-  // LaunchChildMac uses posix_spawnp and prefers the current
-  // architecture when launching. It doesn't require a
-  // null-terminated string but it doesn't matter if we pass one.
+  // We need to detect whether elevation is required for this update. This can
+  // occur when an admin user installs the application, but another admin
+  // user attempts to update (see bug 394984).
+  if (restart && !IsRecursivelyWritable(installDirPath.get())) {
+    if (!LaunchElevatedUpdate(argc, argv, outpid)) {
+      LOG(("Failed to launch elevated update!"));
+      exit(1);
+    }
+    exit(0);
+  }
+
   if (isStaged) {
     // Launch the updater to replace the installation with the staged updated.
     LaunchChildMac(argc, argv);
   } else {
     // Launch the updater to either stage or apply an update.
     LaunchChildMac(argc, argv, outpid);
   }
+  if (restart) {
+    exit(0);
+  }
 #else
   if (isStaged) {
     // Launch the updater to replace the installation with the staged updated.
     PR_CreateProcessDetached(updaterPath.get(), argv, nullptr, nullptr);
   } else {
     // Launch the updater to either stage or apply an update.
     *outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr);
   }
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -17,17 +17,16 @@
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Vector.h"
 #include "GeckoProfiler.h"
 #include "ProfilerIOInterposeObserver.h"
 #include "mozilla/StackWalk.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/TimeStamp.h"
-#include "mozilla/Sprintf.h"
 #include "mozilla/StaticPtr.h"
 #include "PseudoStack.h"
 #include "ThreadInfo.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsIObserverService.h"
 #include "nsIXULAppInfo.h"
 #include "nsIXULRuntime.h"
 #include "nsDirectoryServiceUtils.h"
@@ -670,17 +669,17 @@ AddDynamicCodeLocationTag(ProfileBuffer*
     memcpy(text, &aStr[j], len);
     j += sizeof(void*) / sizeof(char);
 
     // Cast to *((void**) to pass the text data to a void*.
     aBuffer->addTag(ProfileBufferEntry::EmbeddedString(*((void**)(&text[0]))));
   }
 }
 
-static const int SAMPLER_MAX_STRING_LENGTH = 128;
+static const int SAMPLER_MAX_STRING_LENGTH = 512;
 
 static void
 AddPseudoEntry(PSLockRef aLock, ProfileBuffer* aBuffer,
                volatile js::ProfileEntry& entry,
                NotNull<RacyThreadInfo*> aRacyInfo)
 {
   // Pseudo-frames with the BEGIN_PSEUDO_JS flag are just annotations and
   // should not be recorded in the profile.
@@ -695,19 +694,27 @@ AddPseudoEntry(PSLockRef aLock, ProfileB
   const char* sampleLabel = entry.label();
   bool includeDynamicString = !ActivePS::FeaturePrivacy(aLock);
   const char* dynamicString =
     includeDynamicString ? entry.getDynamicString() : nullptr;
   char combinedStringBuffer[SAMPLER_MAX_STRING_LENGTH];
 
   if (entry.isCopyLabel() || dynamicString) {
     if (dynamicString) {
-      int bytesWritten =
-        SprintfLiteral(combinedStringBuffer, "%s %s", sampleLabel, dynamicString);
-      if (bytesWritten > 0) {
+      // Create a string that is sampleLabel + ' ' + annotationString.
+      // Avoid sprintf because it can take a lock on Windows, and this
+      // code runs during the profiler's "critical section" as defined
+      // in SamplerThread::SuspendAndSampleAndResumeThread.
+      size_t labelLength = strlen(sampleLabel);
+      size_t dynamicLength = strlen(dynamicString);
+      if (labelLength + 1 + dynamicLength < ArrayLength(combinedStringBuffer)) {
+        PodCopy(combinedStringBuffer, sampleLabel, labelLength);
+        combinedStringBuffer[labelLength] = ' ';
+        PodCopy(&combinedStringBuffer[labelLength + 1], dynamicString, dynamicLength);
+        combinedStringBuffer[labelLength + 1 + dynamicLength] = '\0';
         sampleLabel = combinedStringBuffer;
       }
     }
     // Store the string using 1 or more EmbeddedString tags.
     // That will happen to the preceding tag.
     AddDynamicCodeLocationTag(aBuffer, sampleLabel);
     if (entry.isJs()) {
       JSScript* script = entry.script();
@@ -3064,10 +3071,21 @@ profiler_call_exit(void* aHandle)
   if (!aHandle) {
     return;
   }
 
   PseudoStack* pseudoStack = static_cast<PseudoStack*>(aHandle);
   pseudoStack->pop();
 }
 
+void*
+profiler_get_stack_top()
+{
+  PSAutoLock lock(gPSMutex);
+  ThreadInfo* threadInfo = FindLiveThreadInfo(lock);
+  if (threadInfo) {
+    return threadInfo->StackTop();
+  }
+  return nullptr;
+}
+
 // END externally visible functions
 ////////////////////////////////////////////////////////////////////////
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -310,16 +310,22 @@ PROFILER_FUNC(bool profiler_thread_is_sl
 PROFILER_FUNC_VOID(profiler_js_interrupt_callback())
 
 // The number of milliseconds since the process started. Operates the same
 // whether the profiler is active or inactive.
 PROFILER_FUNC(double profiler_time(), 0)
 
 PROFILER_FUNC_VOID(profiler_log(const char *str))
 
+// Gets the stack top of the current thread.
+//
+// The thread must have been previously registered with the profiler, otherwise
+// this method will return nullptr.
+PROFILER_FUNC(void* profiler_get_stack_top(), nullptr)
+
 // End of the functions defined whether the profiler is enabled or not.
 
 #if defined(MOZ_GECKO_PROFILER)
 
 #include <stdlib.h>
 #include <signal.h>
 #include "js/ProfilingStack.h"
 #include "mozilla/Sprintf.h"
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -3413,17 +3413,17 @@ static const NSString* kStateCollectionB
 
 - (void)setTemporaryBackgroundColor
 {
   [super setBackgroundColor:[NSColor whiteColor]];
 }
 
 - (void)restoreBackgroundColor
 {
-  [super setBackgroundColor:mColor];
+  [super setBackgroundColor:mBackgroundColor];
 }
 
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect
 {
   [self setTitlebarNeedsDisplayInRect:aRect sync:NO];
 }
 
 - (void)setTitlebarNeedsDisplayInRect:(NSRect)aRect sync:(BOOL)aSync
--- a/xpcom/threads/BackgroundHangMonitor.cpp
+++ b/xpcom/threads/BackgroundHangMonitor.cpp
@@ -27,16 +27,26 @@
 
 #include <algorithm>
 
 // Activate BHR only for one every BHR_BETA_MOD users.
 // This is now 100% of Beta population for the Beta 45/46 e10s A/B trials
 // It can be scaled back again in the future
 #define BHR_BETA_MOD 1;
 
+// This variable controls the maximum number of native hang stacks which may be
+// attached to a ping. This is due to how large native stacks can be. We want to
+// reduce the chance of a ping being discarded due to it exceeding the maximum
+// ping size.
+//
+// NOTE: 300 native hang stacks would, by a rough estimation based on stacks
+// collected from nightly on March 21, 2017, take up approximately 168kb of
+// space.
+static const uint32_t kMaximumNativeHangStacks = 300;
+
 // Maximum depth of the call stack in the reported thread hangs. This value represents
 // the 99.9th percentile of the thread hangs stack depths reported by Telemetry.
 static const size_t kMaxThreadHangStackDepth = 30;
 
 // An utility comparator function used by std::unique to collapse "(* script)" entries in
 // a vector representing a call stack.
 bool StackScriptEntriesCollapser(const char* aStackEntry, const char *aAnotherStackEntry)
 {
@@ -175,16 +185,18 @@ public:
   // Is the thread in a waiting state
   bool mWaiting;
   // Is the thread dedicated to a single BackgroundHangMonitor
   BackgroundHangMonitor::ThreadType mThreadType;
   // Platform-specific helper to get hang stacks
   ThreadStackHelper mStackHelper;
   // Stack of current hang
   Telemetry::HangStack mHangStack;
+  // Native stack of current hang
+  Telemetry::NativeHangStack mNativeHangStack;
   // Statistics for telemetry
   Telemetry::ThreadHangStats mStats;
   // Annotations for the current hang
   UniquePtr<HangMonitor::HangAnnotations> mAnnotations;
   // Annotators registered for this thread
   HangMonitor::Observer::Annotators mAnnotators;
 
   BackgroundHangThread(const char* aName,
@@ -327,17 +339,29 @@ BackgroundHangManager::RunMonitorThread(
         currentThread->mHanging = false;
         currentThread->ReportPermaHang();
         continue;
       }
 
       if (MOZ_LIKELY(!currentThread->mHanging)) {
         if (MOZ_UNLIKELY(hangTime >= currentThread->mTimeout)) {
           // A hang started
-          currentThread->mStackHelper.GetStack(currentThread->mHangStack);
+#ifdef NIGHTLY_BUILD
+          if (currentThread->mStats.mNativeStackCnt < kMaximumNativeHangStacks) {
+            // NOTE: In nightly builds of firefox we want to collect native stacks
+            // for all hangs, not just permahangs.
+            currentThread->mStats.mNativeStackCnt += 1;
+            currentThread->mStackHelper.GetPseudoAndNativeStack(
+              currentThread->mHangStack, currentThread->mNativeHangStack);
+          } else {
+            currentThread->mStackHelper.GetPseudoStack(currentThread->mHangStack);
+          }
+#else
+          currentThread->mStackHelper.GetPseudoStack(currentThread->mHangStack);
+#endif
           currentThread->mHangStart = interval;
           currentThread->mHanging = true;
           currentThread->mAnnotations =
             currentThread->mAnnotators.GatherAnnotations();
         }
       } else {
         if (MOZ_LIKELY(interval != currentThread->mHangStart)) {
           // A hang ended
@@ -446,17 +470,17 @@ BackgroundHangThread::ReportHang(PRInter
   if (mHangStack.length() > kMaxThreadHangStackDepth) {
     const int elementsToRemove = mHangStack.length() - kMaxThreadHangStackDepth;
     // Replace the oldest frame with a known label so that we can tell this stack
     // was limited.
     mHangStack[0] = "(reduced stack)";
     mHangStack.erase(mHangStack.begin() + 1, mHangStack.begin() + elementsToRemove);
   }
 
-  Telemetry::HangHistogram newHistogram(Move(mHangStack));
+  Telemetry::HangHistogram newHistogram(Move(mHangStack), Move(mNativeHangStack));
   for (Telemetry::HangHistogram* oldHistogram = mStats.mHangs.begin();
        oldHistogram != mStats.mHangs.end(); oldHistogram++) {
     if (newHistogram == *oldHistogram) {
       // New histogram matches old one
       oldHistogram->Add(aHangTime, Move(mAnnotations));
       return *oldHistogram;
     }
   }
@@ -470,19 +494,22 @@ BackgroundHangThread::ReportHang(PRInter
 
 void
 BackgroundHangThread::ReportPermaHang()
 {
   // Permanently hanged; called on the monitor thread
   // mManager->mLock IS locked
 
   Telemetry::HangHistogram& hang = ReportHang(mMaxTimeout);
-  Telemetry::HangStack& stack = hang.GetNativeStack();
+  Telemetry::NativeHangStack& stack = hang.GetNativeStack();
   if (stack.empty()) {
-    mStackHelper.GetNativeStack(stack);
+    mStats.mNativeStackCnt += 1;
+    if (mStats.mNativeStackCnt <= kMaximumNativeHangStacks) {
+      mStackHelper.GetNativeStack(stack);
+    }
   }
 }
 
 MOZ_ALWAYS_INLINE void
 BackgroundHangThread::Update()
 {
   PRIntervalTime intervalNow = mManager->mIntervalNow;
   if (mWaiting) {
--- a/xpcom/threads/ThreadStackHelper.cpp
+++ b/xpcom/threads/ThreadStackHelper.cpp
@@ -129,16 +129,17 @@ ThreadStackHelper::ThreadStackHelper()
   mInitialized = !!::DuplicateHandle(
     ::GetCurrentProcess(), ::GetCurrentThread(),
     ::GetCurrentProcess(), &mThreadID,
     THREAD_SUSPEND_RESUME
 #ifdef MOZ_THREADSTACKHELPER_NATIVE
     | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION
 #endif
     , FALSE, 0);
+  mStackTop = profiler_get_stack_top();
   MOZ_ASSERT(mInitialized);
 #elif defined(XP_MACOSX)
   mThreadID = mach_thread_self();
 #endif
 }
 
 ThreadStackHelper::~ThreadStackHelper()
 {
@@ -159,118 +160,161 @@ private:
   T*& mPtr;
 public:
   ScopedSetPtr(T*& p, T* val) : mPtr(p) { mPtr = val; }
   ~ScopedSetPtr() { mPtr = nullptr; }
 };
 } // namespace
 
 void
-ThreadStackHelper::GetStack(Stack& aStack)
+ThreadStackHelper::GetPseudoStack(Stack& aStack)
 {
-  GetStackInternal(aStack, /* aAppendNativeStack */ false);
+  GetStacksInternal(&aStack, nullptr);
 }
 
 void
-ThreadStackHelper::GetStackInternal(Stack& aStack, bool aAppendNativeStack)
+ThreadStackHelper::GetStacksInternal(Stack* aStack, NativeStack* aNativeStack)
 {
   // Always run PrepareStackBuffer first to clear aStack
-  if (!PrepareStackBuffer(aStack)) {
+  if (aStack && !PrepareStackBuffer(*aStack)) {
     // Skip and return empty aStack
     return;
   }
 
-  ScopedSetPtr<Stack> stackPtr(mStackToFill, &aStack);
+  ScopedSetPtr<Stack> stackPtr(mStackToFill, aStack);
 
 #if defined(XP_LINUX)
   if (!sInitialized) {
     MOZ_ASSERT(false);
     return;
   }
-  siginfo_t uinfo = {};
-  uinfo.si_signo = sFillStackSignum;
-  uinfo.si_code = SI_QUEUE;
-  uinfo.si_pid = getpid();
-  uinfo.si_uid = getuid();
-  uinfo.si_value.sival_ptr = this;
-  if (::syscall(SYS_rt_tgsigqueueinfo, uinfo.si_pid,
-                mThreadID, sFillStackSignum, &uinfo)) {
-    // rt_tgsigqueueinfo was added in Linux 2.6.31.
-    // Could have failed because the syscall did not exist.
-    return;
+  if (aStack) {
+    siginfo_t uinfo = {};
+    uinfo.si_signo = sFillStackSignum;
+    uinfo.si_code = SI_QUEUE;
+    uinfo.si_pid = getpid();
+    uinfo.si_uid = getuid();
+    uinfo.si_value.sival_ptr = this;
+    if (::syscall(SYS_rt_tgsigqueueinfo, uinfo.si_pid,
+                  mThreadID, sFillStackSignum, &uinfo)) {
+      // rt_tgsigqueueinfo was added in Linux 2.6.31.
+      // Could have failed because the syscall did not exist.
+      return;
+    }
+    MOZ_ALWAYS_TRUE(!::sem_wait(&mSem));
   }
-  MOZ_ALWAYS_TRUE(!::sem_wait(&mSem));
 
 #elif defined(XP_WIN)
   if (!mInitialized) {
     MOZ_ASSERT(false);
     return;
   }
 
-  if (aAppendNativeStack) {
-    aStack.EnsureNativeFrameCapacity(Telemetry::HangStack::sMaxNativeFrames);
+  // NOTE: We can only perform frame pointer stack walking on non win64
+  // platforms, because Win64 always omits frame pointers. We don't want to use
+  // MozStackWalk here, so we just skip collecting stacks entirely.
+#ifndef MOZ_THREADSTACKHELPER_X64
+  if (aNativeStack) {
+    aNativeStack->reserve(Telemetry::HangStack::sMaxNativeFrames);
   }
+#endif
 
   if (::SuspendThread(mThreadID) == DWORD(-1)) {
     MOZ_ASSERT(false);
     return;
   }
 
   // SuspendThread is asynchronous, so the thread may still be running. Use
   // GetThreadContext to ensure it's really suspended.
   // See https://blogs.msdn.microsoft.com/oldnewthing/20150205-00/?p=44743.
   CONTEXT context;
+  memset(&context, 0, sizeof(context));
   context.ContextFlags = CONTEXT_CONTROL;
   if (::GetThreadContext(mThreadID, &context)) {
-    FillStackBuffer();
-  }
+    if (aStack) {
+      FillStackBuffer();
+    }
+
+#ifndef MOZ_THREADSTACKHELPER_X64
+    if (aNativeStack) {
+      auto callback = [](uint32_t, void* aPC, void*, void* aClosure) {
+        NativeStack* stack = static_cast<NativeStack*>(aClosure);
+        stack->push_back(reinterpret_cast<uintptr_t>(aPC));
+      };
+
+      // Now we need to get our frame pointer, our stack pointer, and our stack
+      // top. Rather than registering and storing the stack tops ourselves, we use
+      // the gecko profiler to look it up.
+      void** framePointer = reinterpret_cast<void**>(context.Ebp);
+      void** stackPointer = reinterpret_cast<void**>(context.Esp);
+
+      MOZ_ASSERT(mStackTop, "The thread should be registered by the profiler");
 
-  if (aAppendNativeStack) {
-    auto callback = [](uint32_t, void* aPC, void*, void* aClosure) {
-      Stack* stack = static_cast<Stack*>(aClosure);
-      stack->AppendNativeFrame(reinterpret_cast<uintptr_t>(aPC));
-    };
-
-    MozStackWalk(callback, /* skipFrames */ 0,
-                 /* maxFrames */ Telemetry::HangStack::sMaxNativeFrames,
-                 reinterpret_cast<void*>(&aStack),
-                 reinterpret_cast<uintptr_t>(mThreadID), nullptr);
+      // Double check that the values we pulled for the thread make sense before
+      // walking the stack.
+      if (mStackTop && framePointer >= stackPointer && framePointer < mStackTop) {
+        // NOTE: In bug 1346415 this was changed to use FramePointerStackWalk.
+        // This was done because lowering the background hang timer threshold
+        // would cause it to fire on infra early during the boot process, causing
+        // a deadlock in MozStackWalk when the target thread was holding the
+        // windows-internal lock on the function table, as it would be suspended
+        // before we tried to grab the lock to walk its stack.
+        //
+        // FramePointerStackWalk is implemented entirely in userspace and thus
+        // doesn't have the same issues with deadlocking. Unfortunately as 64-bit
+        // windows is not guaranteed to have frame pointers, the stack walking
+        // code is only enabled on 32-bit windows builds (bug 1357829).
+        FramePointerStackWalk(callback, /* skipFrames */ 0,
+                              /* maxFrames */ Telemetry::HangStack::sMaxNativeFrames,
+                              reinterpret_cast<void*>(aNativeStack), framePointer,
+                              mStackTop);
+      }
+    }
+#endif
   }
 
   MOZ_ALWAYS_TRUE(::ResumeThread(mThreadID) != DWORD(-1));
 
 #elif defined(XP_MACOSX)
 # if defined(MOZ_VALGRIND) && defined(RUNNING_ON_VALGRIND)
   if (RUNNING_ON_VALGRIND) {
     /* thread_suspend and thread_resume sometimes hang runs on Valgrind,
        for unknown reasons.  So, just avoid them.  See bug 1100911. */
     return;
   }
 # endif
 
-  if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
-    MOZ_ASSERT(false);
-    return;
+  if (aStack) {
+    if (::thread_suspend(mThreadID) != KERN_SUCCESS) {
+      MOZ_ASSERT(false);
+      return;
+    }
+
+    FillStackBuffer();
+
+    MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS);
   }
 
-  FillStackBuffer();
-
-  MOZ_ALWAYS_TRUE(::thread_resume(mThreadID) == KERN_SUCCESS);
-
 #endif
 }
 
 void
-ThreadStackHelper::GetNativeStack(Stack& aStack)
+ThreadStackHelper::GetNativeStack(NativeStack& aNativeStack)
 {
 #ifdef MOZ_THREADSTACKHELPER_NATIVE
-  GetStackInternal(aStack, /* aAppendNativeStack */ true);
+  GetStacksInternal(nullptr, &aNativeStack);
 #endif // MOZ_THREADSTACKHELPER_NATIVE
 }
 
+void
+ThreadStackHelper::GetPseudoAndNativeStack(Stack& aStack, NativeStack& aNativeStack)
+{
+  GetStacksInternal(&aStack, &aNativeStack);
+}
+
 #ifdef XP_LINUX
 
 int ThreadStackHelper::sInitialized;
 int ThreadStackHelper::sFillStackSignum;
 
 void
 ThreadStackHelper::FillStackHandler(int aSignal, siginfo_t* aInfo,
                                     void* aContext)
--- a/xpcom/threads/ThreadStackHelper.h
+++ b/xpcom/threads/ThreadStackHelper.h
@@ -55,16 +55,22 @@ namespace mozilla {
  * Only non-copying labels are included in the stack, which means labels
  * with custom text and markers are not included.
  */
 class ThreadStackHelper
 {
 public:
   typedef Telemetry::HangStack Stack;
 
+  // When a native stack is gathered, this vector holds the raw program counter
+  // values that FramePointerStackWalk will return to us after it walks the
+  // stack. When gathering the Telemetry payload, Telemetry will take care of
+  // mapping these program counters to proper addresses within modules.
+  typedef Telemetry::NativeHangStack NativeStack;
+
 private:
   Stack* mStackToFill;
 #ifdef MOZ_THREADSTACKHELPER_PSEUDO
   const PseudoStack* const mPseudoStack;
   size_t mMaxStackSize;
   size_t mMaxBufferSize;
 #endif
 
@@ -94,42 +100,56 @@ public:
   ~ThreadStackHelper();
 
   /**
    * Retrieve the current pseudostack of the thread associated
    * with this ThreadStackHelper.
    *
    * @param aStack Stack instance to be filled.
    */
-  void GetStack(Stack& aStack);
+  void GetPseudoStack(Stack& aStack);
 
   /**
    * Retrieve the current native stack of the thread associated
    * with this ThreadStackHelper.
    *
-   * @param aNativeStack Stack instance to be filled.
+   * @param aNativeStack NativeStack instance to be filled.
    */
-  void GetNativeStack(Stack& aStack);
+  void GetNativeStack(NativeStack& aNativeStack);
+
+  /**
+   * Retrieve the current pseudostack and native stack of the thread associated
+   * with this ThreadStackHelper. This method only pauses the target thread once
+   * to get both stacks.
+   *
+   * @param aStack        Stack instance to be filled with the pseudostack.
+   * @param aNativeStack  NativeStack instance to be filled with the native stack.
+   */
+  void GetPseudoAndNativeStack(Stack& aStack, NativeStack& aNativeStack);
 
 private:
-  void GetStackInternal(Stack& aStack, bool aAppendNativeStack);
+  // Fill in the passed aStack and aNativeStack datastructures with backtraces.
+  // If only aStack needs to be collected, nullptr may be passed for
+  // aNativeStack, and vice versa.
+  void GetStacksInternal(Stack* aStack, NativeStack* aNativeStack);
 #if defined(XP_LINUX)
 private:
   static int sInitialized;
   static int sFillStackSignum;
 
   static void FillStackHandler(int aSignal, siginfo_t* aInfo, void* aContext);
 
   sem_t mSem;
   pid_t mThreadID;
 
 #elif defined(XP_WIN)
 private:
   bool mInitialized;
   HANDLE mThreadID;
+  void* mStackTop;
 
 #elif defined(XP_MACOSX)
 private:
   thread_act_t mThreadID;
 
 #endif
 };