merge autoland to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 20 Jan 2017 15:21:47 +0100
changeset 377558 2f514ff474a80a55985ea977bb602b6d8937577d
parent 377527 e674ae0954df1bf18645ef7dba91365b8282f27e (current diff)
parent 377557 516551993d16fb186abb4469ef5eba9f88e91b9b (diff)
child 377573 3cedab21a7e65e6a1c4c2294ecfb5502575a46e3
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone53.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 autoland to mozilla-central a=merge
memory/mozjemalloc/osx_zone_types.h
--- a/browser/base/content/browser-addons.js
+++ b/browser/base/content/browser-addons.js
@@ -497,33 +497,51 @@ const gExtensionsNotifications = {
     if (!this.initialized) {
       return;
     }
     ExtensionsUI.off("change", this.boundUpdate);
   },
 
   updateAlerts() {
     let sideloaded = ExtensionsUI.sideloaded;
-    if (sideloaded.size == 0) {
+    let updates = ExtensionsUI.updates;
+    if (sideloaded.size + updates.size == 0) {
       gMenuButtonBadgeManager.removeBadge(gMenuButtonBadgeManager.BADGEID_ADDONS);
     } else {
       gMenuButtonBadgeManager.addBadge(gMenuButtonBadgeManager.BADGEID_ADDONS,
                                        "addon-alert");
     }
 
     let container = document.getElementById("PanelUI-footer-addons");
 
     while (container.firstChild) {
       container.firstChild.remove();
     }
 
     // Strings below to be properly localized in bug 1316996
     const DEFAULT_EXTENSION_ICON =
       "chrome://mozapps/skin/extensions/extensionGeneric.svg";
     let items = 0;
+    for (let update of updates) {
+      if (++items > 4) {
+        break;
+      }
+      let button = document.createElement("toolbarbutton");
+      button.setAttribute("label", `"${update.addon.name}" requires new permissions`);
+
+      let icon = update.addon.iconURL || DEFAULT_EXTENSION_ICON;
+      button.setAttribute("image", icon);
+
+      button.addEventListener("click", evt => {
+        ExtensionsUI.showUpdate(gBrowser, update);
+      });
+
+      container.appendChild(button);
+    }
+
     for (let addon of sideloaded) {
       if (++items > 4) {
         break;
       }
       let button = document.createElement("toolbarbutton");
       button.setAttribute("label", `"${addon.name}" added to Firefox`);
 
       let icon = addon.iconURL || DEFAULT_EXTENSION_ICON;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7407,20 +7407,22 @@ var gIdentityHandler = {
             found = true;
             permission.inUse = true;
             break;
           }
           if (!found) {
             // If the permission item we were looking for doesn't exist,
             // the user has temporarily allowed sharing and we need to add
             // an item in the permissions array to reflect this.
-            let permission =
-              SitePermissions.getPermissionDetails(id, SitePermissions.SCOPE_REQUEST);
-            permission.inUse = true;
-            permissions.push(permission);
+            permissions.push({
+              id,
+              state: SitePermissions.ALLOW,
+              scope: SitePermissions.SCOPE_REQUEST,
+              inUse: true,
+            });
           }
         }
       }
     }
     for (let permission of permissions) {
       let item = this._createPermissionItem(permission);
       this._permissionList.appendChild(item);
     }
@@ -7471,17 +7473,17 @@ var gIdentityHandler = {
     stateLabel.setAttribute("class", "identity-popup-permission-state-label");
     let {state, scope} = aPermission;
     // If the user did not permanently allow this device but it is currently
     // used, set the variables to display a "temporarily allowed" info.
     if (state != SitePermissions.ALLOW && aPermission.inUse) {
       state = SitePermissions.ALLOW;
       scope = SitePermissions.SCOPE_REQUEST;
     }
-    stateLabel.textContent = SitePermissions.getStateLabel(state, scope);
+    stateLabel.textContent = SitePermissions.getCurrentStateLabel(state, scope);
 
     let button = document.createElement("button");
     button.setAttribute("class", "identity-popup-permission-remove-button");
     let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip");
     button.setAttribute("tooltiptext", tooltiptext);
     button.addEventListener("command", () => {
 	  let browser = gBrowser.selectedBrowser;
       // Only resize the window if the reload hint was previously hidden.
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -130,17 +130,17 @@ function createRow(aPartId) {
   controls.appendChild(spacer);
 
   let radiogroup = document.createElement("radiogroup");
   radiogroup.setAttribute("id", radiogroupId);
   radiogroup.setAttribute("orient", "horizontal");
   for (let state of SitePermissions.getAvailableStates(aPartId)) {
     let radio = document.createElement("radio");
     radio.setAttribute("id", aPartId + "#" + state);
-    radio.setAttribute("label", SitePermissions.getStateLabel(state));
+    radio.setAttribute("label", SitePermissions.getMultichoiceStateLabel(state));
     radio.setAttribute("command", commandId);
     radiogroup.appendChild(radio);
   }
   controls.appendChild(radiogroup);
 
   row.appendChild(controls);
 
   document.getElementById("permList").appendChild(row);
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -115,16 +115,19 @@ support-files =
   test_mcb_redirect.sjs
   file_bug1045809_1.html
   file_bug1045809_2.html
   file_csp_block_all_mixedcontent.html
   file_csp_block_all_mixedcontent.js
   file_install_extensions.html
   browser_webext_permissions.xpi
   browser_webext_nopermissions.xpi
+  browser_webext_update1.xpi
+  browser_webext_update2.xpi
+  browser_webext_update.json
   !/image/test/mochitest/blue.png
   !/toolkit/components/passwordmgr/test/browser/form_basic.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test.html
   !/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html
   !/toolkit/content/tests/browser/common/mockTransfer.js
   !/toolkit/modules/tests/browser/metadata_*.html
   !/toolkit/mozapps/extensions/test/xpinstall/amosigned.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi
@@ -301,16 +304,17 @@ skip-if = os == "mac" # decoder doctor i
 [browser_discovery.js]
 [browser_double_close_tab.js]
 [browser_documentnavigation.js]
 [browser_duplicateIDs.js]
 [browser_drag.js]
 skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 [browser_extension_permissions.js]
 [browser_extension_sideloading.js]
+[browser_extension_update.js]
 [browser_favicon_change.js]
 [browser_favicon_change_not_in_document.js]
 [browser_findbarClose.js]
 [browser_focusonkeydown.js]
 [browser_fullscreen-window-open.js]
 tags = fullscreen
 skip-if = os == "linux" # Linux: Intermittent failures - bug 941575.
 [browser_fxaccounts.js]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_extension_update.js
@@ -0,0 +1,192 @@
+const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
+
+const URL_BASE = "https://example.com/browser/browser/base/content/test/general";
+const ID = "update@tests.mozilla.org";
+
+function promiseViewLoaded(tab, viewid) {
+  let win = tab.linkedBrowser.contentWindow;
+  if (win.gViewController && !win.gViewController.isLoading &&
+      win.gViewController.currentViewId == viewid) {
+     return Promise.resolve();
+  }
+
+  return new Promise(resolve => {
+    function listener() {
+      if (win.gViewController.currentViewId != viewid) {
+        return;
+      }
+      win.document.removeEventListener("ViewChanged", listener);
+      resolve();
+    }
+    win.document.addEventListener("ViewChanged", listener);
+  });
+}
+
+function promisePopupNotificationShown(name) {
+  return new Promise(resolve => {
+    function popupshown() {
+      let notification = PopupNotifications.getNotification(name);
+      if (!notification) { return; }
+
+      ok(notification, `${name} notification shown`);
+      ok(PopupNotifications.isPanelOpen, "notification panel open");
+
+      PopupNotifications.panel.removeEventListener("popupshown", popupshown);
+      resolve(PopupNotifications.panel.firstChild);
+    }
+
+    PopupNotifications.panel.addEventListener("popupshown", popupshown);
+  });
+}
+
+function getBadgeStatus() {
+  let menuButton = document.getElementById("PanelUI-menu-button");
+  return menuButton.getAttribute("badge-status");
+}
+
+function promiseUpdateDownloaded(addon) {
+  return new Promise(resolve => {
+    let listener = {
+      onDownloadEnded(install) {
+        if (install.addon.id == addon.id) {
+          AddonManager.removeInstallListener(listener);
+          resolve();
+        }
+      },
+    };
+    AddonManager.addInstallListener(listener);
+  });
+}
+
+function promiseUpgrade(addon) {
+  return new Promise(resolve => {
+    let listener = {
+      onInstallEnded(install, newAddon) {
+        if (newAddon.id == addon.id) {
+          AddonManager.removeInstallListener(listener);
+          resolve(newAddon);
+        }
+      },
+    };
+    AddonManager.addInstallListener(listener);
+  });
+}
+
+add_task(function* () {
+  yield SpecialPowers.pushPrefEnv({set: [
+    // Turn on background updates
+    ["extensions.update.enabled", true],
+
+    // Point updates to the local mochitest server
+    ["extensions.update.background.url", `${URL_BASE}/browser_webext_update.json`],
+
+    // We don't have pre-pinned certificates for the local mochitest server
+    ["extensions.install.requireBuiltInCerts", false],
+    ["extensions.update.requireBuiltInCerts", false],
+
+    // XXX remove this when prompts are enabled by default
+    ["extensions.webextPermissionPrompts", true],
+  ]});
+
+  // Install version 1.0 of the test extension
+  let url1 = `${URL_BASE}/browser_webext_update1.xpi`;
+  let install = yield AddonManager.getInstallForURL(url1, null, "application/x-xpinstall");
+  ok(install, "Created install");
+
+  let addon = yield new Promise(resolve => {
+    install.addListener({
+      onInstallEnded(_install, _addon) {
+        resolve(_addon);
+      },
+    });
+    install.install();
+  });
+
+  ok(addon, "Addon was installed");
+  is(getBadgeStatus(), "", "Should not start out with an addon alert badge");
+
+  // Trigger an update check and wait for the update for this addon
+  // to be downloaded.
+  let updatePromise = promiseUpdateDownloaded(addon);
+  AddonManagerPrivate.backgroundUpdateCheck();
+  yield updatePromise;
+
+  is(getBadgeStatus(), "addon-alert", "Should have addon alert badge");
+
+  // Find the menu entry for the update
+  yield PanelUI.show();
+
+  let addons = document.getElementById("PanelUI-footer-addons");
+  is(addons.children.length, 1, "Have a menu entry for the update");
+
+  // Click the menu item
+  let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:addons");
+  let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
+  addons.children[0].click();
+
+  // about:addons should load and go to the list of extensions
+  let tab = yield tabPromise;
+  is(tab.linkedBrowser.currentURI.spec, "about:addons");
+
+  const VIEW = "addons://list/extension";
+  yield promiseViewLoaded(tab, VIEW);
+  let win = tab.linkedBrowser.contentWindow;
+  ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
+  is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
+
+  // Wait for the permission prompt and cancel it
+  let panel = yield popupPromise;
+  panel.secondaryButton.click();
+
+  addon = yield AddonManager.getAddonByID(ID);
+  is(addon.version, "1.0", "Should still be running the old version");
+
+  yield BrowserTestUtils.removeTab(tab);
+
+  // Alert badge and hamburger menu items should be gone
+  is(getBadgeStatus(), "", "Addon alert badge should be gone");
+
+  yield PanelUI.show();
+  addons = document.getElementById("PanelUI-footer-addons");
+  is(addons.children.length, 0, "Update menu entries should be gone");
+  yield PanelUI.hide();
+
+  // Re-check for an update
+  updatePromise = promiseUpdateDownloaded(addon);
+  yield AddonManagerPrivate.backgroundUpdateCheck();
+  yield updatePromise;
+
+  is(getBadgeStatus(), "addon-alert", "Should have addon alert badge");
+
+  // Find the menu entry for the update
+  yield PanelUI.show();
+
+  addons = document.getElementById("PanelUI-footer-addons");
+  is(addons.children.length, 1, "Have a menu entry for the update");
+
+  // Click the menu item
+  tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:addons");
+  popupPromise = promisePopupNotificationShown("addon-webext-permissions");
+  addons.children[0].click();
+
+  // Wait for about:addons to load
+  tab = yield tabPromise;
+  is(tab.linkedBrowser.currentURI.spec, "about:addons");
+
+  yield promiseViewLoaded(tab, VIEW);
+  win = tab.linkedBrowser.contentWindow;
+  ok(!win.gViewController.isLoading, "about:addons view is fully loaded");
+  is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
+
+  // Wait for the permission prompt and accept it this time
+  updatePromise = promiseUpgrade(addon);
+  panel = yield popupPromise;
+  panel.button.click();
+
+  addon = yield updatePromise;
+  is(addon.version, "2.0", "Should have upgraded to the new version");
+
+  yield BrowserTestUtils.removeTab(tab);
+
+  is(getBadgeStatus(), "", "Addon alert badge should be gone");
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_webext_update.json
@@ -0,0 +1,18 @@
+{
+  "addons": {
+    "update@tests.mozilla.org": {
+      "updates": [
+        {
+          "version": "2.0",
+          "update_link": "https://example.com/browser/browser/base/content/test/general/browser_webext_update2.xpi",
+          "applications": {
+            "gecko": {
+              "strict_min_version": "1",
+              "advisory_max_version": "55.0"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8eac9daa01745a2247eb9284b51858546b52f6a1
GIT binary patch
literal 4262
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..81c7407ba7f17e486ce553318369dc7aaf1b017b
GIT binary patch
literal 4287
zc${@tXH=6}*A1bFKxop7AU(9ut3aqCT|kr~5=ww*La!mxi*!(s&{0AWP?`dv4I<Ke
z6QuVJQe^;nalSQczL_<1o^^hlXWhHk-uLW3+env?hz<Y%kOJB(C3Vcik&TBG0Kk1}
z0N~eOeN9tUk-G+35TuL0^V6p=QFjm6^aDS+m*kAHF`Z3Pm5@+fSeg%Cr~q1EBJQPq
zHv^nW5iA*|mLy_No>%b#BQT*hmQj|>J8mpEQH2?4tU>Rdw4aQh1oR&?1~xXI2=B_T
z%CGul6DCf?+8ids6kwY@x$1Lz5*Z3mxCu!p)JZGorj}3}kl<iw2oS510>#=Fz=QO@
z5hdR8!%~ZpQbYucj!+1u0($}x!AvJ{+GVp@P*)=+wpdBk1Hy)DK?IcJ+(dHq_(@JF
zQVk#A;FoS}(49AcbwV(=)j3shdN#qQMD5xIq)%>;n49-!#YJ`+zGDpzM@6(03zVG+
zI@dmRX_|a|p2vf9<hJuzCL`DdFCMpMPz0|<r4ow;Mrczl&>fu5cbTNm?SPNeFC!Z_
zILy3>WTA;M%pz2|gZyG=38m+nqHqd0hu}G7FjR`o=8{ISwcqzLTao`aHvnY|_K0-G
z7sBdz`%}-v3}Y|;arLfra53icg2T+ywLF5wf{FU~Y_4lHHD~m!5cGWr+VFidjwrE(
zE3iy4DwRZyq-tm@&=K&Wg)=?Uq)c*}5H5uyCk%C`nkCYS)n7*;s<y^x;>LX}M?ff2
z=jv-yi`}mh5+9wLR@8UeRjNrDPgYs3MMkASDzTp=@XC^8d9{yN;6lpL-+Z6;n{HUf
zDZjAxR4}(!fZ2Gr33o!;1XkT2wT>3!;Yb8<bgia`sn;%r%Us(nnQsSNVV5bXYJH)@
zw5c(e{=SAVhIQ4$uwg_t_>GodXKzG_%dFkwQ}9HwF{Tgqv~h<miLK0g!*dq>zys`0
z($6Vv1w-CT**iV0wegyOz9-AadTzZA#HqMc(m#ZWRu6KD1NG5fiN0lS)h4p<UM?7B
zDQq5`I(ypBOZ#Q54nkP07o=C6MRLDS4qvwo298<f{VXKO0Dbk2E*+N(KZpZG3tw2t
zyg<<7mYls%NvcXOTbsUcwDktmOuSrRa$e?;lhOc3CMc}m$5$SrZpJ)I{wz~4#o*gL
z?0@gY=c+`FuF9ECgb{nh$PGE$Q*^-)Bp25umS%M0Iy1hz&dfy7QM$stal;POvXL`Z
zw~lPS#dTgAoqQI)ikvVRLj^_1nD&~}mz0=!8WZGva5Tcv?QH5YDtg=9?+f;t(gEm&
zO;(=Mk1O^yv0O(mP}Vu_$AnReqqs~%Caz1ElZTUayup<W`){2a@VYl0Trj#Z)MM!K
zMqAKpGzz#$Y}JtsX%xv}LT4D8RD>~B)AoqRwj+9*wD31iu~(?E@d}CNcMr5OeF^dO
zA(d+(vYI@cw<j?rt&gvd@lwr(in4%vh$E<CWYRO6f4DnWyqviPVl2F%rR`YCMSOe0
z$X(iOPu)<|S@f0LI%(f)m7dR2c*&Hlv<V`D=n+MAZS{Z$RhPqdB%XYL>(m)r-rPn@
zi6WH0kLe6|xp#fuZX_zwwWl&6MXZ<W;GyFcXEQ?cC%o!lbW%q?b4!P$RGU<Q{v(WN
z(-RAj;(#=kcBJpcj}0lh$gDKSKzLC}Dy@pdmKBcecqOK8e!J-7o`SSN9kRWX*k0`*
z*Y2=yW-<M2)$A<?%HNf#TH^!DrP}K2i(7e5^zos_AC%~pe^#7J%J9$hO6|@>-VvvJ
z&tr_n3grE0sRv5Vd!)&G$p*fYkO~H>aUwQ}mt2E$#|(G*ob|l!?w-~{96%2<uuKIF
zPn!a)X)ye&W1;fVlWncW#0xt8)xaSE3|mH<7V`P~hov*}U0+hLRnPe-schrNZ)DeL
z|7Iwc)_|m&6k3b8=z2ig(CtS7H~LuUb$+{3o+l?C6It&sY#QA6{cw~<`r%{Y7S|8Z
zaz-EE@8TTee9oI)HTa>x7nWLKw28$k$S7&wS??U@Txx#&^w&I3`1JS00zfQjlW+qd
z9lkxLJ<$C;%|>bA##HMq!bF%QfLY-p^wX`UQghAT*N2q@uU$M?w<M+hp*owX0c?4a
zQ;xe-Ta-bC?N-MS$G=$?Z?9l7?;+T}37wdozwGrtHKdrC!UR-DU+(dQ3P^{yi~98O
zWR6Q(+k(F@dbCSrZEsG4GTBF%BE2Sn!Sg;JQo<h`-L%{^!8n>6>7?VVDW7XdG&a>2
zWGmMrU${$L?_uJDJo{Lexw6DiMuqRORzt`(XK~_*F@zj2|8yi?SlFo>fmK>!#qdi)
z9q;DG-C=yiH;_H~a86ACtMYtrv-aS~Y*F3lyO(`uW~Y3+Ttk+5qDeTPS04>m#{7lQ
z%FVa&+~B=R%7o3G+bwcF=4>=zZkiTN`N`%=8Kq|)jmy2vXElbrrp5Jy3U*rKNjvO0
z<x<neWEGSaQI9#hPD|m5==dC6O+rCcM#^xKEvB?H(i7tTL?gQk>8#Eb$o5^YK09v3
z5ZUz8$XXEhoLt^OFWw~7x@w&qWVZh}-%cL5o?lKt8)+8hIyl8u*Y$yPp`%3XMER_?
zs+iKOgG#kRIGC$((Ib2^hZc)U5PG%=(jmR)p8L{DAh1$r^sWYGSo&}v<plH29)p~U
zuX!X-=Jq&(dJ6{Q&F~qT);k+obd2@1=u}tlAw9B0`X^RaEx3(h?<pVfmA#p<wJr_a
zRYYZG#x@|W9x3UF6gjUO9Y#n79je><RN?||_ZHg{6P6;+rwPY*3@vZ*#LzCIsFWu8
zET172vf8|F+xWQ|dNaMPi)Xr#r`}GM^>g4YFDT+S*Zm3mf$KpOpMZL2`d~oh5RjVM
ziONPET6*SUwDyy!70^d0>>Y#!kT7M@QE2F*Nr9)z2%xZ$fk5QAv{3w1@f3QP9#wvx
z0d!BdQlkNYFQKAjybi$pYMc1z2x1RN7tf4gW#&HARBV<KYnr9WwLJBM!vx4o1dMN8
zD{J+H!dN#r1xzy!82KR(A5FTA*+Loz$Iwb{d{^za`is!7P4Amu&llt-jmJ2dH*d20
zu<G&C&aT~*4E)9wOD?)>A2(5ts2Sv6;({P<OA`$mSKL)<yA+?>ad~^1^BdY~S}>1=
zo-plplf$#p1!k2fxLXCV&A0sNL%i2Ql;Aw0K1?>Ha{??w%s`)QaOD1OmAoU;Xh$o_
z_1NW27C$Z-be?0%sQN}1Z`TxothaunLq>{9Uz0uC1D|)1-1_l+vyhc+31qkldDH=Y
zgxQk3_YrZg#8(knbV@p7G<kxtaFY?X?CJ~39R8xDbxZ{t@Rt5cw%A?QZ7{aU6M)!|
z&puAybC6O$_X{}nMP+}@+7{uHDNP<+*I_S7N!`>pZf;2~<m3{Encs(%S$H{oy=FDw
zlJshuUBHfymIEG>W~12iG;Xk1$RNF=qMn>Z@77~z!V?4(2mWx!P=D`xzrj6~1JRXi
zmk(P__dCC~xoZfEn)j(skA;+ctBw7#ZonC>G@Ic39OI$pKM#ARhVs{}jbWOWV0@je
z;@7)%4@H>_DTjcl*~SIg9&`%EM^`+ONpn&unVb-ObWjdmyLl1LZ%AK1OW$2K>=;KJ
z?raZTF?jk^UvuDC;B-ox5qWF|f8cjvYj<e(1!h06ktt<R-ZWb2Q1@oEAA8LOKghcO
zB?F?)M9TX9e#Ek>d^w@2wEhr>@q<$6{n3P%JD)dSE!?)@c9K{+|4D3D8Mpz+Z@PTt
zu)hjEKJf0YCaMio2+6(l?;<!?;jMNWYo3-TV<Z^NF&6O8Q4AU9W8eFzCOFkqyu4Q<
z>B;zRnEPi1KG$AMpUlLm1;;r3wbb1G;3$`2>!DUIdfMhbJXjM8+<p5KKr&g-1Xthk
zW#9m^ZS#3&p*%*M4s&0$<p~Pj5fh<mv_-|d{ixx&xz2c~48BD%tkE2&EPIaq$UHA2
z$d~QlH-fj=-oq^6I&_bk%-J9Ej8QQUYll7AoZ8yZt7y<M!Nm`+Fz1jso;dY75mm~F
ziL2-|Tf`!pGEiW1g+(@cjI#);rFrIeKM>|wYH#uJkJvt}UAMdZaXL$er!7HJ;x`<D
z25(@EOn1xAu*r@&6Wu2rut3YU-1_g6tFzb5s*A)QMm&)lM=8RSts2|N8Ur$l8iExs
z?r_uZPkHdaZs$mA3y8aydZax?CsOM7I}JU@CM!8I!5=CG`*^G^Li*OC%Ory$<R&~o
zhK5I=W*9%h^`R!u%J1+H=RFqu=v=bSn%LkYLczy`qhTh5oUB>?{q8%b&ex6T4YeZ@
z{peWN3|C5Z#y-8;<yKktK(CO3Ez2`d|I$6B<!|X(@G7+6G4k+zLm!<2Mq7rr!N@V2
zHOxNC_q<p_OMA3}UX5PYuRZ>aby(R{D1H5AC0nuSyQnrDE)|ueqAd%mcSC{oDNTiJ
zsTgnT)JYt$Wotzku<cTtS7!OxcQ`3rv1bJ<tMBO1TFQWqHC3B9P5r)7Xg4#?Sa5n7
zp?b1sUvf!qbd{3G{zyq*+$D9W08K_|SJV1cgRUA0Lpj48JUm4a9xf>T*lDs)Vie)K
zCv?2yc2Tdm7SK_#18vM>?{Mox>}a21{gI5sgRGo736k6K0o<M2p~<dH^ESs`;#!CK
zz{>RU<oM5g@qW4&%*}#Z8CjJ;ajkX+U5gQH3V6Gda$bnu^#Q_UOKiAKPiL_;CaaY%
z|K`}&*FF<w+`Ro<IfLX==I+{tMWC<LBz)jqnye><OG`xKh~k+)B>?`A0Qi4Jd(}P;
zwjvI`o+2=JPiHvH&eH>8^tWJ`zk$pPy_#MD{uvDa)Q*H7==XH%>57OBf^<a$`+EAT
zjKxMI=N9&Ld-OjTcZBO~IMA=Iy4BeigwiRj<gYS1q}nerSb~4x(*%joaxCry%y?=)
zp>Vdq!u<TX#7y^tBDRZ$j@+oXbAW!RrKM=1PVHOU*4IxV305wICWhltL$u9%3*}vz
zVyyv}rM8x$qJY1X?s%>&gSeXfuKLEmrCAR+d7oatt}s|cXY_BR_r1hNy*l*_uf!bv
zQbj0HN*66jE2(=sHdIeZXun6oIQG-gfk@8~5?L3b#0C;i;V;0xERb7aVDLXvP_zic
zzVt6h%h$M%!!kL3b9W=SqDBCuBmD2E{bvOc0RAI*|A7GbZyWwqe4u}r@~^A^zW)C!
z>R(`>e>cP5$^X+1f01XV{C9Kw6XBn``3s?s@?SS)q)SZl>j3f92fcbDXR2S*{{V{7
Bo$det
--- a/browser/locales/en-US/chrome/browser/sitePermissions.properties
+++ b/browser/locales/en-US/chrome/browser/sitePermissions.properties
@@ -1,18 +1,34 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-allow = Allow
-allowForSession = Allow for Session
-allowTemporarily = Allow Temporarily
-block = Block
-blockTemporarily = Block Temporarily
-alwaysAsk = Always Ask
+# LOCALIZATION NOTE (state.current.allowed,
+#                    state.current.allowedForSession,
+#                    state.current.allowedTemporarily,
+#                    state.current.blockedTemporarily,
+#                    state.current.blocked):
+# This label is used to display active permission states in the site
+# identity popup (which does not have a lot of screen space).
+state.current.allowed = Allowed
+state.current.allowedForSession = Allowed for Session
+state.current.allowedTemporarily = Allowed Temporarily
+state.current.blockedTemporarily = Blocked Temporarily
+state.current.blocked = Blocked
+
+# LOCALIZATION NOTE (state.multichoice.alwaysAsk,
+#                    state.multichoice.allow,
+#                    state.multichoice.allowForSession,
+#                    state.multichoice.block):
+# Used to label permission state checkboxes in the page info dialog.
+state.multichoice.alwaysAsk = Always Ask
+state.multichoice.allow = Allow
+state.multichoice.allowForSession = Allow for Session
+state.multichoice.block = Block
 
 permission.cookie.label = Set Cookies
 permission.desktop-notification2.label = Receive Notifications
 permission.image.label = Load Images
 permission.camera.label = Use the Camera
 permission.microphone.label = Use the Microphone
 permission.screen.label = Share the Screen
 permission.install.label = Install Add-ons
--- a/browser/modules/ExtensionsUI.jsm
+++ b/browser/modules/ExtensionsUI.jsm
@@ -21,19 +21,21 @@ XPCOMUtils.defineLazyPreferenceGetter(th
                                       "extensions.webextPermissionPrompts", false);
 
 const DEFAULT_EXENSION_ICON = "chrome://mozapps/skin/extensions/extensionGeneric.svg";
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 
 this.ExtensionsUI = {
   sideloaded: new Set(),
+  updates: new Set(),
 
   init() {
     Services.obs.addObserver(this, "webextension-permission-prompt", false);
+    Services.obs.addObserver(this, "webextension-update-permissions", false);
 
     this._checkForSideloaded();
   },
 
   _checkForSideloaded() {
     AddonManager.getAllAddons(addons => {
       // Check for any side-loaded addons that the user is allowed
       // to enable.
@@ -55,66 +57,98 @@ this.ExtensionsUI = {
         let win = RecentWindow.getMostRecentBrowserWindow();
         for (let addon of sideloaded) {
           win.openUILinkIn(`about:newaddon?id=${addon.id}`, "tab");
         }
       }
     });
   },
 
-  showSideloaded(browser, addon) {
-    addon.markAsSeen();
-    this.sideloaded.delete(addon);
-    this.emit("change");
-
+  showAddonsManager(browser, info) {
     let loadPromise = new Promise(resolve => {
       let listener = (subject, topic) => {
         if (subject.location.href == "about:addons") {
           Services.obs.removeObserver(listener, topic);
           resolve(subject);
         }
       };
       Services.obs.addObserver(listener, "EM-loaded", false);
     });
     let tab = browser.addTab("about:addons");
     browser.selectedTab = tab;
-    loadPromise.then(win => {
+
+    return loadPromise.then(win => {
       win.loadView("addons://list/extension");
-      let info = {
-        addon,
-        icon: addon.iconURL,
-        type: "sideload",
-      };
-      this.showPermissionsPrompt(browser.selectedBrowser, info).then(answer => {
-        addon.userDisabled = !answer;
-      });
+      return this.showPermissionsPrompt(browser.selectedBrowser, info);
+    });
+  },
+
+  showSideloaded(browser, addon) {
+    addon.markAsSeen();
+    this.sideloaded.delete(addon);
+    this.emit("change");
+
+    let info = {
+      addon,
+      permissions: addon.userPermissions,
+      icon: addon.iconURL,
+      type: "sideload",
+    };
+    this.showAddonsManager(browser, info).then(answer => {
+      addon.userDisabled = !answer;
+    });
+  },
+
+  showUpdate(browser, info) {
+    info.type = "update";
+    this.showAddonsManager(browser, info).then(answer => {
+      if (answer) {
+        info.resolve();
+      } else {
+        info.reject();
+      }
+      // At the moment, this prompt will re-appear next time we do an update
+      // check.  See bug 1332360 for proposal to avoid this.
+      this.updates.delete(info);
+      this.emit("change");
     });
   },
 
   observe(subject, topic, data) {
     if (topic == "webextension-permission-prompt") {
       let {target, info} = subject.wrappedJSObject;
 
       // Dismiss the progress notification.  Note that this is bad if
       // there are multiple simultaneous installs happening, see
       // bug 1329884 for a longer explanation.
       let progressNotification = target.ownerGlobal.PopupNotifications.getNotification("addon-progress", target);
       if (progressNotification) {
         progressNotification.remove();
       }
 
-      this.showPermissionsPrompt(target, info).then(answer => {
+      let reply = answer => {
         Services.obs.notifyObservers(subject, "webextension-permission-response",
                                      JSON.stringify(answer));
-      });
+      };
+
+      let perms = info.addon.userPermissions;
+      if (!perms) {
+        reply(true);
+      } else {
+        info.permissions = perms;
+        this.showPermissionsPrompt(target, info).then(reply);
+      }
+    } else if (topic == "webextension-update-permissions") {
+      this.updates.add(subject.wrappedJSObject);
+      this.emit("change");
     }
   },
 
   showPermissionsPrompt(target, info) {
-    let perms = info.addon.userPermissions;
+    let perms = info.permissions;
     if (!perms) {
       return Promise.resolve();
     }
 
     let win = target.ownerGlobal;
 
     let name = info.addon.name;
     if (name.length > 50) {
@@ -142,16 +176,21 @@ this.ExtensionsUI = {
 
     if (info.type == "sideload") {
       header = `${name} added`;
       text = "Another program on your computer installed an add-on that may affect your browser.  Please review this add-on's permission requests and choose to Enable or Disable";
       acceptText = "Enable";
       acceptKey = "E";
       cancelText = "Disable";
       cancelKey = "D";
+    } else if (info.type == "update") {
+      header = "";
+      text = `${name} has been updated.  You must approve new permissions before the updated version will install.`;
+      acceptText = "Update";
+      acceptKey = "U";
     }
 
     let formatPermission = perm => {
       try {
         // return bundle.getString(`webextPerms.description.${perm}`);
         return `localized description of permission ${perm}`;
       } catch (err) {
         // return bundle.getFormattedString("webextPerms.description.unknown",
--- a/browser/modules/SitePermissions.jsm
+++ b/browser/modules/SitePermissions.jsm
@@ -179,44 +179,16 @@ this.SitePermissions = {
         });
       }
     }
 
     return result;
   },
 
   /**
-   * Returns detailed information on the specified permission.
-   *
-   * @param {String} id
-   *        The permissionID of the permission.
-   * @param {SitePermissions scope} scope
-   *        The current scope of the permission.
-   * @param {SitePermissions state} state (optional)
-   *        The current state of the permission.
-   *        Will default to the default state if omitted.
-   *
-   * @return {Object} an object with the keys:
-   *           - id: the permissionID of the permission
-   *           - label: the localized label
-   *           - state: the passed in state argument
-   *           - scope: the passed in scope argument
-   *           - availableStates: an array of all available states for that permission,
-   *             represented as objects with the keys:
-   *             - id: the state constant
-   *             - label: the translated label of that state
-   */
-  getPermissionDetails(id, scope, state = this.getDefault(id)) {
-    let availableStates = this.getAvailableStates(id).map(val => {
-      return { id: val, label: this.getStateLabel(val) };
-    });
-    return {id, label: this.getPermissionLabel(id), state, scope, availableStates};
-  },
-
-  /**
    * Returns all custom permissions for a given browser.
    *
    * To receive a more detailed, albeit less performant listing see
    * SitePermissions.getAllPermissionDetailsForBrowser().
    *
    * @param {Browser} browser
    *        The browser to fetch permission for.
    *
@@ -244,21 +216,27 @@ this.SitePermissions = {
 
   /**
    * Returns a list of objects with detailed information on all permissions
    * that are currently set for the given browser.
    *
    * @param {Browser} browser
    *        The browser to fetch permission for.
    *
-   * @return {Array} a list of objects. See getPermissionDetails for the content of each object.
+   * @return {Array<Object>} a list of objects with the keys:
+   *           - id: the permissionID of the permission
+   *           - state: a constant representing the current permission state
+   *             (e.g. SitePermissions.ALLOW)
+   *           - scope: a constant representing how long the permission will
+   *             be kept.
+   *           - label: the localized label
    */
   getAllPermissionDetailsForBrowser(browser) {
     return this.getAllForBrowser(browser).map(({id, scope, state}) =>
-      this.getPermissionDetails(id, scope, state));
+      ({id, scope, state, label: this.getPermissionLabel(id)}));
   },
 
   /**
    * Checks whether a UI for managing permissions should be exposed for a given
    * URI. This excludes file URIs, for instance, as they don't have a host,
    * even though nsIPermissionManager can still handle them.
    *
    * @param {nsIURI} uri
@@ -484,39 +462,62 @@ this.SitePermissions = {
   },
 
   /**
    * Returns the localized label for the given permission state, to be used in
    * a UI for managing permissions.
    *
    * @param {SitePermissions state} state
    *        The state to get the label for.
+   *
+   * @return {String|null} the localized label or null if an
+   *         unknown state was passed.
+   */
+  getMultichoiceStateLabel(state) {
+    switch (state) {
+      case this.UNKNOWN:
+        return gStringBundle.GetStringFromName("state.multichoice.alwaysAsk");
+      case this.ALLOW:
+        return gStringBundle.GetStringFromName("state.multichoice.allow");
+      case this.ALLOW_COOKIES_FOR_SESSION:
+        return gStringBundle.GetStringFromName("state.multichoice.allowForSession");
+      case this.BLOCK:
+        return gStringBundle.GetStringFromName("state.multichoice.block");
+      default:
+        return null;
+    }
+  },
+
+  /**
+   * Returns the localized label for a permission's current state.
+   *
+   * @param {SitePermissions state} state
+   *        The state to get the label for.
    * @param {SitePermissions scope} scope (optional)
    *        The scope to get the label for.
    *
-   * @return {String} the localized label.
+   * @return {String|null} the localized label or null if an
+   *         unknown state was passed.
    */
-  getStateLabel(state, scope = null) {
+  getCurrentStateLabel(state, scope = null) {
     switch (state) {
-      case this.UNKNOWN:
-        return gStringBundle.GetStringFromName("alwaysAsk");
       case this.ALLOW:
         if (scope && scope != this.SCOPE_PERSISTENT)
-          return gStringBundle.GetStringFromName("allowTemporarily");
-        return gStringBundle.GetStringFromName("allow");
+          return gStringBundle.GetStringFromName("state.current.allowedTemporarily");
+        return gStringBundle.GetStringFromName("state.current.allowed");
       case this.ALLOW_COOKIES_FOR_SESSION:
-        return gStringBundle.GetStringFromName("allowForSession");
+        return gStringBundle.GetStringFromName("state.current.allowedForSession");
       case this.BLOCK:
         if (scope && scope != this.SCOPE_PERSISTENT)
-          return gStringBundle.GetStringFromName("blockTemporarily");
-        return gStringBundle.GetStringFromName("block");
+          return gStringBundle.GetStringFromName("state.current.blockedTemporarily");
+        return gStringBundle.GetStringFromName("state.current.blocked");
       default:
         return null;
     }
-  }
+  },
 };
 
 var gPermissionObject = {
   /* Holds permission ID => options pairs.
    *
    * Supported options:
    *
    *  - exactHostMatch
--- a/browser/modules/test/browser_SitePermissions.js
+++ b/browser/modules/test/browser_SitePermissions.js
@@ -33,68 +33,47 @@ add_task(function* testGetAllPermissionD
   let permissions = SitePermissions.getAllPermissionDetailsForBrowser(tab.linkedBrowser);
 
   let camera = permissions.find(({id}) => id === "camera");
   Assert.deepEqual(camera, {
     id: "camera",
     label: "Use the Camera",
     state: SitePermissions.ALLOW,
     scope: SitePermissions.SCOPE_PERSISTENT,
-    availableStates: [
-      { id: SitePermissions.UNKNOWN, label: "Always Ask" },
-      { id: SitePermissions.ALLOW, label: "Allow" },
-      { id: SitePermissions.BLOCK, label: "Block" },
-    ]
   });
 
-  // check that removed permissions (State.UNKNOWN) are skipped
+  // Check that removed permissions (State.UNKNOWN) are skipped.
   SitePermissions.remove(uri, "camera");
   permissions = SitePermissions.getAllPermissionDetailsForBrowser(tab.linkedBrowser);
 
   camera = permissions.find(({id}) => id === "camera");
   Assert.equal(camera, undefined);
 
-  // check that different available state values are represented
-
   let cookie = permissions.find(({id}) => id === "cookie");
   Assert.deepEqual(cookie, {
     id: "cookie",
     label: "Set Cookies",
     state: SitePermissions.ALLOW_COOKIES_FOR_SESSION,
     scope: SitePermissions.SCOPE_PERSISTENT,
-    availableStates: [
-      { id: SitePermissions.ALLOW, label: "Allow" },
-      { id: SitePermissions.ALLOW_COOKIES_FOR_SESSION, label: "Allow for Session" },
-      { id: SitePermissions.BLOCK, label: "Block" },
-    ]
   });
 
   let popup = permissions.find(({id}) => id === "popup");
   Assert.deepEqual(popup, {
     id: "popup",
     label: "Open Pop-up Windows",
     state: SitePermissions.BLOCK,
     scope: SitePermissions.SCOPE_PERSISTENT,
-    availableStates: [
-      { id: SitePermissions.ALLOW, label: "Allow" },
-      { id: SitePermissions.BLOCK, label: "Block" },
-    ]
   });
 
   let geo = permissions.find(({id}) => id === "geo");
   Assert.deepEqual(geo, {
     id: "geo",
     label: "Access Your Location",
     state: SitePermissions.ALLOW,
     scope: SitePermissions.SCOPE_SESSION,
-    availableStates: [
-      { id: SitePermissions.UNKNOWN, label: "Always Ask" },
-      { id: SitePermissions.ALLOW, label: "Allow" },
-      { id: SitePermissions.BLOCK, label: "Block" },
-    ]
   });
 
   SitePermissions.remove(uri, "cookie");
   SitePermissions.remove(uri, "popup");
   SitePermissions.remove(uri, "geo");
 
   yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
 });
--- a/browser/modules/test/xpcshell/test_SitePermissions.js
+++ b/browser/modules/test/xpcshell/test_SitePermissions.js
@@ -46,8 +46,24 @@ add_task(function* testGetAllByURI() {
   SitePermissions.remove(uri, "desktop-notification");
   Assert.deepEqual(SitePermissions.getAllByURI(uri), []);
 
   // XXX Bug 1303108 - Control Center should only show non-default permissions
   SitePermissions.set(uri, "addon", SitePermissions.BLOCK);
   Assert.deepEqual(SitePermissions.getAllByURI(uri), []);
   SitePermissions.remove(uri, "addon");
 });
+
+add_task(function* testGetAvailableStates() {
+  Assert.deepEqual(SitePermissions.getAvailableStates("camera"),
+                   [ SitePermissions.UNKNOWN,
+                     SitePermissions.ALLOW,
+                     SitePermissions.BLOCK ]);
+
+  Assert.deepEqual(SitePermissions.getAvailableStates("cookie"),
+                   [ SitePermissions.ALLOW,
+                     SitePermissions.ALLOW_COOKIES_FOR_SESSION,
+                     SitePermissions.BLOCK ]);
+
+  Assert.deepEqual(SitePermissions.getAvailableStates("popup"),
+                   [ SitePermissions.ALLOW,
+                     SitePermissions.BLOCK ]);
+});
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -1272,66 +1272,21 @@ EventStateManager::IsRemoteTarget(nsICon
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(target);
   if (browserFrame && browserFrame->GetReallyIsBrowser()) {
     return !!TabParent::GetFrom(target);
   }
 
   return false;
 }
 
-static bool
-CrossProcessSafeEvent(const WidgetEvent& aEvent)
-{
-  switch (aEvent.mClass) {
-  case eKeyboardEventClass:
-  case eWheelEventClass:
-    return true;
-  case eMouseEventClass:
-    switch (aEvent.mMessage) {
-    case eMouseDown:
-    case eMouseUp:
-    case eMouseMove:
-    case eContextMenu:
-    case eMouseEnterIntoWidget:
-    case eMouseExitFromWidget:
-    case eMouseTouchDrag:
-      return true;
-    default:
-      return false;
-    }
-  case eTouchEventClass:
-    switch (aEvent.mMessage) {
-    case eTouchStart:
-    case eTouchMove:
-    case eTouchEnd:
-    case eTouchCancel:
-      return true;
-    default:
-      return false;
-    }
-  case eDragEventClass:
-    switch (aEvent.mMessage) {
-    case eDragOver:
-    case eDragExit:
-    case eDrop:
-      return true;
-    default:
-      return false;
-    }
-  default:
-    return false;
-  }
-}
-
 bool
 EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
                                            nsEventStatus *aStatus) {
   if (*aStatus == nsEventStatus_eConsumeNoDefault ||
-      aEvent->mFlags.mNoCrossProcessBoundaryForwarding ||
-      !CrossProcessSafeEvent(*aEvent)) {
+      !aEvent->CanBeSentToRemoteProcess()) {
     return false;
   }
 
   // Collect the remote event targets we're going to forward this
   // event to.
   //
   // NB: the elements of |targets| must be unique, for correctness.
   AutoTArray<nsCOMPtr<nsIContent>, 1> targets;
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1561,19 +1561,21 @@ mozilla::ipc::IPCResult
 TabChild::RecvMouseEvent(const nsString& aType,
                          const float&    aX,
                          const float&    aY,
                          const int32_t&  aButton,
                          const int32_t&  aClickCount,
                          const int32_t&  aModifiers,
                          const bool&     aIgnoreRootScrollFrame)
 {
-  APZCCallbackHelper::DispatchMouseEvent(GetPresShell(), aType, CSSPoint(aX, aY),
-      aButton, aClickCount, aModifiers, aIgnoreRootScrollFrame,
-      nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN, 0 /* Use the default value here. */);
+  APZCCallbackHelper::DispatchMouseEvent(GetPresShell(), aType,
+                                         CSSPoint(aX, aY), aButton, aClickCount,
+                                         aModifiers, aIgnoreRootScrollFrame,
+                                         nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN,
+                                         0 /* Use the default value here. */);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& aEvent,
                                  const ScrollableLayerGuid& aGuid,
                                  const uint64_t& aInputBlockId)
 {
@@ -1598,23 +1600,25 @@ mozilla::ipc::IPCResult
 TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
                                    const ScrollableLayerGuid& aGuid,
                                    const uint64_t& aInputBlockId)
 {
   // Mouse events like eMouseEnterIntoWidget, that are created in the parent
   // process EventStateManager code, have an input block id which they get from
   // the InputAPZContext in the parent process stack. However, they did not
   // actually go through the APZ code and so their mHandledByAPZ flag is false.
-  // Since thos events didn't go through APZ, we don't need to send notifications
-  // for them.
+  // Since thos events didn't go through APZ, we don't need to send
+  // notifications for them.
   bool pendingLayerization = false;
   if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
     nsCOMPtr<nsIDocument> document(GetDocument());
-    pendingLayerization = APZCCallbackHelper::SendSetTargetAPZCNotification(
-      mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
+    pendingLayerization =
+      APZCCallbackHelper::SendSetTargetAPZCNotification(mPuppetWidget, document,
+                                                        aEvent, aGuid,
+                                                        aInputBlockId);
   }
 
   nsEventStatus unused;
   InputAPZContext context(aGuid, aInputBlockId, unused);
   if (pendingLayerization) {
     context.SetPendingLayerization();
   }
 
@@ -1639,17 +1643,17 @@ TabChild::RecvMouseWheelEvent(const Widg
     nsCOMPtr<nsIDocument> document(GetDocument());
     APZCCallbackHelper::SendSetTargetAPZCNotification(
       mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
   }
 
   WidgetWheelEvent localEvent(aEvent);
   localEvent.mWidget = mPuppetWidget;
   APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
-      mPuppetWidget->GetDefaultScale());
+                                             mPuppetWidget->GetDefaultScale());
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (localEvent.mCanTriggerSwipe) {
     SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
   }
 
   if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
     mAPZEventState->ProcessWheelEvent(localEvent, aGuid, aInputBlockId);
@@ -1664,40 +1668,42 @@ TabChild::RecvRealTouchEvent(const Widge
                              const nsEventStatus& aApzResponse)
 {
   TABC_LOG("Receiving touch event of type %d\n", aEvent.mMessage);
 
   WidgetTouchEvent localEvent(aEvent);
   localEvent.mWidget = mPuppetWidget;
 
   APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
-      mPuppetWidget->GetDefaultScale());
+                                             mPuppetWidget->GetDefaultScale());
 
   if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) {
     nsCOMPtr<nsIDocument> document = GetDocument();
     if (gfxPrefs::TouchActionEnabled()) {
-      APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(mPuppetWidget,
-          document, localEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback);
+      APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(
+        mPuppetWidget, document, localEvent, aInputBlockId,
+        mSetAllowedTouchBehaviorCallback);
     }
     APZCCallbackHelper::SendSetTargetAPZCNotification(mPuppetWidget, document,
-        localEvent, aGuid, aInputBlockId);
+                                                      localEvent, aGuid,
+                                                      aInputBlockId);
   }
 
   // Dispatch event to content (potentially a long-running operation)
   nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   if (!AsyncPanZoomEnabled()) {
     // We shouldn't have any e10s platforms that have touch events enabled
     // without APZ.
     MOZ_ASSERT(false);
     return IPC_OK();
   }
 
   mAPZEventState->ProcessTouchEvent(localEvent, aGuid, aInputBlockId,
-      aApzResponse, status);
+                                    aApzResponse, status);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
                                  const ScrollableLayerGuid& aGuid,
                                  const uint64_t& aInputBlockId,
                                  const nsEventStatus& aApzResponse)
@@ -1777,17 +1783,18 @@ TabChild::RequestNativeKeyBindings(AutoC
     aAutoCache->CacheNoCommands();
   }
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvNativeSynthesisResponse(const uint64_t& aObserverId,
                                       const nsCString& aResponse)
 {
-  mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId, aResponse.get());
+  mozilla::widget::AutoObserverNotifier::NotifySavedObserver(aObserverId,
+                                                             aResponse.get());
   return IPC_OK();
 }
 
 // In case handling repeated keys takes much time, we skip firing new ones.
 bool
 TabChild::SkipRepeatedKeyEvent(const WidgetKeyboardEvent& aEvent)
 {
   if (mRepeatedKeyEventTime.IsNull() ||
@@ -1820,50 +1827,50 @@ TabChild::UpdateRepeatedKeyEventEndTime(
 {
   if (aEvent.mIsRepeat &&
       (aEvent.mMessage == eKeyDown || aEvent.mMessage == eKeyPress)) {
     mRepeatedKeyEventTime = TimeStamp::Now();
   }
 }
 
 mozilla::ipc::IPCResult
-TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event,
+TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& aEvent,
                            const MaybeNativeKeyBinding& aBindings)
 {
-  if (SkipRepeatedKeyEvent(event)) {
+  if (SkipRepeatedKeyEvent(aEvent)) {
     return IPC_OK();
   }
 
   AutoCacheNativeKeyCommands autoCache(mPuppetWidget);
 
-  if (event.mMessage == eKeyPress) {
+  if (aEvent.mMessage == eKeyPress) {
     // If content code called preventDefault() on a keydown event, then we don't
     // want to process any following keypress events.
     if (mIgnoreKeyPressEvent) {
       return IPC_OK();
     }
     if (aBindings.type() == MaybeNativeKeyBinding::TNativeKeyBinding) {
       const NativeKeyBinding& bindings = aBindings;
       autoCache.Cache(bindings.singleLineCommands(),
                       bindings.multiLineCommands(),
                       bindings.richTextCommands());
     } else {
       autoCache.CacheNoCommands();
     }
   }
 
-  WidgetKeyboardEvent localEvent(event);
+  WidgetKeyboardEvent localEvent(aEvent);
   localEvent.mWidget = mPuppetWidget;
   nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
 
   // Update the end time of the possible repeated event so that we can skip
   // some incoming events in case event handling took long time.
   UpdateRepeatedKeyEventEndTime(localEvent);
 
-  if (event.mMessage == eKeyDown) {
+  if (aEvent.mMessage == eKeyDown) {
     mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
   }
 
   if (localEvent.mFlags.mIsSuppressedOrDelayed) {
     localEvent.PreventDefault();
   }
 
   // If a response is desired from the content process, resend the key event.
@@ -1889,32 +1896,32 @@ TabChild::RecvKeyEvent(const nsString& a
 {
   bool ignored = false;
   nsContentUtils::SendKeyEvent(mPuppetWidget, aType, aKeyCode, aCharCode,
                                aModifiers, aPreventDefault, &ignored);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event)
+TabChild::RecvCompositionEvent(const WidgetCompositionEvent& aEvent)
 {
-  WidgetCompositionEvent localEvent(event);
+  WidgetCompositionEvent localEvent(aEvent);
   localEvent.mWidget = mPuppetWidget;
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
-  Unused << SendOnEventNeedingAckHandled(event.mMessage);
+  Unused << SendOnEventNeedingAckHandled(aEvent.mMessage);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
+TabChild::RecvSelectionEvent(const WidgetSelectionEvent& aEvent)
 {
-  WidgetSelectionEvent localEvent(event);
+  WidgetSelectionEvent localEvent(aEvent);
   localEvent.mWidget = mPuppetWidget;
   APZCCallbackHelper::DispatchWidgetEvent(localEvent);
-  Unused << SendOnEventNeedingAckHandled(event.mMessage);
+  Unused << SendOnEventNeedingAckHandled(aEvent.mMessage);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabChild::RecvPasteTransferable(const IPCDataTransfer& aDataTransfer,
                                 const bool& aIsPrivateData,
                                 const IPC::Principal& aRequestingPrincipal)
 {
@@ -1930,17 +1937,18 @@ TabChild::RecvPasteTransferable(const IP
                                                      trans, nullptr, this);
   NS_ENSURE_SUCCESS(rv, IPC_OK());
 
   nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
   if (NS_WARN_IF(!ourDocShell)) {
     return IPC_OK();
   }
 
-  nsCOMPtr<nsICommandParams> params = do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
+  nsCOMPtr<nsICommandParams> params =
+    do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
   NS_ENSURE_SUCCESS(rv, IPC_OK());
 
   rv = params->SetISupportsValue("transferable", trans);
   NS_ENSURE_SUCCESS(rv, IPC_OK());
 
   ourDocShell->DoCommandWithParams("cmd_pasteTransferable", params);
   return IPC_OK();
 }
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1053,110 +1053,116 @@ TabParent::DeallocPIndexedDBPermissionRe
 void
 TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY,
                           int32_t aButton, int32_t aClickCount,
                           int32_t aModifiers, bool aIgnoreRootScrollFrame)
 {
   if (!mIsDestroyed) {
     Unused << PBrowserParent::SendMouseEvent(nsString(aType), aX, aY,
                                              aButton, aClickCount,
-                                             aModifiers, aIgnoreRootScrollFrame);
+                                             aModifiers,
+                                             aIgnoreRootScrollFrame);
   }
 }
 
 void
 TabParent::SendKeyEvent(const nsAString& aType,
                         int32_t aKeyCode,
                         int32_t aCharCode,
                         int32_t aModifiers,
                         bool aPreventDefault)
 {
-  if (!mIsDestroyed) {
-    Unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode,
-                                           aModifiers, aPreventDefault);
+  if (mIsDestroyed) {
+    return;
   }
+  Unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode,
+                                         aModifiers, aPreventDefault);
 }
 
-bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event)
+bool
+TabParent::SendRealMouseEvent(WidgetMouseEvent& aEvent)
 {
   if (mIsDestroyed) {
     return false;
   }
-  event.mRefPoint += GetChildProcessOffset();
+  aEvent.mRefPoint += GetChildProcessOffset();
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     // When we mouseenter the tab, the tab's cursor should
     // become the current cursor.  When we mouseexit, we stop.
-    if (eMouseEnterIntoWidget == event.mMessage) {
+    if (eMouseEnterIntoWidget == aEvent.mMessage) {
       mTabSetsCursor = true;
       if (mCustomCursor) {
-        widget->SetCursor(mCustomCursor, mCustomCursorHotspotX, mCustomCursorHotspotY);
+        widget->SetCursor(mCustomCursor,
+                          mCustomCursorHotspotX, mCustomCursorHotspotY);
       } else if (mCursor != nsCursor(-1)) {
         widget->SetCursor(mCursor);
       }
-    } else if (eMouseExitFromWidget == event.mMessage) {
+    } else if (eMouseExitFromWidget == aEvent.mMessage) {
       mTabSetsCursor = false;
     }
   }
 
   ScrollableLayerGuid guid;
   uint64_t blockId;
   ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
 
-  if (eMouseMove == event.mMessage) {
-    if (event.mReason == WidgetMouseEvent::eSynthesized) {
-      return SendSynthMouseMoveEvent(event, guid, blockId);
+  if (eMouseMove == aEvent.mMessage) {
+    if (aEvent.mReason == WidgetMouseEvent::eSynthesized) {
+      return SendSynthMouseMoveEvent(aEvent, guid, blockId);
     } else {
-      return SendRealMouseMoveEvent(event, guid, blockId);
+      return SendRealMouseMoveEvent(aEvent, guid, blockId);
     }
   }
 
-  return SendRealMouseButtonEvent(event, guid, blockId);
+  return SendRealMouseButtonEvent(aEvent, guid, blockId);
 }
 
 LayoutDeviceToCSSScale
 TabParent::GetLayoutDeviceToCSSScale()
 {
   nsCOMPtr<nsIContent> content = do_QueryInterface(mFrameElement);
   nsIDocument* doc = (content ? content->OwnerDoc() : nullptr);
   nsIPresShell* shell = (doc ? doc->GetShell() : nullptr);
   nsPresContext* ctx = (shell ? shell->GetPresContext() : nullptr);
   return LayoutDeviceToCSSScale(ctx
     ? (float)ctx->AppUnitsPerDevPixel() / nsPresContext::AppUnitsPerCSSPixel()
     : 0.0f);
 }
 
 bool
-TabParent::SendRealDragEvent(WidgetDragEvent& event, uint32_t aDragAction,
+TabParent::SendRealDragEvent(WidgetDragEvent& aEvent, uint32_t aDragAction,
                              uint32_t aDropEffect)
 {
   if (mIsDestroyed) {
     return false;
   }
-  event.mRefPoint += GetChildProcessOffset();
-  return PBrowserParent::SendRealDragEvent(event, aDragAction, aDropEffect);
+  aEvent.mRefPoint += GetChildProcessOffset();
+  return PBrowserParent::SendRealDragEvent(aEvent, aDragAction, aDropEffect);
 }
 
-LayoutDevicePoint TabParent::AdjustTapToChildWidget(const LayoutDevicePoint& aPoint)
+LayoutDevicePoint
+TabParent::AdjustTapToChildWidget(const LayoutDevicePoint& aPoint)
 {
   return aPoint + LayoutDevicePoint(GetChildProcessOffset());
 }
 
-bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event)
+bool
+TabParent::SendMouseWheelEvent(WidgetWheelEvent& aEvent)
 {
   if (mIsDestroyed) {
     return false;
   }
 
   ScrollableLayerGuid guid;
   uint64_t blockId;
   ApzAwareEventRoutingToChild(&guid, &blockId, nullptr);
-  event.mRefPoint += GetChildProcessOffset();
-  return PBrowserParent::SendMouseWheelEvent(event, guid, blockId);
+  aEvent.mRefPoint += GetChildProcessOffset();
+  return PBrowserParent::SendMouseWheelEvent(aEvent, guid, blockId);
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return IPC_OK();
@@ -1200,17 +1206,18 @@ TabParent::RecvDispatchKeyboardEvent(con
 
   widget->DispatchInputEvent(&localEvent);
   return IPC_OK();
 }
 
 static void
 DoCommandCallback(mozilla::Command aCommand, void* aData)
 {
-  static_cast<InfallibleTArray<mozilla::CommandInt>*>(aData)->AppendElement(aCommand);
+  static_cast<InfallibleTArray<mozilla::CommandInt>*>(aData)->
+    AppendElement(aCommand);
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvRequestNativeKeyBindings(const WidgetKeyboardEvent& aEvent,
                                         MaybeNativeKeyBinding* aBindings)
 {
   AutoTArray<mozilla::CommandInt, 4> singleLine;
   AutoTArray<mozilla::CommandInt, 4> multiLine;
@@ -1224,22 +1231,25 @@ TabParent::RecvRequestNativeKeyBindings(
   }
 
   WidgetKeyboardEvent localEvent(aEvent);
 
   if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) {
     return IPC_OK();
   }
 
-  widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForSingleLineEditor,
-                                  localEvent, DoCommandCallback, &singleLine);
-  widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForMultiLineEditor,
-                                  localEvent, DoCommandCallback, &multiLine);
-  widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForRichTextEditor,
-                                  localEvent, DoCommandCallback, &richText);
+  widget->ExecuteNativeKeyBinding(
+            nsIWidget::NativeKeyBindingsForSingleLineEditor,
+            localEvent, DoCommandCallback, &singleLine);
+  widget->ExecuteNativeKeyBinding(
+            nsIWidget::NativeKeyBindingsForMultiLineEditor,
+            localEvent, DoCommandCallback, &multiLine);
+  widget->ExecuteNativeKeyBinding(
+            nsIWidget::NativeKeyBindingsForRichTextEditor,
+            localEvent, DoCommandCallback, &richText);
 
   if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) {
     *aBindings = NativeKeyBinding(singleLine, multiLine, richText);
   }
 
   return IPC_OK();
 }
 
@@ -1260,17 +1270,18 @@ public:
                      const char16_t* aData) override
   {
     if (!mTabParent || !mObserverId) {
       // We already sent the notification, or we don't actually need to
       // send any notification at all.
       return NS_OK;
     }
 
-    if (!mTabParent->SendNativeSynthesisResponse(mObserverId, nsCString(aTopic))) {
+    if (!mTabParent->SendNativeSynthesisResponse(mObserverId,
+                                                 nsCString(aTopic))) {
       NS_WARNING("Unable to send native event synthesization response!");
     }
     // Null out tabparent to indicate we already sent the response
     mTabParent = nullptr;
     return NS_OK;
   }
 
 private:
@@ -1315,33 +1326,34 @@ TabParent::RecvSynthesizeNativeKeyEvent(
                                         const nsString& aCharacters,
                                         const nsString& aUnmodifiedCharacters,
                                         const uint64_t& aObserverId)
 {
   AutoSynthesizedEventResponder responder(this, aObserverId, "keyevent");
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->SynthesizeNativeKeyEvent(aNativeKeyboardLayout, aNativeKeyCode,
-      aModifierFlags, aCharacters, aUnmodifiedCharacters,
-      responder.GetObserver());
+                                     aModifierFlags, aCharacters,
+                                     aUnmodifiedCharacters,
+                                     responder.GetObserver());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvSynthesizeNativeMouseEvent(const LayoutDeviceIntPoint& aPoint,
                                           const uint32_t& aNativeMessage,
                                           const uint32_t& aModifierFlags,
                                           const uint64_t& aObserverId)
 {
   AutoSynthesizedEventResponder responder(this, aObserverId, "mouseevent");
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->SynthesizeNativeMouseEvent(aPoint, aNativeMessage, aModifierFlags,
-      responder.GetObserver());
+                                       responder.GetObserver());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvSynthesizeNativeMouseMove(const LayoutDeviceIntPoint& aPoint,
                                          const uint64_t& aObserverId)
 {
@@ -1349,48 +1361,52 @@ TabParent::RecvSynthesizeNativeMouseMove
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->SynthesizeNativeMouseMove(aPoint, responder.GetObserver());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-TabParent::RecvSynthesizeNativeMouseScrollEvent(const LayoutDeviceIntPoint& aPoint,
-                                                const uint32_t& aNativeMessage,
-                                                const double& aDeltaX,
-                                                const double& aDeltaY,
-                                                const double& aDeltaZ,
-                                                const uint32_t& aModifierFlags,
-                                                const uint32_t& aAdditionalFlags,
-                                                const uint64_t& aObserverId)
+TabParent::RecvSynthesizeNativeMouseScrollEvent(
+             const LayoutDeviceIntPoint& aPoint,
+             const uint32_t& aNativeMessage,
+             const double& aDeltaX,
+             const double& aDeltaY,
+             const double& aDeltaZ,
+             const uint32_t& aModifierFlags,
+             const uint32_t& aAdditionalFlags,
+             const uint64_t& aObserverId)
 {
   AutoSynthesizedEventResponder responder(this, aObserverId, "mousescrollevent");
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->SynthesizeNativeMouseScrollEvent(aPoint, aNativeMessage,
-      aDeltaX, aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags,
-      responder.GetObserver());
+                                             aDeltaX, aDeltaY, aDeltaZ,
+                                             aModifierFlags, aAdditionalFlags,
+                                             responder.GetObserver());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-TabParent::RecvSynthesizeNativeTouchPoint(const uint32_t& aPointerId,
-                                          const TouchPointerState& aPointerState,
-                                          const LayoutDeviceIntPoint& aPoint,
-                                          const double& aPointerPressure,
-                                          const uint32_t& aPointerOrientation,
-                                          const uint64_t& aObserverId)
+TabParent::RecvSynthesizeNativeTouchPoint(
+             const uint32_t& aPointerId,
+             const TouchPointerState& aPointerState,
+             const LayoutDeviceIntPoint& aPoint,
+             const double& aPointerPressure,
+             const uint32_t& aPointerOrientation,
+             const uint64_t& aObserverId)
 {
   AutoSynthesizedEventResponder responder(this, aObserverId, "touchpoint");
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->SynthesizeNativeTouchPoint(aPointerId, aPointerState, aPoint,
-      aPointerPressure, aPointerOrientation, responder.GetObserver());
+                                       aPointerPressure, aPointerOrientation,
+                                       responder.GetObserver());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvSynthesizeNativeTouchTap(const LayoutDeviceIntPoint& aPoint,
                                         const bool& aLongTap,
                                         const uint64_t& aObserverId)
@@ -1409,82 +1425,87 @@ TabParent::RecvClearNativeTouchSequence(
   AutoSynthesizedEventResponder responder(this, aObserverId, "cleartouch");
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     widget->ClearNativeTouchSequence(responder.GetObserver());
   }
   return IPC_OK();
 }
 
-bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event)
+bool
+TabParent::SendRealKeyEvent(WidgetKeyboardEvent& aEvent)
 {
   if (mIsDestroyed) {
     return false;
   }
-  event.mRefPoint += GetChildProcessOffset();
+  aEvent.mRefPoint += GetChildProcessOffset();
 
   MaybeNativeKeyBinding bindings;
   bindings = void_t();
-  if (event.mMessage == eKeyPress) {
+  if (aEvent.mMessage == eKeyPress) {
     nsCOMPtr<nsIWidget> widget = GetWidget();
 
     AutoTArray<mozilla::CommandInt, 4> singleLine;
     AutoTArray<mozilla::CommandInt, 4> multiLine;
     AutoTArray<mozilla::CommandInt, 4> richText;
 
-    widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForSingleLineEditor,
-                                    event, DoCommandCallback, &singleLine);
-    widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForMultiLineEditor,
-                                    event, DoCommandCallback, &multiLine);
-    widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForRichTextEditor,
-                                    event, DoCommandCallback, &richText);
+    widget->ExecuteNativeKeyBinding(
+              nsIWidget::NativeKeyBindingsForSingleLineEditor,
+              aEvent, DoCommandCallback, &singleLine);
+    widget->ExecuteNativeKeyBinding(
+              nsIWidget::NativeKeyBindingsForMultiLineEditor,
+              aEvent, DoCommandCallback, &multiLine);
+    widget->ExecuteNativeKeyBinding(
+              nsIWidget::NativeKeyBindingsForRichTextEditor,
+              aEvent, DoCommandCallback, &richText);
 
     if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) {
       bindings = NativeKeyBinding(singleLine, multiLine, richText);
     }
   }
 
-  return PBrowserParent::SendRealKeyEvent(event, bindings);
+  return PBrowserParent::SendRealKeyEvent(aEvent, bindings);
 }
 
-bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
+bool
+TabParent::SendRealTouchEvent(WidgetTouchEvent& aEvent)
 {
   if (mIsDestroyed) {
     return false;
   }
 
   // PresShell::HandleEventInternal adds touches on touch end/cancel.  This
   // confuses remote content and the panning and zooming logic into thinking
   // that the added touches are part of the touchend/cancel, when actually
   // they're not.
-  if (event.mMessage == eTouchEnd || event.mMessage == eTouchCancel) {
-    for (int i = event.mTouches.Length() - 1; i >= 0; i--) {
-      if (!event.mTouches[i]->mChanged) {
-        event.mTouches.RemoveElementAt(i);
+  if (aEvent.mMessage == eTouchEnd || aEvent.mMessage == eTouchCancel) {
+    for (int i = aEvent.mTouches.Length() - 1; i >= 0; i--) {
+      if (!aEvent.mTouches[i]->mChanged) {
+        aEvent.mTouches.RemoveElementAt(i);
       }
     }
   }
 
   ScrollableLayerGuid guid;
   uint64_t blockId;
   nsEventStatus apzResponse;
   ApzAwareEventRoutingToChild(&guid, &blockId, &apzResponse);
 
   if (mIsDestroyed) {
     return false;
   }
 
   LayoutDeviceIntPoint offset = GetChildProcessOffset();
-  for (uint32_t i = 0; i < event.mTouches.Length(); i++) {
-    event.mTouches[i]->mRefPoint += offset;
+  for (uint32_t i = 0; i < aEvent.mTouches.Length(); i++) {
+    aEvent.mTouches[i]->mRefPoint += offset;
   }
 
-  return (event.mMessage == eTouchMove) ?
-    PBrowserParent::SendRealTouchMoveEvent(event, guid, blockId, apzResponse) :
-    PBrowserParent::SendRealTouchEvent(event, guid, blockId, apzResponse);
+  return (aEvent.mMessage == eTouchMove) ?
+    PBrowserParent::SendRealTouchMoveEvent(aEvent, guid, blockId, apzResponse) :
+    PBrowserParent::SendRealTouchEvent(aEvent, guid, blockId, apzResponse);
 }
 
 bool
 TabParent::SendHandleTap(TapType aType,
                          const LayoutDevicePoint& aPoint,
                          Modifiers aModifiers,
                          const ScrollableLayerGuid& aGuid,
                          uint64_t aInputBlockId)
@@ -1492,18 +1513,18 @@ TabParent::SendHandleTap(TapType aType,
   if (mIsDestroyed) {
     return false;
   }
   if ((aType == TapType::eSingleTap || aType == TapType::eSecondTap) &&
       GetRenderFrame()) {
     GetRenderFrame()->TakeFocusForClickFromTap();
   }
   LayoutDeviceIntPoint offset = GetChildProcessOffset();
-  return PBrowserParent::SendHandleTap(aType, aPoint + offset, aModifiers, aGuid,
-      aInputBlockId);
+  return PBrowserParent::SendHandleTap(aType, aPoint + offset, aModifiers,
+                                       aGuid, aInputBlockId);
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvSyncMessage(const nsString& aMessage,
                            const ClonedMessageData& aData,
                            InfallibleTArray<CpowEntry>&& aCpows,
                            const IPC::Principal& aPrincipal,
                            nsTArray<StructuredCloneData>* aRetVal)
@@ -1700,53 +1721,53 @@ TabParent::RecvNotifyIMEFocus(const Cont
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvNotifyIMETextChange(const ContentCache& aContentCache,
                                    const IMENotification& aIMENotification)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
-  if (!widget)
+  if (!widget) {
     return IPC_OK();
+  }
 
 #ifdef DEBUG
   nsIMEUpdatePreference updatePreference = widget->GetIMEUpdatePreference();
   NS_ASSERTION(updatePreference.WantTextChange(),
-               "Don't call Send/RecvNotifyIMETextChange without NOTIFY_TEXT_CHANGE");
+    "Don't call Send/RecvNotifyIMETextChange without NOTIFY_TEXT_CHANGE");
 #endif
 
   mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
   mContentCache.MaybeNotifyIME(widget, aIMENotification);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvNotifyIMECompositionUpdate(
              const ContentCache& aContentCache,
              const IMENotification& aIMENotification)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return IPC_OK();
   }
-
   mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
   mContentCache.MaybeNotifyIME(widget, aIMENotification);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvNotifyIMESelection(const ContentCache& aContentCache,
                                   const IMENotification& aIMENotification)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
-  if (!widget)
+  if (!widget) {
     return IPC_OK();
-
+  }
   mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
   mContentCache.MaybeNotifyIME(widget, aIMENotification);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvUpdateContentCache(const ContentCache& aContentCache)
 {
@@ -1778,17 +1799,16 @@ TabParent::RecvNotifyIMEMouseButtonEvent
 mozilla::ipc::IPCResult
 TabParent::RecvNotifyIMEPositionChange(const ContentCache& aContentCache,
                                        const IMENotification& aIMENotification)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return IPC_OK();
   }
-
   mContentCache.AssignContent(aContentCache, widget, &aIMENotification);
   mContentCache.MaybeNotifyIME(widget, aIMENotification);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 TabParent::RecvOnEventNeedingAckHandled(const EventMessage& aMessage)
 {
@@ -1935,21 +1955,21 @@ TabParent::GetChildProcessOffset()
                                                             LayoutDeviceIntPoint(0, 0),
                                                             targetFrame);
 
   return LayoutDeviceIntPoint::FromAppUnitsToNearest(
            pt, targetFrame->PresContext()->AppUnitsPerDevPixel());
 }
 
 mozilla::ipc::IPCResult
-TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event)
+TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent)
 {
   NS_ENSURE_TRUE(mFrameElement, IPC_OK());
 
-  WidgetKeyboardEvent localEvent(event);
+  WidgetKeyboardEvent localEvent(aEvent);
   // Mark the event as not to be dispatched to remote process again.
   localEvent.StopCrossProcessForwarding();
 
   // Here we convert the WidgetEvent that we received to an nsIDOMEvent
   // to be able to dispatch it to the <browser> element as the target element.
   nsIDocument* doc = mFrameElement->OwnerDoc();
   nsIPresShell* presShell = doc->GetShell();
   NS_ENSURE_TRUE(presShell, IPC_OK());
@@ -2007,43 +2027,43 @@ TabParent::HandleQueryContentEvent(Widge
       break;
     default:
       break;
   }
   return true;
 }
 
 bool
-TabParent::SendCompositionEvent(WidgetCompositionEvent& event)
+TabParent::SendCompositionEvent(WidgetCompositionEvent& aEvent)
 {
   if (mIsDestroyed) {
     return false;
   }
 
-  if (!mContentCache.OnCompositionEvent(event)) {
+  if (!mContentCache.OnCompositionEvent(aEvent)) {
     return true;
   }
-  return PBrowserParent::SendCompositionEvent(event);
+  return PBrowserParent::SendCompositionEvent(aEvent);
 }
 
 bool
-TabParent::SendSelectionEvent(WidgetSelectionEvent& event)
+TabParent::SendSelectionEvent(WidgetSelectionEvent& aEvent)
 {
   if (mIsDestroyed) {
     return false;
   }
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
     return true;
   }
-  mContentCache.OnSelectionEvent(event);
-  if (NS_WARN_IF(!PBrowserParent::SendSelectionEvent(event))) {
+  mContentCache.OnSelectionEvent(aEvent);
+  if (NS_WARN_IF(!PBrowserParent::SendSelectionEvent(aEvent))) {
     return false;
   }
-  event.mSucceeded = true;
+  aEvent.mSucceeded = true;
   return true;
 }
 
 bool
 TabParent::SendPasteTransferable(const IPCDataTransfer& aDataTransfer,
                                  const bool& aIsPrivateData,
                                  const IPC::Principal& aRequestingPrincipal)
 {
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -449,27 +449,27 @@ public:
   void SendMouseEvent(const nsAString& aType, float aX, float aY,
                       int32_t aButton, int32_t aClickCount,
                       int32_t aModifiers, bool aIgnoreRootScrollFrame);
 
   void SendKeyEvent(const nsAString& aType, int32_t aKeyCode,
                     int32_t aCharCode, int32_t aModifiers,
                     bool aPreventDefault);
 
-  bool SendRealMouseEvent(mozilla::WidgetMouseEvent& event);
+  bool SendRealMouseEvent(mozilla::WidgetMouseEvent& aEvent);
 
   bool SendRealDragEvent(mozilla::WidgetDragEvent& aEvent,
                          uint32_t aDragAction,
                          uint32_t aDropEffect);
 
-  bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& event);
+  bool SendMouseWheelEvent(mozilla::WidgetWheelEvent& aEvent);
 
-  bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& event);
+  bool SendRealKeyEvent(mozilla::WidgetKeyboardEvent& aEvent);
 
-  bool SendRealTouchEvent(WidgetTouchEvent& event);
+  bool SendRealTouchEvent(WidgetTouchEvent& aEvent);
 
   bool SendHandleTap(TapType aType,
                      const LayoutDevicePoint& aPoint,
                      Modifiers aModifiers,
                      const ScrollableLayerGuid& aGuid,
                      uint64_t aInputBlockId);
 
   virtual PDocumentRendererParent*
@@ -507,19 +507,19 @@ public:
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAUTHPROMPTPROVIDER
   NS_DECL_NSISECUREBROWSERUI
   NS_DECL_NSIWEBBROWSERPERSISTABLE
 
   bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
 
-  bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
+  bool SendCompositionEvent(mozilla::WidgetCompositionEvent& aEvent);
 
-  bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
+  bool SendSelectionEvent(mozilla::WidgetSelectionEvent& aEvent);
 
   bool SendPasteTransferable(const IPCDataTransfer& aDataTransfer,
                              const bool& aIsPrivateData,
                              const IPC::Principal& aRequestingPrincipal);
 
   static TabParent* GetFrom(nsFrameLoader* aFrameLoader);
 
   static TabParent* GetFrom(nsIFrameLoader* aFrameLoader);
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -3954,18 +3954,23 @@ var gCSSProperties = {
     initial_values: [ "normal" ],
     other_values: [ "pre", "nowrap", "pre-wrap", "pre-line", "-moz-pre-space" ],
     invalid_values: []
   },
   "width": {
     domProp: "width",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
-    /* computed value tests for width test more with display:block */
-    prerequisites: { "display": "block" },
+    prerequisites: {
+      // computed value tests for width test more with display:block
+      "display": "block",
+      // add some margin to avoid the initial "auto" value getting
+      // resolved to the same length as the parent element.
+      "margin-left": "5px",
+    },
     initial_values: [ " auto" ],
     /* XXX these have prerequisites */
     other_values: [ "15px", "3em", "15%",
       // these three keywords compute to the initial value only when the
       // writing mode is vertical, and we're testing with a horizontal
       // writing mode
       "-moz-max-content", "-moz-min-content", "-moz-fit-content",
       // whether -moz-available computes to the initial value depends on
@@ -5101,17 +5106,22 @@ var gCSSProperties = {
     domProp: "inlineSize",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     logical: true,
     axis: true,
     get_computed: logical_axis_prop_get_computed,
     /* XXX testing auto has prerequisites */
     initial_values: [ "auto" ],
-    prerequisites: { "display": "block" },
+    prerequisites: {
+      "display": "block",
+      // add some margin to avoid the initial "auto" value getting
+      // resolved to the same length as the parent element.
+      "margin-left": "5px",
+    },
     other_values: [ "15px", "3em", "15%",
       // these three keywords compute to the initial value only when the
       // writing mode is vertical, and we're testing with a horizontal
       // writing mode
       "-moz-max-content", "-moz-min-content", "-moz-fit-content",
       // whether -moz-available computes to the initial value depends on
       // the container size, and for the container size we're testing
       // with, it does
--- a/layout/style/test/test_inherit_computation.html
+++ b/layout/style/test/test_inherit_computation.html
@@ -17,16 +17,17 @@
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for computation of CSS 'inherit' on all properties and 'unset' on
     inherited properties **/
 
+var gDisplayTree = document.getElementById("display");
 // elements without a frame
 var gNParent = document.getElementById("nparent");
 var gNChild = document.getElementById("nchild");
 // elements with a frame
 var gFParent = document.getElementById("fparent");
 var gFChild = document.getElementById("fchild");
 
 var gStyleSheet = document.getElementById("stylesheet").sheet;
@@ -122,35 +123,53 @@ function test_property(property)
          property + "'");
       gParentRuleTop.style.removeProperty(property);
       gChildRule1.style.setProperty(property, info.other_values[0], "");
       var inherit_initial_computed_n = get_computed_value_node(gNChild, property);
       var inherit_initial_computed_f = get_computed_value_node(gFChild, property);
       is(inherit_initial_computed_n, initial_computed_n,
          keyword + " should cause inheritance of initial value for '" +
          property + "'");
-      is(inherit_initial_computed_f, initial_computed_f,
-         keyword + " should cause inheritance of initial value for '" +
-         property + "'");
+      // For width and inline-size, getComputedStyle returns used value
+      // when the element is displayed. Their initial value "auto" makes
+      // the element fill available space of the parent, so it doesn't
+      // make sense to compare it with the value we get before.
+      if (property != "width" && property != "inline-size") {
+        is(inherit_initial_computed_f, initial_computed_f,
+           keyword + " should cause inheritance of initial value for '" +
+           property + "'");
+      }
       gParentRuleTop.style.removeProperty(property);
       gChildRule1.style.removeProperty(property);
       gChildRule2.style.removeProperty(property);
     }
 
     if ("prerequisites" in info) {
       var prereqs = info.prerequisites;
       for (var prereq in prereqs) {
         gParentRuleTop.style.removeProperty(prereq);
         gChildRuleTop.style.removeProperty(prereq);
       }
     }
+
+    // FIXME -moz-binding value makes gElementF and its parent loses
+    // their frame. Force it to get recreated after each property.
+    // See bug 1331903.
+    gDisplayTree.style.display = "none";
+    get_computed_value(getComputedStyle(gFChild, ""), "width");
+    gDisplayTree.style.display = "";
+    get_computed_value(getComputedStyle(gFChild, ""), "width");
   });
 }
 
 for (var prop in gCSSProperties) {
+  // Skip -moz-binding because it effectively drops the frame.
+  if (prop == "-moz-binding") {
+    continue;
+  }
   var info = gCSSProperties[prop];
   gChildRule3.style.setProperty(prop, info.other_values[0], "");
 }
 
 for (var prop in gCSSProperties)
   test_property(prop);
 
 </script>
--- a/layout/style/test/test_initial_computation.html
+++ b/layout/style/test/test_initial_computation.html
@@ -41,16 +41,17 @@
 
 var gBrokenInitial = {
 };
 
 function xfail_initial(property) {
   return property in gBrokenInitial;
 }
 
+var gDisplayTree = document.getElementById("display");
 var gElementN = document.getElementById("elementn");
 var gElementF = document.getElementById("elementf");
 var gStyleSheet = document.getElementById("stylesheet").sheet;
 var gRule1 = gStyleSheet.cssRules[gStyleSheet.insertRule("#elementn, #elementf {}", gStyleSheet.cssRules.length)];
 var gRule2 = gStyleSheet.cssRules[gStyleSheet.insertRule("#elementn, #elementf {}", gStyleSheet.cssRules.length)];
 
 var gInitialValuesN;
 var gInitialValuesF;
@@ -131,23 +132,22 @@ function test_property(property)
         gInitialPrereqsRuleF.style.removeProperty(prereq);
       }
     }
     if (info.inherited) {
       gElementN.parentNode.style.removeProperty(property);
       gElementF.parentNode.style.removeProperty(property);
     }
 
-    // FIXME: Something (maybe with the -moz-binding values in
-    // test_value_computation.html, but may as well do it here to match)
-    // causes gElementF's frame to get lost.  Force it to get recreated
-    // after each property.
-    gElementF.parentNode.style.display = "none";
+    // FIXME -moz-binding value makes gElementF and its parent loses
+    // their frame. Force it to get recreated after each property.
+    // See bug 1331903.
+    gDisplayTree.style.display = "none";
     get_computed_value(getComputedStyle(gElementF, ""), "width");
-    gElementF.parentNode.style.display = "";
+    gDisplayTree.style.display = "";
     get_computed_value(getComputedStyle(gElementF, ""), "width");
   });
 }
 
 function run_tests() {
   setup_initial_values("unstyledn", "gInitialValuesN", "gInitialPrereqsRuleN");
   setup_initial_values("unstyledf", "gInitialValuesF", "gInitialPrereqsRuleF");
   for (var prop in gCSSProperties)
--- a/layout/style/test/test_value_computation.html
+++ b/layout/style/test/test_value_computation.html
@@ -99,16 +99,17 @@ var gSwapInitialWhenHaveFrame = {
   "width": [ "-moz-available" ],
 };
 
 function swap_when_frame(property, value) {
   return (property in gSwapInitialWhenHaveFrame) &&
          gSwapInitialWhenHaveFrame[property].indexOf(value) != -1;
 }
 
+var gDisplayTree = document.getElementById("display");
 var gElementN = document.getElementById("elementn");
 var gElementF = document.getElementById("elementf");
 var gStyleSheet = document.getElementById("stylesheet").sheet;
 var gRule1 = gStyleSheet.cssRules[gStyleSheet.insertRule("#elementn, #elementf {}", gStyleSheet.cssRules.length)];
 var gRule2 = gStyleSheet.cssRules[gStyleSheet.insertRule("#elementn, #elementf {}", gStyleSheet.cssRules.length)];
 
 var gInitialValuesN;
 var gInitialValuesF;
@@ -201,22 +202,22 @@ function test_value(property, val, is_in
       gInitialPrereqsRuleF.style.removeProperty(prereq);
     }
   }
   if (info.inherited && is_initial) {
     gElementN.parentNode.style.removeProperty(property);
     gElementF.parentNode.style.removeProperty(property);
   }
 
-  // FIXME: Something (maybe with the -moz-binding values) causes
-  // gElementF's frame to get lost.  Force it to get recreated after
-  // each property.
-  gElementF.parentNode.style.display = "none";
+  // FIXME -moz-binding value makes gElementF and its parent loses
+  // their frame. Force it to get recreated after each property.
+  // See bug 1331903.
+  gDisplayTree.style.display = "none";
   get_computed_value(getComputedStyle(gElementF, ""), "width");
-  gElementF.parentNode.style.display = "";
+  gDisplayTree.style.display = "";
   get_computed_value(getComputedStyle(gElementF, ""), "width");
 }
 
 function test_property(prop) {
   var info = gCSSProperties[prop];
   for (var idx in info.initial_values)
     test_value(prop, info.initial_values[idx], true);
   for (var idx in info.other_values)
--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -30,16 +30,18 @@
 struct FreeMP4Parser { void operator()(mp4parse_parser* aPtr) { mp4parse_free(aPtr); } };
 #endif
 
 using namespace stagefright;
 
 namespace mp4_demuxer
 {
 
+static LazyLogModule sLog("MP4Metadata");
+
 class DataSourceAdapter : public DataSource
 {
 public:
   explicit DataSourceAdapter(Stream* aSource) : mSource(aSource) {}
 
   ~DataSourceAdapter() {}
 
   virtual status_t initCheck() const { return NO_ERROR; }
@@ -192,18 +194,16 @@ TrackTypeToString(mozilla::TrackInfo::Tr
   default:
     return "unknown";
   }
 }
 
 uint32_t
 MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
 {
-  static LazyLogModule sLog("MP4Metadata");
-
   uint32_t numTracks = mStagefright->GetNumberTracks(aType);
 
 #ifdef MOZ_RUST_MP4PARSE
   if (!mRust) {
     return numTracks;
   }
 
   uint32_t numTracksRust = mRust->GetNumberTracks(aType);
@@ -611,17 +611,16 @@ MP4MetadataStagefright::Metadata(Stream*
   return parser->Metadata();
 }
 
 #ifdef MOZ_RUST_MP4PARSE
 bool
 RustStreamAdaptor::Read(uint8_t* buffer, uintptr_t size, size_t* bytes_read)
 {
   if (!mOffset.isValid()) {
-    static LazyLogModule sLog("MP4Metadata");
     MOZ_LOG(sLog, LogLevel::Error, ("Overflow in source stream offset"));
     return false;
   }
   bool rv = mSource->ReadAt(mOffset.value(), buffer, size, bytes_read);
   if (rv) {
     mOffset += *bytes_read;
   }
   return rv;
@@ -633,32 +632,34 @@ read_source(uint8_t* buffer, uintptr_t s
 {
   MOZ_ASSERT(buffer);
   MOZ_ASSERT(userdata);
 
   auto source = reinterpret_cast<RustStreamAdaptor*>(userdata);
   size_t bytes_read = 0;
   bool rv = source->Read(buffer, size, &bytes_read);
   if (!rv) {
-    static LazyLogModule sLog("MP4Metadata");
     MOZ_LOG(sLog, LogLevel::Warning, ("Error reading source data"));
     return -1;
   }
   return bytes_read;
 }
 
 MP4MetadataRust::MP4MetadataRust(Stream* aSource)
   : mSource(aSource)
   , mRustSource(aSource)
 {
   mp4parse_io io = { read_source, &mRustSource };
   mRustParser.reset(mp4parse_new(&io));
   MOZ_ASSERT(mRustParser);
 
-  static LazyLogModule sLog("MP4Metadata");
+  if (MOZ_LOG_TEST(sLog, LogLevel::Debug)) {
+    mp4parse_log(true);
+  }
+
   mp4parse_error rv = mp4parse_read(mRustParser.get());
   MOZ_LOG(sLog, LogLevel::Debug, ("rust parser returned %d\n", rv));
   Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_SUCCESS,
                         rv == MP4PARSE_OK);
   if (rv != MP4PARSE_OK) {
     MOZ_ASSERT(rv > 0);
     Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_ERROR_CODE, rv);
   }
@@ -696,18 +697,16 @@ TrackTypeEqual(TrackInfo::TrackType aLHS
   default:
     return false;
   }
 }
 
 uint32_t
 MP4MetadataRust::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
 {
-  static LazyLogModule sLog("MP4Metadata");
-
   uint32_t tracks;
   auto rv = mp4parse_get_track_count(mRustParser.get(), &tracks);
   if (rv != MP4PARSE_OK) {
     MOZ_LOG(sLog, LogLevel::Warning,
         ("rust parser error %d counting tracks", rv));
     return 0;
   }
   MOZ_LOG(sLog, LogLevel::Info, ("rust parser found %u tracks", tracks));
@@ -757,18 +756,16 @@ MP4MetadataRust::TrackTypeToGlobalTrackI
 
   return Nothing();
 }
 
 mozilla::UniquePtr<mozilla::TrackInfo>
 MP4MetadataRust::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
                               size_t aTrackNumber) const
 {
-  static LazyLogModule sLog("MP4Metadata");
-
   Maybe<uint32_t> trackIndex = TrackTypeToGlobalTrackIndex(aType, aTrackNumber);
   if (trackIndex.isNothing()) {
     return nullptr;
   }
 
   mp4parse_track_info info;
   auto rv = mp4parse_get_track_info(mRustParser.get(), trackIndex.value(), &info);
   if (rv != MP4PARSE_OK) {
--- a/memory/build/moz.build
+++ b/memory/build/moz.build
@@ -34,16 +34,22 @@ if CONFIG['MOZ_JEMALLOC4']:
         if not CONFIG['HAVE_INTTYPES_H']:
             LOCAL_INCLUDES += ['/memory/jemalloc/src/include/msvc_compat/C99']
 
 if CONFIG['MOZ_REPLACE_MALLOC']:
     SOURCES += [
         'replace_malloc.c',
     ]
 
+if CONFIG['OS_TARGET'] == 'Darwin' and (CONFIG['MOZ_REPLACE_MALLOC'] or
+        CONFIG['MOZ_MEMORY'] and not CONFIG['MOZ_JEMALLOC4']):
+    SOURCES += [
+        'zone.c',
+    ]
+
 Library('memory')
 
 if CONFIG['MOZ_GLUE_IN_PROGRAM']:
     SDK_LIBRARY = True
     DIST_INSTALL = True
 
 # Keep jemalloc separated when mozglue is statically linked
 if CONFIG['MOZ_MEMORY'] and (CONFIG['OS_TARGET'] in ('WINNT', 'Darwin', 'Android') or
--- a/memory/build/replace_malloc.c
+++ b/memory/build/replace_malloc.c
@@ -295,252 +295,8 @@ typedef void *(* __realloc_hook_type)(vo
 typedef void *(* __memalign_hook_type)(size_t alignment, size_t size);
 
 MOZ_MEMORY_API __free_hook_type __free_hook = free_impl;
 MOZ_MEMORY_API __malloc_hook_type __malloc_hook = malloc_impl;
 MOZ_MEMORY_API __realloc_hook_type __realloc_hook = realloc_impl;
 MOZ_MEMORY_API __memalign_hook_type __memalign_hook = memalign_impl;
 
 #endif
-
-/*
- * The following is a OSX zone allocator implementation.
- * /!\ WARNING. It assumes the underlying malloc implementation's
- * malloc_usable_size returns 0 when the given pointer is not owned by
- * the allocator. Sadly, OSX does call zone_size with pointers not
- * owned by the allocator.
- */
-
-#ifdef XP_DARWIN
-#include <stdlib.h>
-#include <malloc/malloc.h>
-#include "mozilla/Assertions.h"
-
-static size_t
-zone_size(malloc_zone_t *zone, void *ptr)
-{
-  return malloc_usable_size_impl(ptr);
-}
-
-static void *
-zone_malloc(malloc_zone_t *zone, size_t size)
-{
-  return malloc_impl(size);
-}
-
-static void *
-zone_calloc(malloc_zone_t *zone, size_t num, size_t size)
-{
-  return calloc_impl(num, size);
-}
-
-static void *
-zone_realloc(malloc_zone_t *zone, void *ptr, size_t size)
-{
-  if (malloc_usable_size_impl(ptr))
-    return realloc_impl(ptr, size);
-  return realloc(ptr, size);
-}
-
-static void
-zone_free(malloc_zone_t *zone, void *ptr)
-{
-  if (malloc_usable_size_impl(ptr)) {
-    free_impl(ptr);
-    return;
-  }
-  free(ptr);
-}
-
-static void
-zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
-{
-  size_t current_size = malloc_usable_size_impl(ptr);
-  if (current_size) {
-    MOZ_ASSERT(current_size == size);
-    free_impl(ptr);
-    return;
-  }
-  free(ptr);
-}
-
-static void *
-zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)
-{
-  void *ptr;
-  if (posix_memalign_impl(&ptr, alignment, size) == 0)
-    return ptr;
-  return NULL;
-}
-
-static void *
-zone_valloc(malloc_zone_t *zone, size_t size)
-{
-  return valloc_impl(size);
-}
-
-static void *
-zone_destroy(malloc_zone_t *zone)
-{
-  /* This function should never be called. */
-  MOZ_CRASH();
-}
-
-static size_t
-zone_good_size(malloc_zone_t *zone, size_t size)
-{
-  return malloc_good_size_impl(size);
-}
-
-#ifdef MOZ_JEMALLOC
-
-#include "jemalloc/internal/jemalloc_internal.h"
-
-static void
-zone_force_lock(malloc_zone_t *zone)
-{
-  /* /!\ This calls into jemalloc. It works because we're linked in the
-   * same library. Stolen from jemalloc's zone.c. */
-  if (isthreaded)
-    jemalloc_prefork();
-}
-
-static void
-zone_force_unlock(malloc_zone_t *zone)
-{
-  /* /!\ This calls into jemalloc. It works because we're linked in the
-   * same library. Stolen from jemalloc's zone.c. */
-  if (isthreaded)
-    jemalloc_postfork_parent();
-}
-
-#else
-
-#define JEMALLOC_ZONE_VERSION 6
-
-/* Empty implementations are needed, because fork() calls zone->force_(un)lock
- * unconditionally. */
-static void
-zone_force_lock(malloc_zone_t *zone)
-{
-}
-
-static void
-zone_force_unlock(malloc_zone_t *zone)
-{
-}
-
-#endif
-
-static malloc_zone_t zone;
-static struct malloc_introspection_t zone_introspect;
-
-static malloc_zone_t *get_default_zone()
-{
-  malloc_zone_t **zones = NULL;
-  unsigned int num_zones = 0;
-
-  /*
-   * On OSX 10.12, malloc_default_zone returns a special zone that is not
-   * present in the list of registered zones. That zone uses a "lite zone"
-   * if one is present (apparently enabled when malloc stack logging is
-   * enabled), or the first registered zone otherwise. In practice this
-   * means unless malloc stack logging is enabled, the first registered
-   * zone is the default.
-   * So get the list of zones to get the first one, instead of relying on
-   * malloc_default_zone.
-   */
-  if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, (vm_address_t**) &zones,
-                                           &num_zones)) {
-    /* Reset the value in case the failure happened after it was set. */
-    num_zones = 0;
-  }
-  if (num_zones) {
-    return zones[0];
-  }
-  return malloc_default_zone();
-}
-
-
-__attribute__((constructor)) void
-register_zone(void)
-{
-  malloc_zone_t *default_zone = get_default_zone();
-
-  zone.size = (void *)zone_size;
-  zone.malloc = (void *)zone_malloc;
-  zone.calloc = (void *)zone_calloc;
-  zone.valloc = (void *)zone_valloc;
-  zone.free = (void *)zone_free;
-  zone.realloc = (void *)zone_realloc;
-  zone.destroy = (void *)zone_destroy;
-  zone.zone_name = "replace_malloc_zone";
-  zone.batch_malloc = NULL;
-  zone.batch_free = NULL;
-  zone.introspect = &zone_introspect;
-  zone.version = JEMALLOC_ZONE_VERSION;
-  zone.memalign = zone_memalign;
-  zone.free_definite_size = zone_free_definite_size;
-#if (JEMALLOC_ZONE_VERSION >= 8)
-  zone.pressure_relief = NULL;
-#endif
-  zone_introspect.enumerator = NULL;
-  zone_introspect.good_size = (void *)zone_good_size;
-  zone_introspect.check = NULL;
-  zone_introspect.print = NULL;
-  zone_introspect.log = NULL;
-  zone_introspect.force_lock = (void *)zone_force_lock;
-  zone_introspect.force_unlock = (void *)zone_force_unlock;
-  zone_introspect.statistics = NULL;
-  zone_introspect.zone_locked = NULL;
-#if (JEMALLOC_ZONE_VERSION >= 7)
-  zone_introspect.enable_discharge_checking = NULL;
-  zone_introspect.disable_discharge_checking = NULL;
-  zone_introspect.discharge = NULL;
-#ifdef __BLOCKS__
-  zone_introspect.enumerate_discharged_pointers = NULL;
-#else
-  zone_introspect.enumerate_unavailable_without_blocks = NULL;
-#endif
-#endif
-
-  /*
-   * The default purgeable zone is created lazily by OSX's libc.  It uses
-   * the default zone when it is created for "small" allocations
-   * (< 15 KiB), but assumes the default zone is a scalable_zone.  This
-   * obviously fails when the default zone is the jemalloc zone, so
-   * malloc_default_purgeable_zone is called beforehand so that the
-   * default purgeable zone is created when the default zone is still
-   * a scalable_zone.
-   */
-  malloc_zone_t *purgeable_zone = malloc_default_purgeable_zone();
-
-  /* Register the custom zone.  At this point it won't be the default. */
-  malloc_zone_register(&zone);
-
-  do {
-    /*
-     * Unregister and reregister the default zone.  On OSX >= 10.6,
-     * unregistering takes the last registered zone and places it at the
-     * location of the specified zone.  Unregistering the default zone thus
-     * makes the last registered one the default.  On OSX < 10.6,
-     * unregistering shifts all registered zones.  The first registered zone
-     * then becomes the default.
-     */
-    malloc_zone_unregister(default_zone);
-    malloc_zone_register(default_zone);
-    /*
-     * On OSX 10.6, having the default purgeable zone appear before the default
-     * zone makes some things crash because it thinks it owns the default
-     * zone allocated pointers. We thus unregister/re-register it in order to
-     * ensure it's always after the default zone. On OSX < 10.6, as
-     * unregistering shifts registered zones, this simply removes the purgeable
-     * zone from the list and adds it back at the end, after the default zone.
-     * On OSX >= 10.6, unregistering replaces the purgeable zone with the last
-     * registered zone above, i.e the default zone. Registering it again then
-     * puts it at the end, obviously after the default zone.
-     */
-    malloc_zone_unregister(purgeable_zone);
-    malloc_zone_register(purgeable_zone);
-    default_zone = get_default_zone();
-  } while (default_zone != &zone);
-}
-#endif
copy from memory/build/replace_malloc.c
copy to memory/build/zone.c
--- a/memory/build/replace_malloc.c
+++ b/memory/build/zone.c
@@ -1,326 +1,115 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef MOZ_MEMORY
-#  error Should not compile this file when MOZ_MEMORY is not set
-#endif
-
-#ifndef MOZ_REPLACE_MALLOC
-#  error Should not compile this file when replace-malloc is disabled
-#endif
-
-#ifdef MOZ_SYSTEM_JEMALLOC
-#  error Should not compile this file when we want to use native jemalloc
-#endif
-
 #include "mozmemory_wrap.h"
 
-/* Declare all je_* functions */
-#define MALLOC_DECL(name, return_type, ...) \
-  return_type je_ ## name(__VA_ARGS__);
-#include "malloc_decls.h"
-
-#include "mozilla/Likely.h"
-
-/*
- * Windows doesn't come with weak imports as they are possible with
- * LD_PRELOAD or DYLD_INSERT_LIBRARIES on Linux/OSX. On this platform,
- * the replacement functions are defined as variable pointers to the
- * function resolved with GetProcAddress() instead of weak definitions
- * of functions. On Android, the same needs to happen as well, because
- * the Android linker doesn't handle weak linking with non LD_PRELOADed
- * libraries, but LD_PRELOADing is not very convenient on Android, with
- * the zygote.
- */
-#ifdef XP_DARWIN
-#  define MOZ_REPLACE_WEAK __attribute__((weak_import))
-#elif defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID)
-#  define MOZ_NO_REPLACE_FUNC_DECL
-#elif defined(__GNUC__)
-#  define MOZ_REPLACE_WEAK __attribute__((weak))
-#endif
-
-#include "replace_malloc.h"
-
-#define MALLOC_DECL(name, return_type, ...) \
-    je_ ## name,
-
-static const malloc_table_t malloc_table = {
-#include "malloc_decls.h"
-};
-
-#ifdef MOZ_NO_REPLACE_FUNC_DECL
-#  define MALLOC_DECL(name, return_type, ...) \
-    typedef return_type (replace_ ## name ## _impl_t)(__VA_ARGS__); \
-    replace_ ## name ## _impl_t *replace_ ## name = NULL;
-#  define MALLOC_FUNCS MALLOC_FUNCS_ALL
-#  include "malloc_decls.h"
-
-#  ifdef XP_WIN
-#    include <windows.h>
-static void
-replace_malloc_init_funcs()
-{
-  char replace_malloc_lib[1024];
-  if (GetEnvironmentVariableA("MOZ_REPLACE_MALLOC_LIB", (LPSTR)&replace_malloc_lib,
-                              sizeof(replace_malloc_lib)) > 0) {
-    HMODULE handle = LoadLibraryA(replace_malloc_lib);
-    if (handle) {
-#define MALLOC_DECL(name, ...) \
-  replace_ ## name = (replace_ ## name ## _impl_t *) GetProcAddress(handle, "replace_" # name);
-
-#  define MALLOC_FUNCS MALLOC_FUNCS_ALL
-#include "malloc_decls.h"
-    }
-  }
-}
-#  elif defined(MOZ_WIDGET_ANDROID)
-#    include <dlfcn.h>
-#    include <stdlib.h>
-static void
-replace_malloc_init_funcs()
-{
-  const char *replace_malloc_lib = getenv("MOZ_REPLACE_MALLOC_LIB");
-  if (replace_malloc_lib && *replace_malloc_lib) {
-    void *handle = dlopen(replace_malloc_lib, RTLD_LAZY);
-    if (handle) {
-#define MALLOC_DECL(name, ...) \
-  replace_ ## name = (replace_ ## name ## _impl_t *) dlsym(handle, "replace_" # name);
-
-#  define MALLOC_FUNCS MALLOC_FUNCS_ALL
-#include "malloc_decls.h"
-    }
-  }
-}
-#  else
-#    error No implementation for replace_malloc_init_funcs()
-#  endif
-
-#endif /* MOZ_NO_REPLACE_FUNC_DECL */
-
-/*
- * Below is the malloc implementation overriding jemalloc and calling the
- * replacement functions if they exist.
- */
+#include <stdlib.h>
+#include <mach/mach_types.h>
+#include "mozilla/Assertions.h"
 
 /*
  * Malloc implementation functions are MOZ_MEMORY_API, and jemalloc
  * specific functions MOZ_JEMALLOC_API; see mozmemory_wrap.h
  */
 #define MALLOC_DECL(name, return_type, ...) \
   MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
 #define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
 #include "malloc_decls.h"
 
 #define MALLOC_DECL(name, return_type, ...) \
   MOZ_JEMALLOC_API return_type name ## _impl(__VA_ARGS__);
 #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
 #include "malloc_decls.h"
 
-static int replace_malloc_initialized = 0;
-static void
-init()
-{
-#ifdef MOZ_NO_REPLACE_FUNC_DECL
-  replace_malloc_init_funcs();
-#endif
-  // Set this *before* calling replace_init, otherwise if replace_init calls
-  // malloc() we'll get an infinite loop.
-  replace_malloc_initialized = 1;
-  if (replace_init)
-    replace_init(&malloc_table);
-}
-
-MFBT_API struct ReplaceMallocBridge*
-get_bridge(void)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_get_bridge))
-    return NULL;
-  return replace_get_bridge();
-}
-
-void*
-malloc_impl(size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_malloc))
-    return je_malloc(size);
-  return replace_malloc(size);
-}
+/*
+ * Definitions of the following structs in malloc/malloc.h might be too old
+ * for the built binary to run on newer versions of OSX. So use the newest
+ * possible version of those structs.
+ */
+typedef struct _malloc_zone_t {
+  void *reserved1;
+  void *reserved2;
+  size_t (*size)(struct _malloc_zone_t *, const void *);
+  void *(*malloc)(struct _malloc_zone_t *, size_t);
+  void *(*calloc)(struct _malloc_zone_t *, size_t, size_t);
+  void *(*valloc)(struct _malloc_zone_t *, size_t);
+  void (*free)(struct _malloc_zone_t *, void *);
+  void *(*realloc)(struct _malloc_zone_t *, void *, size_t);
+  void (*destroy)(struct _malloc_zone_t *);
+  const char *zone_name;
+  unsigned (*batch_malloc)(struct _malloc_zone_t *, size_t, void **, unsigned);
+  void (*batch_free)(struct _malloc_zone_t *, void **, unsigned);
+  struct malloc_introspection_t *introspect;
+  unsigned version;
+  void *(*memalign)(struct _malloc_zone_t *, size_t, size_t);
+  void (*free_definite_size)(struct _malloc_zone_t *, void *, size_t);
+  size_t (*pressure_relief)(struct _malloc_zone_t *, size_t);
+} malloc_zone_t;
 
-int
-posix_memalign_impl(void **memptr, size_t alignment, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_posix_memalign))
-    return je_posix_memalign(memptr, alignment, size);
-  return replace_posix_memalign(memptr, alignment, size);
-}
-
-void*
-aligned_alloc_impl(size_t alignment, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_aligned_alloc))
-    return je_aligned_alloc(alignment, size);
-  return replace_aligned_alloc(alignment, size);
-}
-
-void*
-calloc_impl(size_t num, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_calloc))
-    return je_calloc(num, size);
-  return replace_calloc(num, size);
-}
-
-void*
-realloc_impl(void *ptr, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_realloc))
-    return je_realloc(ptr, size);
-  return replace_realloc(ptr, size);
-}
-
-void
-free_impl(void *ptr)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_free))
-    je_free(ptr);
-  else
-    replace_free(ptr);
-}
+typedef struct {
+  vm_address_t address;
+  vm_size_t size;
+} vm_range_t;
 
-void*
-memalign_impl(size_t alignment, size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_memalign))
-    return je_memalign(alignment, size);
-  return replace_memalign(alignment, size);
-}
-
-void*
-valloc_impl(size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_valloc))
-    return je_valloc(size);
-  return replace_valloc(size);
-}
+typedef struct malloc_statistics_t {
+  unsigned blocks_in_use;
+  size_t size_in_use;
+  size_t max_size_in_use;
+  size_t size_allocated;
+} malloc_statistics_t;
 
-size_t
-malloc_usable_size_impl(usable_ptr_t ptr)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_malloc_usable_size))
-    return je_malloc_usable_size(ptr);
-  return replace_malloc_usable_size(ptr);
-}
+typedef kern_return_t memory_reader_t(task_t, vm_address_t, vm_size_t, void **);
 
-size_t
-malloc_good_size_impl(size_t size)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_malloc_good_size))
-    return je_malloc_good_size(size);
-  return replace_malloc_good_size(size);
-}
+typedef void vm_range_recorder_t(task_t, void *, unsigned type, vm_range_t *, unsigned);
 
-void
-jemalloc_stats_impl(jemalloc_stats_t *stats)
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_jemalloc_stats))
-    je_jemalloc_stats(stats);
-  else
-    replace_jemalloc_stats(stats);
-}
-
-void
-jemalloc_purge_freed_pages_impl()
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_jemalloc_purge_freed_pages))
-    je_jemalloc_purge_freed_pages();
-  else
-    replace_jemalloc_purge_freed_pages();
-}
+typedef struct malloc_introspection_t {
+  kern_return_t (*enumerator)(task_t, void *, unsigned, vm_address_t, memory_reader_t, vm_range_recorder_t);
+  size_t (*good_size)(malloc_zone_t *, size_t);
+  boolean_t (*check)(malloc_zone_t *);
+  void (*print)(malloc_zone_t *, boolean_t);
+  void (*log)(malloc_zone_t *, void *);
+  void (*force_lock)(malloc_zone_t *);
+  void (*force_unlock)(malloc_zone_t *);
+  void (*statistics)(malloc_zone_t *, malloc_statistics_t *);
+  boolean_t (*zone_locked)(malloc_zone_t *);
+  boolean_t (*enable_discharge_checking)(malloc_zone_t *);
+  boolean_t (*disable_discharge_checking)(malloc_zone_t *);
+  void (*discharge)(malloc_zone_t *, void *);
+#ifdef __BLOCKS__
+  void (*enumerate_discharged_pointers)(malloc_zone_t *, void (^)(void *, void *));
+#else
+  void *enumerate_unavailable_without_blocks;
+#endif
+  void (*reinit_lock)(malloc_zone_t *);
+} malloc_introspection_t;
 
-void
-jemalloc_free_dirty_pages_impl()
-{
-  if (MOZ_UNLIKELY(!replace_malloc_initialized))
-    init();
-  if (MOZ_LIKELY(!replace_jemalloc_free_dirty_pages))
-    je_jemalloc_free_dirty_pages();
-  else
-    replace_jemalloc_free_dirty_pages();
-}
+extern kern_return_t malloc_get_all_zones(task_t, memory_reader_t, vm_address_t **, unsigned *);
 
-/* The following comment and definitions are from jemalloc.c: */
-#if defined(__GLIBC__) && !defined(__UCLIBC__)
+extern malloc_zone_t *malloc_default_zone(void);
 
-/*
- * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
- * to inconsistently reference libc's malloc(3)-compatible functions
- * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
- *
- * These definitions interpose hooks in glibc.  The functions are actually
- * passed an extra argument for the caller return address, which will be
- * ignored.
- */
+extern void malloc_zone_register(malloc_zone_t *zone);
 
-typedef void (* __free_hook_type)(void *ptr);
-typedef void *(* __malloc_hook_type)(size_t size);
-typedef void *(* __realloc_hook_type)(void *ptr, size_t size);
-typedef void *(* __memalign_hook_type)(size_t alignment, size_t size);
+extern void malloc_zone_unregister(malloc_zone_t *zone);
 
-MOZ_MEMORY_API __free_hook_type __free_hook = free_impl;
-MOZ_MEMORY_API __malloc_hook_type __malloc_hook = malloc_impl;
-MOZ_MEMORY_API __realloc_hook_type __realloc_hook = realloc_impl;
-MOZ_MEMORY_API __memalign_hook_type __memalign_hook = memalign_impl;
+extern malloc_zone_t *malloc_default_purgeable_zone(void);
 
-#endif
 
 /*
  * The following is a OSX zone allocator implementation.
  * /!\ WARNING. It assumes the underlying malloc implementation's
  * malloc_usable_size returns 0 when the given pointer is not owned by
  * the allocator. Sadly, OSX does call zone_size with pointers not
  * owned by the allocator.
  */
 
-#ifdef XP_DARWIN
-#include <stdlib.h>
-#include <malloc/malloc.h>
-#include "mozilla/Assertions.h"
-
 static size_t
-zone_size(malloc_zone_t *zone, void *ptr)
+zone_size(malloc_zone_t *zone, const void *ptr)
 {
   return malloc_usable_size_impl(ptr);
 }
 
 static void *
 zone_malloc(malloc_zone_t *zone, size_t size)
 {
   return malloc_impl(size);
@@ -372,29 +161,86 @@ zone_memalign(malloc_zone_t *zone, size_
 }
 
 static void *
 zone_valloc(malloc_zone_t *zone, size_t size)
 {
   return valloc_impl(size);
 }
 
-static void *
+static void
 zone_destroy(malloc_zone_t *zone)
 {
   /* This function should never be called. */
   MOZ_CRASH();
 }
 
+static unsigned
+zone_batch_malloc(malloc_zone_t *zone, size_t size, void **results,
+    unsigned num_requested)
+{
+  unsigned i;
+
+  for (i = 0; i < num_requested; i++) {
+    results[i] = malloc_impl(size);
+    if (!results[i])
+      break;
+  }
+
+  return i;
+}
+
+static void
+zone_batch_free(malloc_zone_t *zone, void **to_be_freed,
+    unsigned num_to_be_freed)
+{
+  unsigned i;
+
+  for (i = 0; i < num_to_be_freed; i++) {
+    zone_free(zone, to_be_freed[i]);
+    to_be_freed[i] = NULL;
+  }
+}
+
+static size_t
+zone_pressure_relief(malloc_zone_t *zone, size_t goal)
+{
+  return 0;
+}
+
 static size_t
 zone_good_size(malloc_zone_t *zone, size_t size)
 {
   return malloc_good_size_impl(size);
 }
 
+static kern_return_t
+zone_enumerator(task_t task, void *data, unsigned type_mask,
+    vm_address_t zone_address, memory_reader_t reader,
+    vm_range_recorder_t recorder)
+{
+  return KERN_SUCCESS;
+}
+
+static boolean_t
+zone_check(malloc_zone_t *zone)
+{
+  return true;
+}
+
+static void
+zone_print(malloc_zone_t *zone, boolean_t verbose)
+{
+}
+
+static void
+zone_log(malloc_zone_t *zone, void *address)
+{
+}
+
 #ifdef MOZ_JEMALLOC
 
 #include "jemalloc/internal/jemalloc_internal.h"
 
 static void
 zone_force_lock(malloc_zone_t *zone)
 {
   /* /!\ This calls into jemalloc. It works because we're linked in the
@@ -402,39 +248,69 @@ zone_force_lock(malloc_zone_t *zone)
   if (isthreaded)
     jemalloc_prefork();
 }
 
 static void
 zone_force_unlock(malloc_zone_t *zone)
 {
   /* /!\ This calls into jemalloc. It works because we're linked in the
-   * same library. Stolen from jemalloc's zone.c. */
+   * same library. Stolen from jemalloc's zone.c. See the comment there. */
   if (isthreaded)
-    jemalloc_postfork_parent();
+    jemalloc_postfork_child();
 }
 
 #else
 
-#define JEMALLOC_ZONE_VERSION 6
+extern void _malloc_prefork(void);
+extern void _malloc_postfork_child(void);
 
-/* Empty implementations are needed, because fork() calls zone->force_(un)lock
- * unconditionally. */
 static void
 zone_force_lock(malloc_zone_t *zone)
 {
+  /* /!\ This calls into mozjemalloc. It works because we're linked in the
+   * same library. */
+  _malloc_prefork();
 }
 
 static void
 zone_force_unlock(malloc_zone_t *zone)
 {
+  /* /!\ This calls into mozjemalloc. It works because we're linked in the
+   * same library. */
+  _malloc_postfork_child();
 }
 
 #endif
 
+static void
+zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats)
+{
+  /* We make no effort to actually fill the values */
+  stats->blocks_in_use = 0;
+  stats->size_in_use = 0;
+  stats->max_size_in_use = 0;
+  stats->size_allocated = 0;
+}
+
+static boolean_t
+zone_locked(malloc_zone_t *zone)
+{
+  /* Pretend no lock is being held */
+  return false;
+}
+
+static void
+zone_reinit_lock(malloc_zone_t *zone)
+{
+  /* As of OSX 10.12, this function is only used when force_unlock would
+   * be used if the zone version were < 9. So just use force_unlock. */
+  zone_force_unlock(zone);
+}
+
 static malloc_zone_t zone;
 static struct malloc_introspection_t zone_introspect;
 
 static malloc_zone_t *get_default_zone()
 {
   malloc_zone_t **zones = NULL;
   unsigned int num_zones = 0;
 
@@ -455,57 +331,61 @@ static malloc_zone_t *get_default_zone()
   }
   if (num_zones) {
     return zones[0];
   }
   return malloc_default_zone();
 }
 
 
-__attribute__((constructor)) void
+#ifdef MOZ_REPLACE_MALLOC
+__attribute__((constructor))
+#endif
+void
 register_zone(void)
 {
   malloc_zone_t *default_zone = get_default_zone();
 
-  zone.size = (void *)zone_size;
-  zone.malloc = (void *)zone_malloc;
-  zone.calloc = (void *)zone_calloc;
-  zone.valloc = (void *)zone_valloc;
-  zone.free = (void *)zone_free;
-  zone.realloc = (void *)zone_realloc;
-  zone.destroy = (void *)zone_destroy;
+  zone.size = zone_size;
+  zone.malloc = zone_malloc;
+  zone.calloc = zone_calloc;
+  zone.valloc = zone_valloc;
+  zone.free = zone_free;
+  zone.realloc = zone_realloc;
+  zone.destroy = zone_destroy;
+#ifdef MOZ_REPLACE_MALLOC
   zone.zone_name = "replace_malloc_zone";
-  zone.batch_malloc = NULL;
-  zone.batch_free = NULL;
+#else
+  zone.zone_name = "jemalloc_zone";
+#endif
+  zone.batch_malloc = zone_batch_malloc;
+  zone.batch_free = zone_batch_free;
   zone.introspect = &zone_introspect;
-  zone.version = JEMALLOC_ZONE_VERSION;
+  zone.version = 9;
   zone.memalign = zone_memalign;
   zone.free_definite_size = zone_free_definite_size;
-#if (JEMALLOC_ZONE_VERSION >= 8)
-  zone.pressure_relief = NULL;
-#endif
-  zone_introspect.enumerator = NULL;
-  zone_introspect.good_size = (void *)zone_good_size;
-  zone_introspect.check = NULL;
-  zone_introspect.print = NULL;
-  zone_introspect.log = NULL;
-  zone_introspect.force_lock = (void *)zone_force_lock;
-  zone_introspect.force_unlock = (void *)zone_force_unlock;
-  zone_introspect.statistics = NULL;
-  zone_introspect.zone_locked = NULL;
-#if (JEMALLOC_ZONE_VERSION >= 7)
+  zone.pressure_relief = zone_pressure_relief;
+  zone_introspect.enumerator = zone_enumerator;
+  zone_introspect.good_size = zone_good_size;
+  zone_introspect.check = zone_check;
+  zone_introspect.print = zone_print;
+  zone_introspect.log = zone_log;
+  zone_introspect.force_lock = zone_force_lock;
+  zone_introspect.force_unlock = zone_force_unlock;
+  zone_introspect.statistics = zone_statistics;
+  zone_introspect.zone_locked = zone_locked;
   zone_introspect.enable_discharge_checking = NULL;
   zone_introspect.disable_discharge_checking = NULL;
   zone_introspect.discharge = NULL;
 #ifdef __BLOCKS__
   zone_introspect.enumerate_discharged_pointers = NULL;
 #else
   zone_introspect.enumerate_unavailable_without_blocks = NULL;
 #endif
-#endif
+  zone_introspect.reinit_lock = zone_reinit_lock;
 
   /*
    * The default purgeable zone is created lazily by OSX's libc.  It uses
    * the default zone when it is created for "small" allocations
    * (< 15 KiB), but assumes the default zone is a scalable_zone.  This
    * obviously fails when the default zone is the jemalloc zone, so
    * malloc_default_purgeable_zone is called beforehand so that the
    * default purgeable zone is created when the default zone is still
@@ -538,9 +418,8 @@ register_zone(void)
      * registered zone above, i.e the default zone. Registering it again then
      * puts it at the end, obviously after the default zone.
      */
     malloc_zone_unregister(purgeable_zone);
     malloc_zone_register(purgeable_zone);
     default_zone = get_default_zone();
   } while (default_zone != &zone);
 }
-#endif
--- a/memory/jemalloc/src/VERSION
+++ b/memory/jemalloc/src/VERSION
@@ -1,1 +1,1 @@
-4.4.0-0-gf1f76357313e7dcad7262f17a48ff0a2e005fcdc
+4.4.0-3-gc6943acb3c56d1b3d1e82dd43b3fcfeae7771990
--- a/memory/jemalloc/src/configure
+++ b/memory/jemalloc/src/configure
@@ -9002,166 +9002,16 @@ fi
 
 
 if test "x${enable_zone_allocator}" = "x1" ; then
   if test "x${abi}" != "xmacho"; then
     as_fn_error $? "--enable-zone-allocator is only supported on Darwin" "$LINENO" 5
   fi
   $as_echo "#define JEMALLOC_ZONE  " >>confdefs.h
 
-
-        { $as_echo "$as_me:${as_lineno-$LINENO}: checking malloc zone version" >&5
-$as_echo_n "checking malloc zone version... " >&6; }
-
-
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <malloc/malloc.h>
-int
-main ()
-{
-static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 14 ? 1 : -1]
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  JEMALLOC_ZONE_VERSION=3
-else
-
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <malloc/malloc.h>
-int
-main ()
-{
-static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 15 ? 1 : -1]
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  JEMALLOC_ZONE_VERSION=5
-else
-
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <malloc/malloc.h>
-int
-main ()
-{
-static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 16 ? 1 : -1]
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <malloc/malloc.h>
-int
-main ()
-{
-static int foo[sizeof(malloc_introspection_t) == sizeof(void *) * 9 ? 1 : -1]
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  JEMALLOC_ZONE_VERSION=6
-else
-
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <malloc/malloc.h>
-int
-main ()
-{
-static int foo[sizeof(malloc_introspection_t) == sizeof(void *) * 13 ? 1 : -1]
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  JEMALLOC_ZONE_VERSION=7
-else
-  JEMALLOC_ZONE_VERSION=
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
-
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <malloc/malloc.h>
-int
-main ()
-{
-static int foo[sizeof(malloc_zone_t) == sizeof(void *) * 17 ? 1 : -1]
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  JEMALLOC_ZONE_VERSION=8
-else
-
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <malloc/malloc.h>
-int
-main ()
-{
-static int foo[sizeof(malloc_zone_t) > sizeof(void *) * 17 ? 1 : -1]
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  JEMALLOC_ZONE_VERSION=9
-else
-  JEMALLOC_ZONE_VERSION=
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-  if test "x${JEMALLOC_ZONE_VERSION}" = "x"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; }
-    as_fn_error $? "Unsupported malloc zone version" "$LINENO" 5
-  fi
-  if test "${JEMALLOC_ZONE_VERSION}" = 9; then
-    JEMALLOC_ZONE_VERSION=8
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: > 8" >&5
-$as_echo "> 8" >&6; }
-  else
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JEMALLOC_ZONE_VERSION" >&5
-$as_echo "$JEMALLOC_ZONE_VERSION" >&6; }
-  fi
-  cat >>confdefs.h <<_ACEOF
-#define JEMALLOC_ZONE_VERSION $JEMALLOC_ZONE_VERSION
-_ACEOF
-
 fi
 
 
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether glibc malloc hook is compilable" >&5
 $as_echo_n "checking whether glibc malloc hook is compilable... " >&6; }
 if ${je_cv_glibc_malloc_hook+:} false; then :
   $as_echo_n "(cached) " >&6
--- a/memory/jemalloc/src/configure.ac
+++ b/memory/jemalloc/src/configure.ac
@@ -1769,47 +1769,16 @@ fi
 )
 AC_SUBST([enable_zone_allocator])
 
 if test "x${enable_zone_allocator}" = "x1" ; then
   if test "x${abi}" != "xmacho"; then
     AC_MSG_ERROR([--enable-zone-allocator is only supported on Darwin])
   fi
   AC_DEFINE([JEMALLOC_ZONE], [ ])
-
-  dnl The szone version jumped from 3 to 6 between the OS X 10.5.x and 10.6
-  dnl releases.  malloc_zone_t and malloc_introspection_t have new fields in
-  dnl 10.6, which is the only source-level indication of the change.
-  AC_MSG_CHECKING([malloc zone version])
-  AC_DEFUN([JE_ZONE_PROGRAM],
-    [AC_LANG_PROGRAM(
-      [#include <malloc/malloc.h>],
-      [static int foo[[sizeof($1) $2 sizeof(void *) * $3 ? 1 : -1]]]
-    )])
-
-  AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,14)],[JEMALLOC_ZONE_VERSION=3],[
-  AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,15)],[JEMALLOC_ZONE_VERSION=5],[
-  AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,16)],[
-    AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_introspection_t,==,9)],[JEMALLOC_ZONE_VERSION=6],[
-    AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_introspection_t,==,13)],[JEMALLOC_ZONE_VERSION=7],[JEMALLOC_ZONE_VERSION=]
-  )])],[
-  AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,17)],[JEMALLOC_ZONE_VERSION=8],[
-  AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,>,17)],[JEMALLOC_ZONE_VERSION=9],[JEMALLOC_ZONE_VERSION=]
-  )])])])])
-  if test "x${JEMALLOC_ZONE_VERSION}" = "x"; then
-    AC_MSG_RESULT([unsupported])
-    AC_MSG_ERROR([Unsupported malloc zone version])
-  fi
-  if test "${JEMALLOC_ZONE_VERSION}" = 9; then
-    JEMALLOC_ZONE_VERSION=8
-    AC_MSG_RESULT([> 8])
-  else
-    AC_MSG_RESULT([$JEMALLOC_ZONE_VERSION])
-  fi
-  AC_DEFINE_UNQUOTED(JEMALLOC_ZONE_VERSION, [$JEMALLOC_ZONE_VERSION])
 fi
 
 dnl ============================================================================
 dnl Check for glibc malloc hooks
 
 JE_COMPILABLE([glibc malloc hook], [
 #include <stddef.h>
 
--- a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in
+++ b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal.h.in
@@ -153,17 +153,16 @@ static const bool config_cache_oblivious
 #if (defined(JEMALLOC_OSATOMIC) || defined(JEMALLOC_OSSPIN))
 #include <libkern/OSAtomic.h>
 #endif
 
 #ifdef JEMALLOC_ZONE
 #include <mach/mach_error.h>
 #include <mach/mach_init.h>
 #include <mach/vm_map.h>
-#include <malloc/malloc.h>
 #endif
 
 #include "jemalloc/internal/ph.h"
 #ifndef __PGI
 #define	RB_COMPACT
 #endif
 #include "jemalloc/internal/rb.h"
 #include "jemalloc/internal/qr.h"
--- a/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in
+++ b/memory/jemalloc/src/include/jemalloc/internal/jemalloc_internal_defs.h.in
@@ -234,17 +234,16 @@
  * pointer alignments across all cache indices.
  */
 #undef JEMALLOC_CACHE_OBLIVIOUS
 
 /*
  * Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings.
  */
 #undef JEMALLOC_ZONE
-#undef JEMALLOC_ZONE_VERSION
 
 /*
  * Methods for determining whether the OS overcommits.
  * JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY: Linux's
  *                                         /proc/sys/vm.overcommit_memory file.
  * JEMALLOC_SYSCTL_VM_OVERCOMMIT: FreeBSD's vm.overcommit sysctl.
  */
 #undef JEMALLOC_SYSCTL_VM_OVERCOMMIT
--- a/memory/jemalloc/src/include/jemalloc/internal/mb.h
+++ b/memory/jemalloc/src/include/jemalloc/internal/mb.h
@@ -71,17 +71,17 @@ mb_write(void)
 {
 
 	asm volatile ("eieio"
 	    : /* Outputs. */
 	    : /* Inputs. */
 	    : "memory" /* Clobbers. */
 	    );
 }
-#elif defined(__sparc64__)
+#elif defined(__sparc__) && defined(__arch64__)
 JEMALLOC_INLINE void
 mb_write(void)
 {
 
 	asm volatile ("membar #StoreStore"
 	    : /* Outputs. */
 	    : /* Inputs. */
 	    : "memory" /* Clobbers. */
--- a/memory/jemalloc/src/src/zone.c
+++ b/memory/jemalloc/src/src/zone.c
@@ -1,13 +1,82 @@
 #include "jemalloc/internal/jemalloc_internal.h"
 #ifndef JEMALLOC_ZONE
 #  error "This source file is for zones on Darwin (OS X)."
 #endif
 
+/* Definitions of the following structs in malloc/malloc.h might be too old
+ * for the built binary to run on newer versions of OSX. So use the newest
+ * possible version of those structs.
+ */
+typedef struct _malloc_zone_t {
+	void *reserved1;
+	void *reserved2;
+	size_t (*size)(struct _malloc_zone_t *, const void *);
+	void *(*malloc)(struct _malloc_zone_t *, size_t);
+	void *(*calloc)(struct _malloc_zone_t *, size_t, size_t);
+	void *(*valloc)(struct _malloc_zone_t *, size_t);
+	void (*free)(struct _malloc_zone_t *, void *);
+	void *(*realloc)(struct _malloc_zone_t *, void *, size_t);
+	void (*destroy)(struct _malloc_zone_t *);
+	const char *zone_name;
+	unsigned (*batch_malloc)(struct _malloc_zone_t *, size_t, void **, unsigned);
+	void (*batch_free)(struct _malloc_zone_t *, void **, unsigned);
+	struct malloc_introspection_t *introspect;
+	unsigned version;
+	void *(*memalign)(struct _malloc_zone_t *, size_t, size_t);
+	void (*free_definite_size)(struct _malloc_zone_t *, void *, size_t);
+	size_t (*pressure_relief)(struct _malloc_zone_t *, size_t);
+} malloc_zone_t;
+
+typedef struct {
+	vm_address_t address;
+	vm_size_t size;
+} vm_range_t;
+
+typedef struct malloc_statistics_t {
+	unsigned blocks_in_use;
+	size_t size_in_use;
+	size_t max_size_in_use;
+	size_t size_allocated;
+} malloc_statistics_t;
+
+typedef kern_return_t memory_reader_t(task_t, vm_address_t, vm_size_t, void **);
+
+typedef void vm_range_recorder_t(task_t, void *, unsigned type, vm_range_t *, unsigned);
+
+typedef struct malloc_introspection_t {
+	kern_return_t (*enumerator)(task_t, void *, unsigned, vm_address_t, memory_reader_t, vm_range_recorder_t);
+	size_t (*good_size)(malloc_zone_t *, size_t);
+	boolean_t (*check)(malloc_zone_t *);
+	void (*print)(malloc_zone_t *, boolean_t);
+	void (*log)(malloc_zone_t *, void *);
+	void (*force_lock)(malloc_zone_t *);
+	void (*force_unlock)(malloc_zone_t *);
+	void (*statistics)(malloc_zone_t *, malloc_statistics_t *);
+	boolean_t (*zone_locked)(malloc_zone_t *);
+	boolean_t (*enable_discharge_checking)(malloc_zone_t *);
+	boolean_t (*disable_discharge_checking)(malloc_zone_t *);
+	void (*discharge)(malloc_zone_t *, void *);
+#ifdef __BLOCKS__
+	void (*enumerate_discharged_pointers)(malloc_zone_t *, void (^)(void *, void *));
+#else
+	void *enumerate_unavailable_without_blocks;
+#endif
+	void (*reinit_lock)(malloc_zone_t *);
+} malloc_introspection_t;
+
+extern kern_return_t malloc_get_all_zones(task_t, memory_reader_t, vm_address_t **, unsigned *);
+
+extern malloc_zone_t *malloc_default_zone(void);
+
+extern void malloc_zone_register(malloc_zone_t *zone);
+
+extern void malloc_zone_unregister(malloc_zone_t *zone);
+
 /*
  * The malloc_default_purgeable_zone() function is only available on >= 10.6.
  * We need to check whether it is present at runtime, thus the weak_import.
  */
 extern malloc_zone_t *malloc_default_purgeable_zone(void)
 JEMALLOC_ATTR(weak_import);
 
 /******************************************************************************/
@@ -15,42 +84,53 @@ JEMALLOC_ATTR(weak_import);
 
 static malloc_zone_t *default_zone, *purgeable_zone;
 static malloc_zone_t jemalloc_zone;
 static struct malloc_introspection_t jemalloc_zone_introspect;
 
 /******************************************************************************/
 /* Function prototypes for non-inline static functions. */
 
-static size_t	zone_size(malloc_zone_t *zone, void *ptr);
+static size_t	zone_size(malloc_zone_t *zone, const void *ptr);
 static void	*zone_malloc(malloc_zone_t *zone, size_t size);
 static void	*zone_calloc(malloc_zone_t *zone, size_t num, size_t size);
 static void	*zone_valloc(malloc_zone_t *zone, size_t size);
 static void	zone_free(malloc_zone_t *zone, void *ptr);
 static void	*zone_realloc(malloc_zone_t *zone, void *ptr, size_t size);
-#if (JEMALLOC_ZONE_VERSION >= 5)
 static void	*zone_memalign(malloc_zone_t *zone, size_t alignment,
-#endif
-#if (JEMALLOC_ZONE_VERSION >= 6)
     size_t size);
 static void	zone_free_definite_size(malloc_zone_t *zone, void *ptr,
     size_t size);
-#endif
-static void	*zone_destroy(malloc_zone_t *zone);
+static void	zone_destroy(malloc_zone_t *zone);
+static unsigned	zone_batch_malloc(struct _malloc_zone_t *zone, size_t size,
+    void **results, unsigned num_requested);
+static void	zone_batch_free(struct _malloc_zone_t *zone,
+    void **to_be_freed, unsigned num_to_be_freed);
+static size_t	zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal);
 static size_t	zone_good_size(malloc_zone_t *zone, size_t size);
+static kern_return_t	zone_enumerator(task_t task, void *data, unsigned type_mask,
+    vm_address_t zone_address, memory_reader_t reader,
+    vm_range_recorder_t recorder);
+static boolean_t	zone_check(malloc_zone_t *zone);
+static void	zone_print(malloc_zone_t *zone, boolean_t verbose);
+static void	zone_log(malloc_zone_t *zone, void *address);
 static void	zone_force_lock(malloc_zone_t *zone);
 static void	zone_force_unlock(malloc_zone_t *zone);
+static void	zone_statistics(malloc_zone_t *zone,
+    malloc_statistics_t *stats);
+static boolean_t	zone_locked(malloc_zone_t *zone);
+static void	zone_reinit_lock(malloc_zone_t *zone);
 
 /******************************************************************************/
 /*
  * Functions.
  */
 
 static size_t
-zone_size(malloc_zone_t *zone, void *ptr)
+zone_size(malloc_zone_t *zone, const void *ptr)
 {
 
 	/*
 	 * There appear to be places within Darwin (such as setenv(3)) that
 	 * cause calls to this function with pointers that *no* zone owns.  If
 	 * we knew that all pointers were owned by *some* zone, we could split
 	 * our zone into two parts, and use one as the default allocator and
 	 * the other as the default deallocator/reallocator.  Since that will
@@ -101,63 +181,115 @@ zone_realloc(malloc_zone_t *zone, void *
 {
 
 	if (ivsalloc(tsdn_fetch(), ptr, config_prof) != 0)
 		return (je_realloc(ptr, size));
 
 	return (realloc(ptr, size));
 }
 
-#if (JEMALLOC_ZONE_VERSION >= 5)
 static void *
 zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)
 {
 	void *ret = NULL; /* Assignment avoids useless compiler warning. */
 
 	je_posix_memalign(&ret, alignment, size);
 
 	return (ret);
 }
-#endif
 
-#if (JEMALLOC_ZONE_VERSION >= 6)
 static void
 zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
 {
 	size_t alloc_size;
 
 	alloc_size = ivsalloc(tsdn_fetch(), ptr, config_prof);
 	if (alloc_size != 0) {
 		assert(alloc_size == size);
 		je_free(ptr);
 		return;
 	}
 
 	free(ptr);
 }
-#endif
 
-static void *
+static void
 zone_destroy(malloc_zone_t *zone)
 {
 
 	/* This function should never be called. */
 	not_reached();
-	return (NULL);
+}
+
+static unsigned
+zone_batch_malloc(struct _malloc_zone_t *zone, size_t size, void **results,
+    unsigned num_requested)
+{
+	unsigned i;
+
+	for (i = 0; i < num_requested; i++) {
+		results[i] = je_malloc(size);
+		if (!results[i])
+			break;
+	}
+
+	return i;
+}
+
+static void
+zone_batch_free(struct _malloc_zone_t *zone, void **to_be_freed,
+    unsigned num_to_be_freed)
+{
+	unsigned i;
+
+	for (i = 0; i < num_to_be_freed; i++) {
+		zone_free(zone, to_be_freed[i]);
+		to_be_freed[i] = NULL;
+	}
+}
+
+static size_t
+zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal)
+{
+	return 0;
 }
 
 static size_t
 zone_good_size(malloc_zone_t *zone, size_t size)
 {
 
 	if (size == 0)
 		size = 1;
 	return (s2u(size));
 }
 
+static kern_return_t
+zone_enumerator(task_t task, void *data, unsigned type_mask,
+    vm_address_t zone_address, memory_reader_t reader,
+    vm_range_recorder_t recorder)
+{
+	return KERN_SUCCESS;
+}
+
+static boolean_t
+zone_check(malloc_zone_t *zone)
+{
+	return true;
+}
+
+static void
+zone_print(malloc_zone_t *zone, boolean_t verbose)
+{
+}
+
+static void
+zone_log(malloc_zone_t *zone, void *address)
+{
+}
+
 static void
 zone_force_lock(malloc_zone_t *zone)
 {
 
 	if (isthreaded)
 		jemalloc_prefork();
 }
 
@@ -172,62 +304,78 @@ zone_force_unlock(malloc_zone_t *zone)
 	 * reinitialized, but the child cannot unlock mutexes that were locked
 	 * by the parent.
 	 */
 	if (isthreaded)
 		jemalloc_postfork_child();
 }
 
 static void
+zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats)
+{
+	/* We make no effort to actually fill the values */
+	stats->blocks_in_use = 0;
+	stats->size_in_use = 0;
+	stats->max_size_in_use = 0;
+	stats->size_allocated = 0;
+}
+
+static boolean_t
+zone_locked(malloc_zone_t *zone)
+{
+	/* Pretend no lock is being held */
+	return false;
+}
+
+static void
+zone_reinit_lock(malloc_zone_t *zone)
+{
+	/* As of OSX 10.12, this function is only used when force_unlock would
+	 * be used if the zone version were < 9. So just use force_unlock. */
+	zone_force_unlock(zone);
+}
+
+static void
 zone_init(void)
 {
 
-	jemalloc_zone.size = (void *)zone_size;
-	jemalloc_zone.malloc = (void *)zone_malloc;
-	jemalloc_zone.calloc = (void *)zone_calloc;
-	jemalloc_zone.valloc = (void *)zone_valloc;
-	jemalloc_zone.free = (void *)zone_free;
-	jemalloc_zone.realloc = (void *)zone_realloc;
-	jemalloc_zone.destroy = (void *)zone_destroy;
+	jemalloc_zone.size = zone_size;
+	jemalloc_zone.malloc = zone_malloc;
+	jemalloc_zone.calloc = zone_calloc;
+	jemalloc_zone.valloc = zone_valloc;
+	jemalloc_zone.free = zone_free;
+	jemalloc_zone.realloc = zone_realloc;
+	jemalloc_zone.destroy = zone_destroy;
 	jemalloc_zone.zone_name = "jemalloc_zone";
-	jemalloc_zone.batch_malloc = NULL;
-	jemalloc_zone.batch_free = NULL;
+	jemalloc_zone.batch_malloc = zone_batch_malloc;
+	jemalloc_zone.batch_free = zone_batch_free;
 	jemalloc_zone.introspect = &jemalloc_zone_introspect;
-	jemalloc_zone.version = JEMALLOC_ZONE_VERSION;
-#if (JEMALLOC_ZONE_VERSION >= 5)
+	jemalloc_zone.version = 9;
 	jemalloc_zone.memalign = zone_memalign;
-#endif
-#if (JEMALLOC_ZONE_VERSION >= 6)
 	jemalloc_zone.free_definite_size = zone_free_definite_size;
-#endif
-#if (JEMALLOC_ZONE_VERSION >= 8)
-	jemalloc_zone.pressure_relief = NULL;
-#endif
+	jemalloc_zone.pressure_relief = zone_pressure_relief;
 
-	jemalloc_zone_introspect.enumerator = NULL;
-	jemalloc_zone_introspect.good_size = (void *)zone_good_size;
-	jemalloc_zone_introspect.check = NULL;
-	jemalloc_zone_introspect.print = NULL;
-	jemalloc_zone_introspect.log = NULL;
-	jemalloc_zone_introspect.force_lock = (void *)zone_force_lock;
-	jemalloc_zone_introspect.force_unlock = (void *)zone_force_unlock;
-	jemalloc_zone_introspect.statistics = NULL;
-#if (JEMALLOC_ZONE_VERSION >= 6)
-	jemalloc_zone_introspect.zone_locked = NULL;
-#endif
-#if (JEMALLOC_ZONE_VERSION >= 7)
+	jemalloc_zone_introspect.enumerator = zone_enumerator;
+	jemalloc_zone_introspect.good_size = zone_good_size;
+	jemalloc_zone_introspect.check = zone_check;
+	jemalloc_zone_introspect.print = zone_print;
+	jemalloc_zone_introspect.log = zone_log;
+	jemalloc_zone_introspect.force_lock = zone_force_lock;
+	jemalloc_zone_introspect.force_unlock = zone_force_unlock;
+	jemalloc_zone_introspect.statistics = zone_statistics;
+	jemalloc_zone_introspect.zone_locked = zone_locked;
 	jemalloc_zone_introspect.enable_discharge_checking = NULL;
 	jemalloc_zone_introspect.disable_discharge_checking = NULL;
 	jemalloc_zone_introspect.discharge = NULL;
-#  ifdef __BLOCKS__
+#ifdef __BLOCKS__
 	jemalloc_zone_introspect.enumerate_discharged_pointers = NULL;
-#  else
+#else
 	jemalloc_zone_introspect.enumerate_unavailable_without_blocks = NULL;
-#  endif
 #endif
+	jemalloc_zone_introspect.reinit_lock = zone_reinit_lock;
 }
 
 static malloc_zone_t *
 zone_default_get(void)
 {
 	malloc_zone_t **zones = NULL;
 	unsigned int num_zones = 0;
 
--- a/memory/jemalloc/upstream.info
+++ b/memory/jemalloc/upstream.info
@@ -1,2 +1,2 @@
 UPSTREAM_REPO=https://github.com/jemalloc/jemalloc
-UPSTREAM_COMMIT=4.4.0
+UPSTREAM_COMMIT=c6943acb3c56d1b3d1e82dd43b3fcfeae7771990
--- a/memory/mozjemalloc/jemalloc.c
+++ b/memory/mozjemalloc/jemalloc.c
@@ -1446,77 +1446,28 @@ static void	*huge_palloc(size_t size, si
 static void	*huge_ralloc(void *ptr, size_t size, size_t oldsize);
 static void	huge_dalloc(void *ptr);
 static void	malloc_print_stats(void);
 #ifndef MOZ_MEMORY_WINDOWS
 static
 #endif
 bool		malloc_init_hard(void);
 
-static void	_malloc_prefork(void);
-static void	_malloc_postfork(void);
-
-#ifdef MOZ_MEMORY_DARWIN
-/*
- * MALLOC_ZONE_T_NOTE
- *
- * On Darwin, we hook into the memory allocator using a malloc_zone_t struct.
- * We must be very careful around this struct because of different behaviour on
- * different versions of OSX.
- *
- * Each of OSX 10.5, 10.6 and 10.7 use different versions of the struct
- * (with version numbers 3, 6 and 8 respectively). The binary we use on each of
- * these platforms will not necessarily be built using the correct SDK [1].
- * This means we need to statically know the correct struct size to use on all
- * OSX releases, and have a fallback for unknown future versions. The struct
- * sizes defined in osx_zone_types.h.
- *
- * For OSX 10.8 and later, we may expect the malloc_zone_t struct to change
- * again, and need to dynamically account for this. By simply leaving
- * malloc_zone_t alone, we don't quite deal with the problem, because there
- * remain calls to jemalloc through the mozalloc interface. We check this
- * dynamically on each allocation, using the CHECK_DARWIN macro and
- * osx_use_jemalloc.
- *
- *
- * [1] Mozilla is built as a universal binary on Mac, supporting i386 and
- *     x86_64. The i386 target is built using the 10.5 SDK, even if it runs on
- *     10.6. The x86_64 target is built using the 10.6 SDK, even if it runs on
- *     10.7 or later, or 10.5.
- *
- * FIXME:
- *   When later versions of OSX come out (10.8 and up), we need to check their
- *   malloc_zone_t versions. If they're greater than 8, we need a new version
- *   of malloc_zone_t adapted into osx_zone_types.h.
- */
-
-#ifndef MOZ_REPLACE_MALLOC
-#include "osx_zone_types.h"
-
-#define LEOPARD_MALLOC_ZONE_T_VERSION 3
-#define SNOW_LEOPARD_MALLOC_ZONE_T_VERSION 6
-#define LION_MALLOC_ZONE_T_VERSION 8
-
-static bool osx_use_jemalloc = false;
-
-
-static lion_malloc_zone l_szone;
-static malloc_zone_t * szone = (malloc_zone_t*)(&l_szone);
-
-static lion_malloc_introspection l_ozone_introspect;
-static malloc_introspection_t * const ozone_introspect =
-	(malloc_introspection_t*)(&l_ozone_introspect);
-static malloc_zone_t *get_default_zone();
-static void szone2ozone(malloc_zone_t *zone, size_t size);
-static size_t zone_version_size(int version);
-#else
-static const bool osx_use_jemalloc = true;
-#endif
-
-#endif
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void	_malloc_prefork(void);
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void	_malloc_postfork_parent(void);
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void	_malloc_postfork_child(void);
 
 /*
  * End function prototypes.
  */
 /******************************************************************************/
 
 static inline size_t
 load_acquire_z(size_t *p)
@@ -5575,32 +5526,33 @@ malloc_init(void)
 
 	if (malloc_initialized == false)
 		return (malloc_init_hard());
 
 	return (false);
 }
 #endif
 
+#if defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_REPLACE_MALLOC)
+extern void register_zone(void);
+#endif
+
 #if !defined(MOZ_MEMORY_WINDOWS)
 static
 #endif
 bool
 malloc_init_hard(void)
 {
 	unsigned i;
 	char buf[PATH_MAX + 1];
 	const char *opts;
 	long result;
 #ifndef MOZ_MEMORY_WINDOWS
 	int linklen;
 #endif
-#ifdef MOZ_MEMORY_DARWIN
-    malloc_zone_t* default_zone;
-#endif
 
 #ifndef MOZ_MEMORY_WINDOWS
 	malloc_mutex_lock(&init_lock);
 #endif
 
 	if (malloc_initialized) {
 		/*
 		 * Another thread initialized the allocator before this one
@@ -6086,65 +6038,27 @@ MALLOC_OUT:
 	if (chunk_rtree == NULL)
 		return (true);
 #endif
 
 	malloc_initialized = true;
 
 #if !defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN)
 	/* Prevent potential deadlock on malloc locks after fork. */
-	pthread_atfork(_malloc_prefork, _malloc_postfork, _malloc_postfork);
+	pthread_atfork(_malloc_prefork, _malloc_postfork_parent, _malloc_postfork_child);
 #endif
 
 #if defined(NEEDS_PTHREAD_MMAP_UNALIGNED_TSD)
 	if (pthread_key_create(&mmap_unaligned_tsd, NULL) != 0) {
 		malloc_printf("<jemalloc>: Error in pthread_key_create()\n");
 	}
 #endif
 
 #if defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_REPLACE_MALLOC)
-	/*
-	* Overwrite the default memory allocator to use jemalloc everywhere.
-	*/
-	default_zone = get_default_zone();
-
-	/*
-	 * We only use jemalloc with MacOS 10.6 and 10.7.  jemalloc is disabled
-	 * on 32-bit builds (10.5 and 32-bit 10.6) due to bug 702250, an
-	 * apparent MacOS bug.  In fact, this code isn't even compiled on
-	 * 32-bit builds.
-	 *
-	 * We'll have to update our code to work with newer versions, because
-	 * the malloc zone layout is likely to change.
-	 */
-
-	osx_use_jemalloc = (default_zone->version == SNOW_LEOPARD_MALLOC_ZONE_T_VERSION ||
-			    default_zone->version == LION_MALLOC_ZONE_T_VERSION);
-
-	/* Allow us dynamically turn off jemalloc for testing. */
-	if (getenv("NO_MAC_JEMALLOC")) {
-		osx_use_jemalloc = false;
-#ifdef __i386__
-		malloc_printf("Warning: NO_MAC_JEMALLOC has no effect on "
-			      "i386 machines (such as this one).\n");
-#endif
-	}
-
-	if (osx_use_jemalloc) {
-		/*
-		 * Convert the default szone to an "overlay zone" that is capable
-		 * of deallocating szone-allocated objects, but allocating new
-		 * objects from jemalloc.
-		 */
-		size_t size = zone_version_size(default_zone->version);
-		szone2ozone(default_zone, size);
-	}
-	else {
-		szone = default_zone;
-	}
+	register_zone();
 #endif
 
 #ifndef MOZ_MEMORY_WINDOWS
 	malloc_mutex_unlock(&init_lock);
 #endif
 	return (false);
 }
 
@@ -6161,42 +6075,21 @@ malloc_shutdown()
 /*
  * End general internal functions.
  */
 /******************************************************************************/
 /*
  * Begin malloc(3)-compatible functions.
  */
 
-/*
- * Even though we compile with MOZ_MEMORY, we may have to dynamically decide
- * not to use jemalloc, as discussed above. However, we call jemalloc
- * functions directly from mozalloc. Since it's pretty dangerous to mix the
- * allocators, we need to call the OSX allocators from the functions below,
- * when osx_use_jemalloc is not (dynamically) set.
- *
- * Note that we assume jemalloc is enabled on i386.  This is safe because the
- * only i386 versions of MacOS are 10.5 and 10.6, which we support.  We have to
- * do this because madvise isn't in the malloc zone struct for 10.5.
- *
- * This means that NO_MAC_JEMALLOC doesn't work on i386.
- */
-#if defined(MOZ_MEMORY_DARWIN) && !defined(__i386__) && !defined(MOZ_REPLACE_MALLOC)
-#define DARWIN_ONLY(A) if (!osx_use_jemalloc) { A; }
-#else
-#define DARWIN_ONLY(A)
-#endif
-
 MOZ_MEMORY_API void *
 malloc_impl(size_t size)
 {
 	void *ret;
 
-	DARWIN_ONLY(return (szone->malloc)(szone, size));
-
 	if (malloc_init()) {
 		ret = NULL;
 		goto RETURN;
 	}
 
 	if (size == 0) {
 #ifdef MALLOC_SYSV
 		if (opt_sysv == false)
@@ -6269,18 +6162,16 @@ memalign_impl(size_t alignment, size_t s
 #ifndef MOZ_MEMORY_ELF
 MOZ_MEMORY_API
 #endif
 void *
 MEMALIGN(size_t alignment, size_t size)
 {
 	void *ret;
 
-	DARWIN_ONLY(return (szone->memalign)(szone, alignment, size));
-
 	assert(((alignment - 1) & alignment) == 0);
 
 	if (malloc_init()) {
 		ret = NULL;
 		goto RETURN;
 	}
 
 	if (size == 0) {
@@ -6369,18 +6260,16 @@ valloc_impl(size_t size)
 }
 
 MOZ_MEMORY_API void *
 calloc_impl(size_t num, size_t size)
 {
 	void *ret;
 	size_t num_size;
 
-	DARWIN_ONLY(return (szone->calloc)(szone, num, size));
-
 	if (malloc_init()) {
 		num_size = 0;
 		ret = NULL;
 		goto RETURN;
 	}
 
 	num_size = num * size;
 	if (num_size == 0) {
@@ -6425,18 +6314,16 @@ RETURN:
 	return (ret);
 }
 
 MOZ_MEMORY_API void *
 realloc_impl(void *ptr, size_t size)
 {
 	void *ret;
 
-	DARWIN_ONLY(return (szone->realloc)(szone, ptr, size));
-
 	if (size == 0) {
 #ifdef MALLOC_SYSV
 		if (opt_sysv == false)
 #endif
 			size = 1;
 #ifdef MALLOC_SYSV
 		else {
 			if (ptr != NULL)
@@ -6489,18 +6376,16 @@ RETURN:
 	return (ret);
 }
 
 MOZ_MEMORY_API void
 free_impl(void *ptr)
 {
 	size_t offset;
 
-	DARWIN_ONLY((szone->free)(szone, ptr); return);
-
 	UTRACE(ptr, 0, 0);
 
 	/*
 	 * A version of idalloc that checks for NULL pointer but only for
 	 * huge allocations assuming that CHUNK_ADDR2OFFSET(NULL) == 0.
 	 */
 	assert(CHUNK_ADDR2OFFSET(NULL) == 0);
 	offset = CHUNK_ADDR2OFFSET(ptr);
@@ -6514,22 +6399,17 @@ free_impl(void *ptr)
  * End malloc(3)-compatible functions.
  */
 /******************************************************************************/
 /*
  * Begin non-standard functions.
  */
 
 /* This was added by Mozilla for use by SQLite. */
-#if defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_REPLACE_MALLOC)
-static
-#else
-MOZ_MEMORY_API
-#endif
-size_t
+MOZ_MEMORY_API size_t
 malloc_good_size_impl(size_t size)
 {
 	/*
 	 * This duplicates the logic in imalloc(), arena_malloc() and
 	 * arena_malloc_small().
 	 */
 	if (size < small_min) {
 		/* Small (tiny). */
@@ -6561,18 +6441,16 @@ malloc_good_size_impl(size_t size)
 	}
 	return size;
 }
 
 
 MOZ_MEMORY_API size_t
 malloc_usable_size_impl(MALLOC_USABLE_SIZE_CONST_PTR void *ptr)
 {
-	DARWIN_ONLY(return (szone->size)(szone, ptr));
-
 #ifdef MALLOC_VALIDATE
 	return (isalloc_validate(ptr));
 #else
 	assert(ptr != NULL);
 
 	return (isalloc(ptr));
 #endif
 }
@@ -6880,17 +6758,20 @@ jemalloc_free_dirty_pages_impl(void)
 /******************************************************************************/
 /*
  * Begin library-private functions, used by threading libraries for protection
  * of malloc during fork().  These functions are only called if the program is
  * running in threaded mode, so there is no need to check whether the program
  * is threaded here.
  */
 
-static void
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void
 _malloc_prefork(void)
 {
 	unsigned i;
 
 	/* Acquire all mutexes in a safe order. */
 
 	malloc_spin_lock(&arenas_lock);
 	for (i = 0; i < narenas; i++) {
@@ -6898,293 +6779,69 @@ static void
 			malloc_spin_lock(&arenas[i]->lock);
 	}
 
 	malloc_mutex_lock(&base_mtx);
 
 	malloc_mutex_lock(&huge_mtx);
 }
 
-static void
-_malloc_postfork(void)
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void
+_malloc_postfork_parent(void)
 {
 	unsigned i;
 
 	/* Release all mutexes, now that fork() has completed. */
 
 	malloc_mutex_unlock(&huge_mtx);
 
 	malloc_mutex_unlock(&base_mtx);
 
 	for (i = 0; i < narenas; i++) {
 		if (arenas[i] != NULL)
 			malloc_spin_unlock(&arenas[i]->lock);
 	}
 	malloc_spin_unlock(&arenas_lock);
 }
 
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void
+_malloc_postfork_child(void)
+{
+	unsigned i;
+
+	/* Reinitialize all mutexes, now that fork() has completed. */
+
+	malloc_mutex_init(&huge_mtx);
+
+	malloc_mutex_init(&base_mtx);
+
+	for (i = 0; i < narenas; i++) {
+		if (arenas[i] != NULL)
+			malloc_spin_init(&arenas[i]->lock);
+	}
+	malloc_spin_init(&arenas_lock);
+}
+
 /*
  * End library-private functions.
  */
 /******************************************************************************/
 
 #ifdef HAVE_DLOPEN
 #  include <dlfcn.h>
 #endif
 
 #if defined(MOZ_MEMORY_DARWIN)
 
-#if !defined(MOZ_REPLACE_MALLOC)
-static void *
-zone_malloc(malloc_zone_t *zone, size_t size)
-{
-
-	return (malloc_impl(size));
-}
-
-static void *
-zone_calloc(malloc_zone_t *zone, size_t num, size_t size)
-{
-
-	return (calloc_impl(num, size));
-}
-
-static void *
-zone_valloc(malloc_zone_t *zone, size_t size)
-{
-	void *ret = NULL; /* Assignment avoids useless compiler warning. */
-
-	posix_memalign_impl(&ret, pagesize, size);
-
-	return (ret);
-}
-
-static void *
-zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size)
-{
-	return (memalign_impl(alignment, size));
-}
-
-static void *
-zone_destroy(malloc_zone_t *zone)
-{
-
-	/* This function should never be called. */
-	assert(false);
-	return (NULL);
-}
-
-static size_t
-zone_good_size(malloc_zone_t *zone, size_t size)
-{
-	return malloc_good_size_impl(size);
-}
-
-static size_t
-ozone_size(malloc_zone_t *zone, void *ptr)
-{
-	size_t ret = isalloc_validate(ptr);
-	if (ret == 0)
-		ret = szone->size(zone, ptr);
-
-	return ret;
-}
-
-static void
-ozone_free(malloc_zone_t *zone, void *ptr)
-{
-	if (isalloc_validate(ptr) != 0)
-		free_impl(ptr);
-	else {
-		size_t size = szone->size(zone, ptr);
-		if (size != 0)
-			(szone->free)(zone, ptr);
-		/* Otherwise we leak. */
-	}
-}
-
-static void *
-ozone_realloc(malloc_zone_t *zone, void *ptr, size_t size)
-{
-    size_t oldsize;
-	if (ptr == NULL)
-		return (malloc_impl(size));
-
-	oldsize = isalloc_validate(ptr);
-	if (oldsize != 0)
-		return (realloc_impl(ptr, size));
-	else {
-		oldsize = szone->size(zone, ptr);
-		if (oldsize == 0)
-			return (malloc_impl(size));
-		else {
-			void *ret = malloc_impl(size);
-			if (ret != NULL) {
-				memcpy(ret, ptr, (oldsize < size) ? oldsize :
-				    size);
-				(szone->free)(zone, ptr);
-			}
-			return (ret);
-		}
-	}
-}
-
-static unsigned
-ozone_batch_malloc(malloc_zone_t *zone, size_t size, void **results,
-    unsigned num_requested)
-{
-	/* Don't bother implementing this interface, since it isn't required. */
-	return 0;
-}
-
-static void
-ozone_batch_free(malloc_zone_t *zone, void **to_be_freed, unsigned num)
-{
-	unsigned i;
-
-	for (i = 0; i < num; i++)
-		ozone_free(zone, to_be_freed[i]);
-}
-
-static void
-ozone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size)
-{
-	if (isalloc_validate(ptr) != 0) {
-		assert(isalloc_validate(ptr) == size);
-		free_impl(ptr);
-	} else {
-		assert(size == szone->size(zone, ptr));
-		l_szone.m16(zone, ptr, size);
-	}
-}
-
-static void
-ozone_force_lock(malloc_zone_t *zone)
-{
-	_malloc_prefork();
-	szone->introspect->force_lock(zone);
-}
-
-static void
-ozone_force_unlock(malloc_zone_t *zone)
-{
-	szone->introspect->force_unlock(zone);
-        _malloc_postfork();
-}
-
-static size_t
-zone_version_size(int version)
-{
-    switch (version)
-    {
-        case SNOW_LEOPARD_MALLOC_ZONE_T_VERSION:
-            return sizeof(snow_leopard_malloc_zone);
-        case LEOPARD_MALLOC_ZONE_T_VERSION:
-            return sizeof(leopard_malloc_zone);
-        default:
-        case LION_MALLOC_ZONE_T_VERSION:
-            return sizeof(lion_malloc_zone);
-    }
-}
-
-static malloc_zone_t *get_default_zone()
-{
-  malloc_zone_t **zones = NULL;
-  unsigned int num_zones = 0;
-
-  /*
-   * On OSX 10.12, malloc_default_zone returns a special zone that is not
-   * present in the list of registered zones. That zone uses a "lite zone"
-   * if one is present (apparently enabled when malloc stack logging is
-   * enabled), or the first registered zone otherwise. In practice this
-   * means unless malloc stack logging is enabled, the first registered
-   * zone is the default.
-   * So get the list of zones to get the first one, instead of relying on
-   * malloc_default_zone.
-   */
-  if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, (vm_address_t**) &zones,
-                                           &num_zones)) {
-    /* Reset the value in case the failure happened after it was set. */
-    num_zones = 0;
-  }
-  if (num_zones) {
-    return zones[0];
-  }
-  return malloc_default_zone();
-}
-
-/*
- * Overlay the default scalable zone (szone) such that existing allocations are
- * drained, and further allocations come from jemalloc. This is necessary
- * because Core Foundation directly accesses and uses the szone before the
- * jemalloc library is even loaded.
- */
-static void
-szone2ozone(malloc_zone_t *default_zone, size_t size)
-{
-    lion_malloc_zone *l_zone;
-	assert(malloc_initialized);
-
-	/*
-	 * Stash a copy of the original szone so that we can call its
-	 * functions as needed. Note that internally, the szone stores its
-	 * bookkeeping data structures immediately following the malloc_zone_t
-	 * header, so when calling szone functions, we need to pass a pointer to
-	 * the original zone structure.
-	 */
-	memcpy(szone, default_zone, size);
-
-	/* OSX 10.7 allocates the default zone in protected memory. */
-	if (default_zone->version >= LION_MALLOC_ZONE_T_VERSION) {
-		void* start_of_page = (void*)((size_t)(default_zone) & ~pagesize_mask);
-		mprotect (start_of_page, size, PROT_READ | PROT_WRITE);
-	}
-
-	default_zone->size = (void *)ozone_size;
-	default_zone->malloc = (void *)zone_malloc;
-	default_zone->calloc = (void *)zone_calloc;
-	default_zone->valloc = (void *)zone_valloc;
-	default_zone->free = (void *)ozone_free;
-	default_zone->realloc = (void *)ozone_realloc;
-	default_zone->destroy = (void *)zone_destroy;
-	default_zone->batch_malloc = NULL;
-	default_zone->batch_free = ozone_batch_free;
-	default_zone->introspect = ozone_introspect;
-
-	/* Don't modify default_zone->zone_name; Mac libc may rely on the name
-	 * being unchanged.  See Mozilla bug 694896. */
-
-	ozone_introspect->enumerator = NULL;
-	ozone_introspect->good_size = (void *)zone_good_size;
-	ozone_introspect->check = NULL;
-	ozone_introspect->print = NULL;
-	ozone_introspect->log = NULL;
-	ozone_introspect->force_lock = (void *)ozone_force_lock;
-	ozone_introspect->force_unlock = (void *)ozone_force_unlock;
-	ozone_introspect->statistics = NULL;
-
-    /* Platform-dependent structs */
-    l_zone = (lion_malloc_zone*)(default_zone);
-
-    if (default_zone->version >= SNOW_LEOPARD_MALLOC_ZONE_T_VERSION) {
-        l_zone->m15 = (void (*)())zone_memalign;
-        l_zone->m16 = (void (*)())ozone_free_definite_size;
-        l_ozone_introspect.m9 = NULL;
-    }
-
-    if (default_zone->version >= LION_MALLOC_ZONE_T_VERSION) {
-        l_zone->m17 = NULL;
-        l_ozone_introspect.m10 = NULL;
-        l_ozone_introspect.m11 = NULL;
-        l_ozone_introspect.m12 = NULL;
-        l_ozone_introspect.m13 = NULL;
-    }
-}
-#endif
-
 __attribute__((constructor))
 void
 jemalloc_darwin_init(void)
 {
 	if (malloc_init_hard())
 		abort();
 }
 
deleted file mode 100644
--- a/memory/mozjemalloc/osx_zone_types.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* -*- Mode: C; tab-width: 8; c-basic-offset: 8 -*- */
-/* vim:set softtabstop=8 shiftwidth=8: */
-/*-
- * Copyright (C) 2006-2008 Jason Evans <jasone@FreeBSD.org>.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice(s), this list of conditions and the following disclaimer as
- *    the first lines of this file unmodified other than the possible
- *    addition of one or more copyright notices.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice(s), this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * The purpose of these structs is described in jemalloc.c, in the comment
- * marked MALLOC_ZONE_T_NOTE.
- *
- * We need access to some structs that come with a specific version of OSX 
- * but can't copy them here because of licensing restrictions (see bug
- * 603655). The structs below are equivalent in that they'll always be
- * compiled to the same representation on all platforms.
- *
- * `void*` and `void (*)()` may not be the same size on weird platforms, but
- * the size of a function pointer shouldn't vary according to its parameters
- * or return type.
- *
- * Apple's version of these structures, complete with member names and
- * comments, is available online at
- *
- * http://www.opensource.apple.com/source/Libc/Libc-763.12/include/malloc/malloc.h
- *
- */
-
-/*
- * OSX 10.5 - Leopard
- */
-typedef struct _leopard_malloc_zone {
- 	void *m1;
-	void *m2;
-	void (*m3)();
-	void (*m4)();
-	void (*m5)();
-	void (*m6)();
-	void (*m7)();
-	void (*m8)();
-	void (*m9)();
-	void *m10;
-	void (*m11)();
-	void (*m12)();
-	void *m13;
-	unsigned m14;
-} leopard_malloc_zone;
-
-/*
- * OSX 10.6 - Snow Leopard
- */
-typedef struct _snow_leopard_malloc_zone {
-	void *m1;
-	void *m2;
-	void (*m3)();
-	void (*m4)();
-	void (*m5)();
-	void (*m6)();
-	void (*m7)();
-	void (*m8)();
-	void (*m9)();
-	void *m10;
-	void (*m11)();
-	void (*m12)();
-	void *m13;
-	unsigned m14;
-	void (*m15)(); // this member added in 10.6
-	void (*m16)(); // this member added in 10.6
-} snow_leopard_malloc_zone;
-
-typedef struct _snow_leopard_malloc_introspection {
-    void (*m1)();
-    void (*m2)();
-    void (*m3)();
-    void (*m4)();
-    void (*m5)();
-    void (*m6)();
-    void (*m7)();
-    void (*m8)();
-    void (*m9)(); // this member added in 10.6
-} snow_leopard_malloc_introspection;
-
-/*
- * OSX 10.7 - Lion
- */
-typedef struct _lion_malloc_zone {
-	void *m1;
-	void *m2;
-	void (*m3)();
-	void (*m4)();
-	void (*m5)();
-	void (*m6)();
-	void (*m7)();
-	void (*m8)();
-	void (*m9)();
-	void *m10;
-	void (*m11)();
-	void (*m12)();
-	void *m13;
-	unsigned m14;
-	void (*m15)();
-	void (*m16)();
-	void (*m17)(); // this member added in 10.7
-} lion_malloc_zone;
-
-typedef struct _lion_malloc_introspection {
-    void (*m1)();
-    void (*m2)();
-    void (*m3)();
-    void (*m4)();
-    void (*m5)();
-    void (*m6)();
-    void (*m7)();
-    void (*m8)();
-    void (*m9)();
-    void (*m10)(); // this member added in 10.7
-    void (*m11)(); // this member added in 10.7
-    void (*m12)(); // this member added in 10.7
-#ifdef __BLOCKS__
-    void (*m13)(); // this member added in 10.7
-#else
-    void *m13; // this member added in 10.7
-#endif
-} lion_malloc_introspection;
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -736,16 +736,17 @@ public class BrowserApp extends GeckoApp
             "Menu:Remove",
             "LightweightTheme:Update",
             "Tab:Added",
             "Video:Play",
             "CharEncoding:Data",
             "CharEncoding:State",
             "Settings:Show",
             "Updater:Launch",
+            "Sanitize:OpenTabs",
             null);
 
         EventDispatcher.getInstance().registerBackgroundThreadListener(this,
             "Experiments:GetActive",
             "Experiments:SetOverride",
             "Experiments:ClearOverride",
             "Favicon:Request",
             "Feedback:MaybeLater",
@@ -1449,16 +1450,17 @@ public class BrowserApp extends GeckoApp
             "Menu:Remove",
             "LightweightTheme:Update",
             "Tab:Added",
             "Video:Play",
             "CharEncoding:Data",
             "CharEncoding:State",
             "Settings:Show",
             "Updater:Launch",
+            "Sanitize:OpenTabs",
             null);
 
         EventDispatcher.getInstance().unregisterBackgroundThreadListener(this,
             "Experiments:GetActive",
             "Experiments:SetOverride",
             "Experiments:ClearOverride",
             "Favicon:Request",
             "Feedback:MaybeLater",
@@ -1909,16 +1911,21 @@ public class BrowserApp extends GeckoApp
                         .execute(IconsHelper.createBase64EventCallback(callback));
                 break;
 
             case "Feedback:MaybeLater":
                 SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
                 settings.edit().putInt(getPackageName() + ".feedback_launch_count", 0).apply();
                 break;
 
+            case "Sanitize:OpenTabs":
+                Tabs.getInstance().closeAll();
+                callback.sendSuccess(null);
+                break;
+
             case "Sanitize:ClearHistory":
                 BrowserDB.from(getProfile()).clearHistory(
                         getContentResolver(), message.getBoolean("clearSearchHistory", false));
                 callback.sendSuccess(null);
                 break;
 
             case "Sanitize:ClearSyncedTabs":
                 FennecTabsRepository.deleteNonLocalClientsAndTabs(getContext());
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -580,27 +580,30 @@ public abstract class GeckoApp
 
             final JSONObject res = new JSONObject();
             try {
                 res.put("sanitize", clearObj);
             } catch (JSONException ex) {
                 Log.e(LOGTAG, "Error adding sanitize object", ex);
             }
 
-            // If the user has opted out of session restore, and does want to clear history
+            // If the user wants to clear open tabs, or else has opted out of session restore and does want to clear history,
             // we also want to prevent the current session info from being saved.
-            if (clearObj.has("private.data.history")) {
-                final String sessionRestore = getSessionRestorePreference(getSharedPreferences());
-                try {
+            try {
+                if (clearObj.has("private.data.openTabs")) {
+                    res.put("dontSaveSession", true);
+                } else if (clearObj.has("private.data.history")) {
+
+                    final String sessionRestore = getSessionRestorePreference(getSharedPreferences());
                     res.put("dontSaveSession", "quit".equals(sessionRestore));
-                } catch (JSONException ex) {
-                    Log.e(LOGTAG, "Error adding session restore data", ex);
+
                 }
+            } catch (JSONException ex) {
+                Log.e(LOGTAG, "Error adding session restore data", ex);
             }
-
             GeckoAppShell.notifyObservers("Browser:Quit", res.toString());
             // We don't call doShutdown() here because this creates a race condition which can
             // cause the clearing of private data to fail. Instead, we shut down the UI only after
             // we're done sanitizing.
             return true;
         }
 
         return super.onOptionsItemSelected(item);
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -80,16 +80,22 @@ public class Tabs implements BundleEvent
     private volatile boolean mInitialTabsAdded;
 
     private Context mAppContext;
     private LayerView mLayerView;
     private ContentObserver mBookmarksContentObserver;
     private PersistTabsRunnable mPersistTabsRunnable;
     private int mPrivateClearColor;
 
+    public void closeAll() {
+        for (final Tab tab : mOrder) {
+            Tabs.getInstance().closeTab(tab, false);
+        }
+    }
+
     private static class PersistTabsRunnable implements Runnable {
         private final BrowserDB db;
         private final Context context;
         private final Iterable<Tab> tabs;
 
         public PersistTabsRunnable(final Context context, Iterable<Tab> tabsInOrder) {
             this.context = context;
             this.db = BrowserDB.from(context);
--- a/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java
@@ -220,18 +220,23 @@ public class HomePager extends ViewPager
         adapter.setPanelStateChangeListener(mPanelStateChangeListener);
         adapter.setCanLoadHint(true);
         setAdapter(adapter);
 
         // Don't show the tabs strip until we have the
         // list of panels in place.
         mTabStrip.setVisibility(View.INVISIBLE);
 
-        // Load list of panels from configuration
-        lm.initLoader(LOADER_ID_CONFIG, null, mConfigLoaderCallbacks);
+        // If HomeConfigLoader already exist, force load to select the current item
+        if (lm.getLoader(LOADER_ID_CONFIG) != null) {
+            lm.getLoader(LOADER_ID_CONFIG).forceLoad();
+        } else {
+            // Load list of panels from configuration
+            lm.initLoader(LOADER_ID_CONFIG, null, mConfigLoaderCallbacks);
+        }
 
         if (shouldAnimate) {
             animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
                 @Override
                 public void onPropertyAnimationStart() {
                     setLayerType(View.LAYER_TYPE_HARDWARE, null);
                 }
 
--- a/mobile/android/base/java/org/mozilla/gecko/home/activitystream/menu/ActivityStreamContextMenu.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/activitystream/menu/ActivityStreamContextMenu.java
@@ -2,18 +2,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 package org.mozilla.gecko.home.activitystream.menu;
 
 import android.content.Context;
 import android.content.Intent;
 import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.support.design.widget.NavigationView;
 import android.view.MenuItem;
 import android.view.View;
 
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.IntentHelper;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
@@ -77,16 +75,17 @@ public abstract class ActivityStreamCont
      * <p/>
      * Your implementation must be ready to return items from getItemByID() before postInit() is
      * called, i.e. you should probably inflate your menu items before this call.
      */
     /* package-local */ void postInit() {
         final MenuItem bookmarkItem = getItemByID(R.id.bookmark);
         if (Boolean.TRUE.equals(item.isBookmarked())) {
             bookmarkItem.setTitle(R.string.bookmark_remove);
+            bookmarkItem.setIcon(R.drawable.as_bookmark_filled);
         }
 
         final MenuItem pinItem = getItemByID(R.id.pin);
         if (Boolean.TRUE.equals(item.isPinned())) {
             pinItem.setTitle(R.string.contextmenu_top_sites_unpin);
         }
 
         // Disable "dismiss" for topsites until we have decided on its behaviour for topsites
@@ -106,16 +105,17 @@ public abstract class ActivityStreamCont
                 protected Boolean doInBackground() {
                     return BrowserDB.from(context).isBookmark(context.getContentResolver(), item.getUrl());
                 }
 
                 @Override
                 protected void onPostExecute(Boolean hasBookmark) {
                     if (hasBookmark) {
                         bookmarkItem.setTitle(R.string.bookmark_remove);
+                        bookmarkItem.setIcon(R.drawable.as_bookmark_filled);
                     }
 
                     item.updateBookmarked(hasBookmark);
                     bookmarkItem.setEnabled(true);
                 }
             }).execute();
         }
 
--- a/mobile/android/base/java/org/mozilla/gecko/widget/FadedMultiColorTextView.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/FadedMultiColorTextView.java
@@ -49,22 +49,23 @@ public class FadedMultiColorTextView ext
 
         final boolean needsEllipsis = needsEllipsis();
         if (needsEllipsis) {
             final int right = getWidth() - getCompoundPaddingRight();
             final float left = right - fadeWidth;
 
             updateGradientShader(needsEllipsis, right);
 
-            final float center = getHeight() / 2;
-
             // Shrink height of gradient to prevent it overlaying parent view border.
             // The shrunk size just nee to cover the text itself.
-            final float top = center - getTextSize() / 2;
-            final float bottom = center + getTextSize() / 2;
+            final float density = getResources().getDisplayMetrics().density;
+            final float h = Math.abs(fadePaint.getFontMetrics().top) + 1;
+            final float l = fadePaint.getFontMetrics().bottom + 1;
+            final float top = getBaseline() - h * density;
+            final float bottom = getBaseline() + l * density;
 
             canvas.drawRect(left, top, right, bottom, fadePaint);
         }
     }
 
     private void updateGradientShader(final boolean needsEllipsis, final int gradientEndRight) {
         final int backgroundColor =
                 fadeBackgroundColorList.getColorForState(getDrawableState(), Color.RED);
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -382,16 +382,17 @@ size. -->
 
 <!ENTITY pref_use_master_password "Use master password">
 <!ENTITY pref_sync2 "Sign in">
 <!ENTITY pref_sync_summary2 "Sync your tabs, bookmarks, logins, history">
 <!ENTITY pref_search_suggestions "Show search suggestions">
 <!ENTITY pref_history_search_suggestions "Show search history">
 <!ENTITY pref_import_options "Import options">
 <!ENTITY pref_import_android_summary "Import bookmarks and history from the native browser">
+<!ENTITY pref_private_data_openTabs "Open tabs">
 <!ENTITY pref_private_data_history2 "Browsing history">
 <!ENTITY pref_private_data_searchHistory "Search history">
 <!ENTITY pref_private_data_formdata2 "Form history">
 <!ENTITY pref_private_data_cookies2 "Cookies &amp; active logins">
 <!ENTITY pref_private_data_passwords2 "Saved logins">
 <!ENTITY pref_private_data_cache "Cache">
 <!ENTITY pref_private_data_offlineApps "Offline website data">
 <!ENTITY pref_private_data_siteSettings2 "Site settings">
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/drawable/as_bookmark_filled.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,1C11.508,1.068 11.087,1.415 10.925,1.895L8.178,7.562L2.301,8.552C0.956,8.771 0.622,9.738 1.557,10.7L5.717,15.186L4.748,21.497C4.601,22.445 4.99,22.997 5.673,22.997C5.985,22.985 6.291,22.899 6.564,22.748L12.021,19.817L17.542,22.748C17.816,22.9 18.121,22.985 18.434,22.997C19.117,22.997 19.504,22.442 19.36,21.497L18.394,15.186L22.505,10.705C23.441,9.739 23.105,8.771 21.761,8.552L15.972,7.562L13.1,1.9C12.939,1.416 12.516,1.067 12.01,1L12.01,1Z"/>
+</vector>
--- a/mobile/android/base/resources/values/arrays.xml
+++ b/mobile/android/base/resources/values/arrays.xml
@@ -73,16 +73,17 @@
         <item>true</item>
         <item>true</item>
     </string-array>
     <string-array name="pref_import_android_values">
         <item>android_import.data.bookmarks</item>
         <item>android_import.data.history</item>
     </string-array>
     <string-array name="pref_private_data_entries">
+        <item>@string/pref_private_data_openTabs</item>
         <item>@string/pref_private_data_history2</item>
         <item>@string/pref_private_data_searchHistory</item>
         <item>@string/pref_private_data_downloadFiles2</item>
         <item>@string/pref_private_data_formdata2</item>
         <item>@string/pref_private_data_cookies2</item>
         <item>@string/pref_private_data_cache</item>
         <item>@string/pref_private_data_offlineApps</item>
         <item>@string/pref_private_data_siteSettings</item>
@@ -94,31 +95,34 @@
         <item>true</item>
         <item>true</item>
         <item>true</item>
         <item>true</item>
         <item>true</item>
         <item>true</item>
         <item>true</item>
         <item>true</item>
+        <item>true</item>
         <item>false</item>
     </string-array>
     <string-array name="pref_private_data_values">
+        <item>private.data.openTabs</item>
         <item>private.data.history</item>
         <item>private.data.searchHistory</item>
         <item>private.data.downloadFiles</item>
         <item>private.data.formdata</item>
         <item>private.data.cookies_sessions</item>
         <item>private.data.cache</item>
         <item>private.data.offlineApps</item>
         <item>private.data.siteSettings</item>
         <item>private.data.syncedTabs</item>
         <item>private.data.passwords</item>
     </string-array>
     <string-array name="pref_private_data_keys">
+        <item>private.data.openTabs</item>
         <item>private.data.history</item>
         <item>private.data.searchHistory</item>
         <item>private.data.downloadFiles</item>
         <item>private.data.formdata</item>
         <item>private.data.cookies_sessions</item>
         <item>private.data.cache</item>
         <item>private.data.offlineApps</item>
         <item>private.data.siteSettings</item>
@@ -131,16 +135,17 @@
         <item>false</item>
         <item>false</item>
         <item>false</item>
         <item>false</item>
         <item>false</item>
         <item>false</item>
         <item>false</item>
         <item>false</item>
+        <item>false</item>
     </string-array>
     <string-array name="pref_restore_entries">
         <item>@string/pref_restore_always</item>
         <item>@string/pref_restore_quit</item>
     </string-array>
     <string-array name="pref_restore_values">
         <item>always</item>
         <item>quit</item>
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -274,16 +274,17 @@
   <string name="pref_qrcode_enabled_summary">&pref_qrcode_enabled_summary2;</string>
   <string name="pref_restore">&pref_restore_tabs;</string>
   <string name="pref_restore_always">&pref_restore_always;</string>
   <string name="pref_restore_quit">&pref_restore_quit;</string>
   <string name="pref_sync">&pref_sync2;</string>
   <string name="pref_sync_summary">&pref_sync_summary2;</string>
   <string name="pref_search_suggestions">&pref_search_suggestions;</string>
   <string name="pref_history_search_suggestions">&pref_history_search_suggestions;</string>
+  <string name="pref_private_data_openTabs">&pref_private_data_openTabs;</string>
   <string name="pref_private_data_history2">&pref_private_data_history2;</string>
   <string name="pref_private_data_searchHistory">&pref_private_data_searchHistory;</string>
   <string name="pref_private_data_formdata2">&pref_private_data_formdata2;</string>
   <string name="pref_private_data_cookies2">&pref_private_data_cookies2;</string>
   <string name="pref_private_data_passwords">&pref_private_data_passwords2;</string>
   <string name="pref_private_data_cache">&pref_private_data_cache;</string>
   <string name="pref_private_data_offlineApps">&pref_private_data_offlineApps;</string>
   <string name="pref_private_data_siteSettings">&pref_private_data_siteSettings2;</string>
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1465,16 +1465,22 @@ var BrowserApp = {
 
       key = key.replace("private.data.", "");
 
       switch (key) {
         case "cookies_sessions":
           promises.push(Sanitizer.clearItem("cookies"));
           promises.push(Sanitizer.clearItem("sessions"));
           break;
+        case "openTabs":
+          if (aShutdown === true) {
+            Services.obs.notifyObservers(null, "browser:purge-session-tabs", "");
+            break;
+          }
+          // fall-through if aShutdown is false
         default:
           promises.push(Sanitizer.clearItem(key));
       }
     }
 
     Promise.all(promises).then(function() {
       GlobalEventDispatcher.sendRequest({
         type: "Sanitize:Finished",
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -175,16 +175,17 @@ SessionStore.prototype = {
     let self = this;
     let observerService = Services.obs;
     switch (aTopic) {
       case "app-startup":
         observerService.addObserver(this, "final-ui-startup", true);
         observerService.addObserver(this, "domwindowopened", true);
         observerService.addObserver(this, "domwindowclosed", true);
         observerService.addObserver(this, "browser:purge-session-history", true);
+        observerService.addObserver(this, "browser:purge-session-tabs", true);
         observerService.addObserver(this, "quit-application-requested", true);
         observerService.addObserver(this, "quit-application-proceeding", true);
         observerService.addObserver(this, "quit-application", true);
         observerService.addObserver(this, "Session:Restore", true);
         observerService.addObserver(this, "Session:NotifyLocationChange", true);
         observerService.addObserver(this, "Tab:KeepZombified", true);
         observerService.addObserver(this, "application-background", true);
         observerService.addObserver(this, "application-foreground", true);
@@ -231,18 +232,19 @@ SessionStore.prototype = {
         observerService.removeObserver(this, "quit-application-proceeding");
         observerService.removeObserver(this, "quit-application");
 
         // Flush all pending writes to disk now
         this.flushPendingState();
         this._loadState = STATE_QUITTING_FLUSHED;
 
         break;
+      case "browser:purge-session-tabs":
       case "browser:purge-session-history": // catch sanitization
-        log("browser:purge-session-history");
+        log(aTopic);
         this._clearDisk();
 
         // Clear all data about closed tabs
         this._forgetClosedTabs();
 
         if (this._loadState == STATE_RUNNING) {
           // Save the purged state immediately
           this.saveState();
@@ -1775,16 +1777,22 @@ SessionStore.prototype = {
       this._lastClosedTabIndex = -1;
     }
     if (this._notifyClosedTabs) {
       this._sendClosedTabsToJava(aWindow);
     }
   },
 
   _sendClosedTabsToJava: function ss_sendClosedTabsToJava(aWindow) {
+
+    // If the app is shutting down, we don't need to do anything.
+    if (this._loadState <= STATE_QUITTING) {
+      return;
+    }
+
     if (!aWindow.__SSID) {
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
     }
 
     let closedTabs = this._windows[aWindow.__SSID].closedTabs;
     let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(aWindow.BrowserApp.selectedBrowser);
 
     let tabs = closedTabs
--- a/mobile/android/config/proguard/appcompat-v7-keeps.cfg
+++ b/mobile/android/config/proguard/appcompat-v7-keeps.cfg
@@ -4,8 +4,15 @@
 
 -keep public class android.support.v7.widget.** { *; }
 -keep public class android.support.v7.internal.widget.** { *; }
 -keep public class android.support.v7.internal.view.menu.** { *; }
 
 -keep public class * extends android.support.v4.view.ActionProvider {
     public <init>(android.content.Context);
 }
+
+-keepclassmembers class android.support.graphics.drawable.VectorDrawableCompat$* {
+   void set*(***);
+   *** get*();
+}
+
+-keepattributes LocalVariableTable
--- a/mobile/android/modules/Sanitizer.jsm
+++ b/mobile/android/modules/Sanitizer.jsm
@@ -163,16 +163,36 @@ Sanitizer.prototype = {
       get canClear()
       {
         // bug 347231: Always allow clearing history due to dependencies on
         // the browser:purge-session-history notification. (like error console)
         return true;
       }
     },
 
+    openTabs: {
+      clear: function ()
+      {
+        return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:OpenTabs" })
+          .catch(e => Cu.reportError("Java-side tab clearing failed: " + e))
+          .then(function() {
+            try {
+              // clear "Recently Closed" tabs in Android App
+              Services.obs.notifyObservers(null, "browser:purge-session-tabs", "");
+            }
+            catch (e) { }
+          });
+      },
+
+      get canClear()
+      {
+        return true;
+      }
+    },
+
     searchHistory: {
       clear: function ()
       {
         return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:ClearHistory", clearSearchHistory: true })
           .catch(e => Cu.reportError("Java-side search history clearing failed: " + e))
       },
 
       get canClear()
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -1371,16 +1371,45 @@ var AddonManagerInternal = {
         return aMatch;
       }
     });
 
     // escape() does not properly encode + symbols in any embedded FVF strings.
     return uri.replace(/\+/g, "%2B");
   },
 
+  _updatePromptHandler(info) {
+    let oldPerms = info.existingAddon.userPermissions || {hosts: [], permissions: []};
+    let newPerms = info.addon.userPermissions;
+
+    // See bug 1331769: should we do something more complicated to
+    // compare host permissions?
+    // e.g., if we go from <all_urls> to a specific host or from
+    // a *.domain.com to specific-host.domain.com that's actually a
+    // drop in permissions but the simple test below will cause a prompt.
+    let difference = {
+      hosts: newPerms.hosts.filter(perm => !oldPerms.hosts.includes(perm)),
+      permissions: newPerms.permissions.filter(perm => !oldPerms.permissions.includes(perm)),
+    };
+
+    // If there are no new permissions, just go ahead with the update
+    if (difference.hosts.length == 0 && difference.permissions.length == 0) {
+      return Promise.resolve();
+    }
+
+    return new Promise((resolve, reject) => {
+      let subject = {wrappedJSObject: {
+        addon: info.addon,
+        permissions: difference,
+        resolve, reject
+      }};
+      Services.obs.notifyObservers(subject, "webextension-update-permissions", null);
+    });
+  },
+
   /**
    * Performs a background update check by starting an update for all add-ons
    * that can be updated.
    * @return Promise{null} Resolves when the background update check is complete
    *                       (the resulting addon installations may still be in progress).
    */
   backgroundUpdateCheck() {
     if (!gStarted)
@@ -1425,16 +1454,19 @@ var AddonManagerInternal = {
                 // Start installing updates when the add-on can be updated and
                 // background updates should be applied.
                 logger.debug("Found update for add-on ${id}", aAddon);
                 if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE &&
                     AddonManager.shouldAutoUpdate(aAddon)) {
                   // XXX we really should resolve when this install is done,
                   // not when update-available check completes, no?
                   logger.debug(`Starting upgrade install of ${aAddon.id}`);
+                  if (WEBEXT_PERMISSION_PROMPTS) {
+                    aInstall.promptHandler = (...args) => AddonManagerInternal._updatePromptHandler(...args);
+                  }
                   aInstall.install();
                 }
               },
 
               onUpdateFinished: aAddon => { logger.debug("onUpdateFinished for ${id}", aAddon); resolve(); }
             }, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
           }));
         }
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -504,16 +504,20 @@ public:
    */
   bool HasIMEEventMessage() const;
   /**
    * Returns true if the event mMessage is one of plugin activation events.
    */
   bool HasPluginActivationEventMessage() const;
 
   /**
+   * Returns true if the event can be sent to remote process.
+   */
+  bool CanBeSentToRemoteProcess() const;
+  /**
    * Returns true if the event is native event deliverer event for plugin and
    * it should be retarted to focused document.
    */
   bool IsRetargetedNativeEventDelivererForPlugin() const;
   /**
    * Returns true if the event is native event deliverer event for plugin and
    * it should NOT be retarted to focused document.
    */
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -301,50 +301,50 @@ PuppetWidget::Invalidate(const LayoutDev
   if (!mDirtyRegion.IsEmpty() && !mPaintTask.IsPending()) {
     mPaintTask = new PaintTask(this);
     NS_DispatchToCurrentThread(mPaintTask.get());
     return;
   }
 }
 
 void
-PuppetWidget::InitEvent(WidgetGUIEvent& event, LayoutDeviceIntPoint* aPoint)
+PuppetWidget::InitEvent(WidgetGUIEvent& aEvent, LayoutDeviceIntPoint* aPoint)
 {
   if (nullptr == aPoint) {
-    event.mRefPoint = LayoutDeviceIntPoint(0, 0);
+    aEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
   } else {
     // use the point override if provided
-    event.mRefPoint = *aPoint;
+    aEvent.mRefPoint = *aPoint;
   }
-  event.mTime = PR_Now() / 1000;
+  aEvent.mTime = PR_Now() / 1000;
 }
 
 nsresult
-PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
+PuppetWidget::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
 {
 #ifdef DEBUG
-  debug_DumpEvent(stdout, event->mWidget, event, "PuppetWidget", 0);
+  debug_DumpEvent(stdout, aEvent->mWidget, aEvent, "PuppetWidget", 0);
 #endif
 
   MOZ_ASSERT(!mChild || mChild->mWindowType == eWindowType_popup,
              "Unexpected event dispatch!");
 
   AutoCacheNativeKeyCommands autoCache(this);
-  if ((event->mFlags.mIsSynthesizedForTests ||
-       event->mFlags.mIsSuppressedOrDelayed) && !mNativeKeyCommandsValid) {
-    WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
+  if ((aEvent->mFlags.mIsSynthesizedForTests ||
+       aEvent->mFlags.mIsSuppressedOrDelayed) && !mNativeKeyCommandsValid) {
+    WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
     if (keyEvent) {
       mTabChild->RequestNativeKeyBindings(&autoCache, keyEvent);
     }
   }
 
-  if (event->mClass == eCompositionEventClass) {
+  if (aEvent->mClass == eCompositionEventClass) {
     // Store the latest native IME context of parent process's widget or
     // TextEventDispatcher if it's in this process.
-    WidgetCompositionEvent* compositionEvent = event->AsCompositionEvent();
+    WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
 #ifdef DEBUG
     if (mNativeIMEContext.IsValid() &&
         mNativeIMEContext != compositionEvent->mNativeIMEContext) {
       RefPtr<TextComposition> composition =
         IMEStateManager::GetTextCompositionFor(this);
       MOZ_ASSERT(!composition,
         "When there is composition caused by old native IME context, "
         "composition events caused by different native IME context are not "
@@ -352,17 +352,18 @@ PuppetWidget::DispatchEvent(WidgetGUIEve
     }
 #endif // #ifdef DEBUG
     mNativeIMEContext = compositionEvent->mNativeIMEContext;
   }
 
   aStatus = nsEventStatus_eIgnore;
 
   if (GetCurrentWidgetListener()) {
-    aStatus = GetCurrentWidgetListener()->HandleEvent(event, mUseAttachedEvents);
+    aStatus =
+      GetCurrentWidgetListener()->HandleEvent(aEvent, mUseAttachedEvents);
   }
 
   return NS_OK;
 }
 
 nsEventStatus
 PuppetWidget::DispatchInputEvent(WidgetInputEvent* aEvent)
 {
@@ -404,114 +405,121 @@ PuppetWidget::SynthesizeNativeKeyEvent(i
                                        const nsAString& aUnmodifiedCharacters,
                                        nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "keyevent");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendSynthesizeNativeKeyEvent(aNativeKeyboardLayout, aNativeKeyCode,
-    aModifierFlags, nsString(aCharacters), nsString(aUnmodifiedCharacters),
-    notifier.SaveObserver());
+                                          aModifierFlags, nsString(aCharacters),
+                                          nsString(aUnmodifiedCharacters),
+                                          notifier.SaveObserver());
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::SynthesizeNativeMouseEvent(mozilla::LayoutDeviceIntPoint aPoint,
                                          uint32_t aNativeMessage,
                                          uint32_t aModifierFlags,
                                          nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "mouseevent");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendSynthesizeNativeMouseEvent(aPoint, aNativeMessage,
-    aModifierFlags, notifier.SaveObserver());
+                                            aModifierFlags,
+                                            notifier.SaveObserver());
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::SynthesizeNativeMouseMove(mozilla::LayoutDeviceIntPoint aPoint,
                                         nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "mousemove");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendSynthesizeNativeMouseMove(aPoint, notifier.SaveObserver());
   return NS_OK;
 }
 
 nsresult
-PuppetWidget::SynthesizeNativeMouseScrollEvent(mozilla::LayoutDeviceIntPoint aPoint,
-                                               uint32_t aNativeMessage,
-                                               double aDeltaX,
-                                               double aDeltaY,
-                                               double aDeltaZ,
-                                               uint32_t aModifierFlags,
-                                               uint32_t aAdditionalFlags,
-                                               nsIObserver* aObserver)
+PuppetWidget::SynthesizeNativeMouseScrollEvent(
+                mozilla::LayoutDeviceIntPoint aPoint,
+                uint32_t aNativeMessage,
+                double aDeltaX,
+                double aDeltaY,
+                double aDeltaZ,
+                uint32_t aModifierFlags,
+                uint32_t aAdditionalFlags,
+                nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "mousescrollevent");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendSynthesizeNativeMouseScrollEvent(aPoint, aNativeMessage,
-    aDeltaX, aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags,
-    notifier.SaveObserver());
+                                                  aDeltaX, aDeltaY, aDeltaZ,
+                                                  aModifierFlags,
+                                                  aAdditionalFlags,
+                                                  notifier.SaveObserver());
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::SynthesizeNativeTouchPoint(uint32_t aPointerId,
                                          TouchPointerState aPointerState,
                                          LayoutDeviceIntPoint aPoint,
                                          double aPointerPressure,
                                          uint32_t aPointerOrientation,
                                          nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "touchpoint");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendSynthesizeNativeTouchPoint(aPointerId, aPointerState,
-    aPoint, aPointerPressure, aPointerOrientation,
-    notifier.SaveObserver());
+                                            aPoint, aPointerPressure,
+                                            aPointerOrientation,
+                                            notifier.SaveObserver());
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::SynthesizeNativeTouchTap(LayoutDeviceIntPoint aPoint,
                                        bool aLongTap,
                                        nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "touchtap");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendSynthesizeNativeTouchTap(aPoint, aLongTap,
-    notifier.SaveObserver());
+                                          notifier.SaveObserver());
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::ClearNativeTouchSequence(nsIObserver* aObserver)
 {
   AutoObserverNotifier notifier(aObserver, "cleartouch");
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendClearNativeTouchSequence(notifier.SaveObserver());
   return NS_OK;
 }
  
 void
-PuppetWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId,
-                                     const nsTArray<ScrollableLayerGuid>& aTargets) const
+PuppetWidget::SetConfirmedTargetAPZC(
+                uint64_t aInputBlockId,
+                const nsTArray<ScrollableLayerGuid>& aTargets) const
 {
   if (mTabChild) {
     mTabChild->SetTargetAPZC(aInputBlockId, aTargets);
   }
 }
 
 void
 PuppetWidget::UpdateZoomConstraints(const uint32_t& aPresShellId,
@@ -525,25 +533,22 @@ PuppetWidget::UpdateZoomConstraints(cons
 
 bool
 PuppetWidget::AsyncPanZoomEnabled() const
 {
   return mTabChild && mTabChild->AsyncPanZoomEnabled();
 }
 
 bool
-PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType,
-                                      const mozilla::WidgetKeyboardEvent& aEvent,
-                                      DoCommandCallback aCallback,
-                                      void* aCallbackData)
+PuppetWidget::ExecuteNativeKeyBinding(
+                NativeKeyBindingsType aType,
+                const mozilla::WidgetKeyboardEvent& aEvent,
+                DoCommandCallback aCallback,
+                void* aCallbackData)
 {
-  // B2G doesn't have native key bindings.
-#ifdef MOZ_WIDGET_GONK
-  return false;
-#else // #ifdef MOZ_WIDGET_GONK
   AutoCacheNativeKeyCommands autoCache(this);
   if (!aEvent.mWidget && !mNativeKeyCommandsValid) {
     MOZ_ASSERT(!aEvent.mFlags.mIsSynthesizedForTests);
     // Abort if untrusted to avoid leaking system settings
     if (NS_WARN_IF(!aEvent.IsTrusted())) {
       return false;
     }
     mTabChild->RequestNativeKeyBindings(&autoCache, &aEvent);
@@ -570,17 +575,16 @@ PuppetWidget::ExecuteNativeKeyBinding(Na
   if (commands->IsEmpty()) {
     return false;
   }
 
   for (uint32_t i = 0; i < commands->Length(); i++) {
     aCallback(static_cast<mozilla::Command>((*commands)[i]), aCallbackData);
   }
   return true;
-#endif
 }
 
 LayerManager*
 PuppetWidget::GetLayerManager(PLayerTransactionChild* aShadowManager,
                               LayersBackend aBackendHint,
                               LayerManagerPersistence aPersistence)
 {
   if (!mLayerManager) {
@@ -601,17 +605,16 @@ PuppetWidget::RecreateLayerManager(PLaye
     lf->SetShadowManager(aShadowManager);
   }
   return mLayerManager;
 }
 
 nsresult
 PuppetWidget::RequestIMEToCommitComposition(bool aCancel)
 {
-#ifdef MOZ_CROSS_PROCESS_IME
   if (!mTabChild) {
     return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(!Destroyed());
 
   // There must not be composition which is caused by the PuppetWidget instance.
   if (NS_WARN_IF(!mNativeIMEContext.IsValid())) {
@@ -641,19 +644,16 @@ PuppetWidget::RequestIMEToCommitComposit
   // Dispatch eCompositionCommit event.
   WidgetCompositionEvent compositionCommitEvent(true, eCompositionCommit, this);
   InitEvent(compositionCommitEvent, nullptr);
   compositionCommitEvent.mData = committedString;
   nsEventStatus status = nsEventStatus_eIgnore;
   DispatchEvent(&compositionCommitEvent, status);
 
   // NOTE: PuppetWidget might be destroyed already.
-
-#endif // #ifdef MOZ_CROSS_PROCESS_IME
-
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
 {
   switch (aIMENotification.mMessage) {
     case REQUEST_TO_COMMIT_COMPOSITION:
@@ -712,41 +712,32 @@ void
 PuppetWidget::SetInputContext(const InputContext& aContext,
                               const InputContextAction& aAction)
 {
   mInputContext = aContext;
   // Any widget instances cannot cache IME open state because IME open state
   // can be changed by user but native IME may not notify us of changing the
   // open state on some platforms.
   mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
-
-#ifndef MOZ_CROSS_PROCESS_IME
-  return;
-#endif
-
   if (!mTabChild) {
     return;
   }
   mTabChild->SendSetInputContext(
     static_cast<int32_t>(aContext.mIMEState.mEnabled),
     static_cast<int32_t>(aContext.mIMEState.mOpen),
     aContext.mHTMLInputType,
     aContext.mHTMLInputInputmode,
     aContext.mActionHint,
     static_cast<int32_t>(aAction.mCause),
     static_cast<int32_t>(aAction.mFocusChange));
 }
 
 InputContext
 PuppetWidget::GetInputContext()
 {
-#ifndef MOZ_CROSS_PROCESS_IME
-  return InputContext();
-#endif
-
   // XXX Currently, we don't support retrieving IME open state from child
   //     process.
 
   // When this widget caches input context and currently managed by
   // IMEStateManager, the cache is valid.  Only in this case, we can
   // avoid to use synchronous IPC.
   if (mInputContext.mIMEState.mEnabled != IMEState::UNKNOWN &&
       IMEStateManager::GetWidgetForActiveInputContext() == this) {
@@ -772,22 +763,19 @@ NativeIMEContext
 PuppetWidget::GetNativeIMEContext()
 {
   return mNativeIMEContext;
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfFocusChange(const IMENotification& aIMENotification)
 {
-#ifndef MOZ_CROSS_PROCESS_IME
-  return NS_OK;
-#endif
-
-  if (!mTabChild)
+  if (!mTabChild) {
     return NS_ERROR_FAILURE;
+  }
 
   bool gotFocus = aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS;
   if (gotFocus) {
     if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN) {
       // When IME gets focus, we should initalize all information of the
       // content.
       if (NS_WARN_IF(!mContentCache.CacheAll(this, &aIMENotification))) {
         return NS_ERROR_FAILURE;
@@ -811,66 +799,55 @@ PuppetWidget::NotifyIMEOfFocusChange(con
   }
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfCompositionUpdate(
                 const IMENotification& aIMENotification)
 {
-#ifndef MOZ_CROSS_PROCESS_IME
-  return NS_OK;
-#endif
-
-  NS_ENSURE_TRUE(mTabChild, NS_ERROR_FAILURE);
+  if (NS_WARN_IF(!mTabChild)) {
+    return NS_ERROR_FAILURE;
+  }
 
   if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
       NS_WARN_IF(!mContentCache.CacheSelection(this, &aIMENotification))) {
     return NS_ERROR_FAILURE;
   }
   mTabChild->SendNotifyIMECompositionUpdate(mContentCache, aIMENotification);
   return NS_OK;
 }
 
 nsIMEUpdatePreference
 PuppetWidget::GetIMEUpdatePreference()
 {
-#ifdef MOZ_CROSS_PROCESS_IME
   // e10s requires IME content cache in in the TabParent for handling query
   // content event only with the parent process.  Therefore, this process
   // needs to receive a lot of information from the focused editor to sent
   // the latest content to the parent process.
   if (mInputContext.mIMEState.mEnabled == IMEState::PLUGIN) {
     // But if a plugin has focus, we cannot receive text nor selection change
     // in the plugin.  Therefore, PuppetWidget needs to receive only position
     // change event for updating the editor rect cache.
     return nsIMEUpdatePreference(mIMEPreferenceOfParent.mWantUpdates |
                                  nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE);
   }
   return nsIMEUpdatePreference(mIMEPreferenceOfParent.mWantUpdates |
                                nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE |
                                nsIMEUpdatePreference::NOTIFY_POSITION_CHANGE );
-#else
-  // B2G doesn't handle IME as widget-level.
-  return nsIMEUpdatePreference();
-#endif
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfTextChange(const IMENotification& aIMENotification)
 {
   MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE,
              "Passed wrong notification");
-
-#ifndef MOZ_CROSS_PROCESS_IME
-  return NS_OK;
-#endif
-
-  if (!mTabChild)
+  if (!mTabChild) {
     return NS_ERROR_FAILURE;
+  }
 
   // While a plugin has focus, text change notification shouldn't be available.
   if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
     return NS_ERROR_FAILURE;
   }
 
   // FYI: text change notification is the first notification after
   //      a user operation changes the content.  So, we need to modify
@@ -891,23 +868,19 @@ PuppetWidget::NotifyIMEOfTextChange(cons
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfSelectionChange(
                 const IMENotification& aIMENotification)
 {
   MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE,
              "Passed wrong notification");
-
-#ifndef MOZ_CROSS_PROCESS_IME
-  return NS_OK;
-#endif
-
-  if (!mTabChild)
+  if (!mTabChild) {
     return NS_ERROR_FAILURE;
+  }
 
   // While a plugin has focus, selection change notification shouldn't be
   // available.
   if (NS_WARN_IF(mInputContext.mIMEState.mEnabled == IMEState::PLUGIN)) {
     return NS_ERROR_FAILURE;
   }
 
   // Note that selection change must be notified after text change if it occurs.
@@ -946,19 +919,16 @@ PuppetWidget::NotifyIMEOfMouseButtonEven
   }
 
   return consumedByIME ? NS_SUCCESS_EVENT_CONSUMED : NS_OK;
 }
 
 nsresult
 PuppetWidget::NotifyIMEOfPositionChange(const IMENotification& aIMENotification)
 {
-#ifndef MOZ_CROSS_PROCESS_IME
-  return NS_OK;
-#endif
   if (NS_WARN_IF(!mTabChild)) {
     return NS_ERROR_FAILURE;
   }
 
   if (NS_WARN_IF(!mContentCache.CacheEditorRect(this, &aIMENotification))) {
     return NS_ERROR_FAILURE;
   }
   // While a plugin has focus, selection range isn't available.  So, we don't
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -309,16 +309,51 @@ WidgetEvent::HasPluginActivationEventMes
 
 /******************************************************************************
  * mozilla::WidgetEvent
  *
  * Specific event checking methods.
  ******************************************************************************/
 
 bool
+WidgetEvent::CanBeSentToRemoteProcess() const
+{
+  // If this event is explicitly marked as shouldn't be sent to remote process,
+  // just return false.
+  if (mFlags.mNoCrossProcessBoundaryForwarding) {
+    return false;
+  }
+
+  if (mClass == eKeyboardEventClass ||
+      mClass == eWheelEventClass) {
+    return true;
+  }
+
+  switch (mMessage) {
+    case eMouseDown:
+    case eMouseUp:
+    case eMouseMove:
+    case eContextMenu:
+    case eMouseEnterIntoWidget:
+    case eMouseExitFromWidget:
+    case eMouseTouchDrag:
+    case eTouchStart:
+    case eTouchMove:
+    case eTouchEnd:
+    case eTouchCancel:
+    case eDragOver:
+    case eDragExit:
+    case eDrop:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool
 WidgetEvent::IsRetargetedNativeEventDelivererForPlugin() const
 {
   const WidgetPluginEvent* pluginEvent = AsPluginEvent();
   return pluginEvent && pluginEvent->mRetargetToFocusedDocument;
 }
 
 bool
 WidgetEvent::IsNonRetargetedNativeEventDelivererForPlugin() const