Merge m-c to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 17 Apr 2014 12:55:12 +0200
changeset 197515 dd8f5ea32834fc3d1186ad75ee965daefdee2265
parent 197514 15844988512f1e1c6342c56cfd44cb7697502e04 (current diff)
parent 197500 c55dfb01a02757b15d5c5d1f2bfec4310d0232fc (diff)
child 197516 5453dbdd4897c0602e44677a0c8896978c3096f0
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.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 m-c to b2g-inbound
services/fxaccounts/FxAccountsUtils.jsm
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -1431,25 +1431,31 @@ nsAccessibilityService::CreateHTMLAccess
       }
     }
 
     return nullptr;
   }
 
   if (tag == nsGkAtoms::abbr ||
       tag == nsGkAtoms::acronym ||
+      tag == nsGkAtoms::article ||
+      tag == nsGkAtoms::aside ||
       tag == nsGkAtoms::blockquote ||
       tag == nsGkAtoms::form ||
+      tag == nsGkAtoms::footer ||
+      tag == nsGkAtoms::header ||
       tag == nsGkAtoms::h1 ||
       tag == nsGkAtoms::h2 ||
       tag == nsGkAtoms::h3 ||
       tag == nsGkAtoms::h4 ||
       tag == nsGkAtoms::h5 ||
       tag == nsGkAtoms::h6 ||
-      tag == nsGkAtoms::q) {
+      tag == nsGkAtoms::nav ||
+      tag == nsGkAtoms::q ||
+      tag == nsGkAtoms::section) {
     nsRefPtr<Accessible> accessible =
       new HyperTextAccessibleWrap(aContent, document);
     return accessible.forget();
   }
 
   if (tag == nsGkAtoms::label) {
     nsRefPtr<Accessible> accessible =
       new HTMLLabelAccessible(aContent, document);
--- a/accessible/src/jsat/Constants.jsm
+++ b/accessible/src/jsat/Constants.jsm
@@ -1,14 +1,15 @@
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 
-this.EXPORTED_SYMBOLS = ['Roles', 'Events', 'Relations', 'Filters', 'States'];
+this.EXPORTED_SYMBOLS = ['Roles', 'Events', 'Relations',
+                         'Filters', 'States', 'Prefilters'];
 
 function ConstantsMap (aObject, aPrefix, aMap = {}, aModifier = null) {
   let offset = aPrefix.length;
   for (var name in aObject) {
     if (name.indexOf(aPrefix) === 0) {
       aMap[name.slice(offset)] = aModifier ?
         aModifier(aObject[name]) : aObject[name];
     }
@@ -31,16 +32,22 @@ XPCOMUtils.defineLazyGetter(
 
 XPCOMUtils.defineLazyGetter(
   this, 'Relations',
   function() {
     return ConstantsMap(Ci.nsIAccessibleRelation, 'RELATION_');
   });
 
 XPCOMUtils.defineLazyGetter(
+  this, 'Prefilters',
+  function() {
+    return ConstantsMap(Ci.nsIAccessibleTraversalRule, 'PREFILTER_');
+  });
+
+XPCOMUtils.defineLazyGetter(
   this, 'Filters',
   function() {
     return ConstantsMap(Ci.nsIAccessibleTraversalRule, 'FILTER_');
   });
 
 XPCOMUtils.defineLazyGetter(
   this, 'States',
   function() {
--- a/accessible/src/jsat/TraversalRules.jsm
+++ b/accessible/src/jsat/TraversalRules.jsm
@@ -14,16 +14,18 @@ this.EXPORTED_SYMBOLS = ['TraversalRules
 Cu.import('resource://gre/modules/accessibility/Utils.jsm');
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Roles',
   'resource://gre/modules/accessibility/Constants.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'Filters',
   'resource://gre/modules/accessibility/Constants.jsm');
 XPCOMUtils.defineLazyModuleGetter(this, 'States',
   'resource://gre/modules/accessibility/Constants.jsm');
+XPCOMUtils.defineLazyModuleGetter(this, 'Prefilters',
+  'resource://gre/modules/accessibility/Constants.jsm');
 
 let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images');
 
 function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter) {
   this._explicitMatchRoles = new Set(aRoles);
   this._matchRoles = aRoles;
   if (aRoles.indexOf(Roles.LABEL) < 0) {
     this._matchRoles.push(Roles.LABEL);
@@ -141,31 +143,28 @@ var gSimpleMatchFunc = function gSimpleM
   default:
     // Ignore the subtree, if there is one. So that we don't land on
     // the same content that was already presented by its parent.
     return Filters.MATCH |
       Filters.IGNORE_SUBTREE;
   }
 };
 
-var gSimplePreFilter = Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
-  Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE |
-  Ci.nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN |
-  Ci.nsIAccessibleTraversalRule.PREFILTER_TRANSPARENT;
+var gSimplePreFilter = Prefilters.DEFUNCT |
+  Prefilters.INVISIBLE |
+  Prefilters.ARIA_HIDDEN |
+  Prefilters.TRANSPARENT;
 
 this.TraversalRules = {
   Simple: new BaseTraversalRule(gSimpleTraversalRoles, gSimpleMatchFunc),
 
   SimpleOnScreen: new BaseTraversalRule(
     gSimpleTraversalRoles, gSimpleMatchFunc,
-    Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
-      Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE |
-      Ci.nsIAccessibleTraversalRule.PREFILTER_ARIA_HIDDEN |
-      Ci.nsIAccessibleTraversalRule.PREFILTER_TRANSPARENT |
-      Ci.nsIAccessibleTraversalRule.PREFILTER_OFFSCREEN),
+    Prefilters.DEFUNCT | Prefilters.INVISIBLE | Prefilters.ARIA_HIDDEN |
+    Prefilters.TRANSPARENT | Prefilters.OFFSCREEN),
 
   Anchor: new BaseTraversalRule(
     [Roles.LINK],
     function Anchor_match(aAccessible)
     {
       // We want to ignore links, only focus named anchors.
       if (Utils.getState(aAccessible).contains(States.LINKED)) {
         return Filters.IGNORE;
--- a/accessible/tests/mochitest/role/test_general.html
+++ b/accessible/tests/mochitest/role/test_general.html
@@ -24,16 +24,25 @@
       // Test html:form.
       testRole("nav", ROLE_SECTION);
       testRole("header", ROLE_HEADER);
       testRole("footer", ROLE_FOOTER);
       testRole("article", ROLE_DOCUMENT);
       testRole("aside", ROLE_NOTE);
       testRole("section", ROLE_SECTION);
 
+      // Bug 996821
+      // Check that landmark elements get accessibles with styled overflow.
+      testRole("section_overflow", ROLE_SECTION);
+      testRole("nav_overflow", ROLE_SECTION);
+      testRole("header_overflow", ROLE_HEADER);
+      testRole("aside_overflow", ROLE_NOTE);
+      testRole("footer_overflow", ROLE_FOOTER);
+      testRole("article_overflow", ROLE_DOCUMENT);
+
       // test html:div
       testRole("sec", ROLE_SECTION);
 
       // Test html:blockquote
       testRole("quote", ROLE_SECTION);
 
       // Test html:h, all levels
       testRole("head1", ROLE_HEADING);
@@ -122,16 +131,29 @@
 
   <nav id="nav">a nav</nav>
   <header id="header">a header</header>
   <footer id="footer">a footer</footer>
   <article id="article">an article</article>
   <aside id="aside">by the way I am an aside</aside>
   <section id="section">a section</section>
 
+  <section style="overflow: hidden;" id="section_overflow">
+    <nav style="overflow: hidden;"
+         id="nav_overflow">overflow nav</nav>
+    <header style="overflow: hidden;"
+            id="header_overflow">overflow header</header>
+    <aside style="overflow: hidden;"
+           id="aside_overflow">overflow aside</aside>
+    <footer style="overflow: hidden;"
+            id="footer_overflow">overflow footer</footer>
+  </section>
+  <article style="overflow: hidden;"
+           id="article_overflow">overflow article</article>
+
   <p id="p">A paragraph for comparison.</p>
   <div id="sec">A normal div</div>
   <blockquote id="quote">A citation</blockquote>
   <h1 id="head1">A heading level 1</h1>
   <h2 id="head2">A heading level 2</h2>
   <h3 id="head3">A heading level 3</h3>
   <h4 id="head4">A heading level 4</h4>
   <h5 id="head5">A heading level 5</h5>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1420,16 +1420,18 @@ pref("ui.key.menuAccessKeyFocuses", true
 
 // Delete HTTP cache v2 data of users that didn't opt-in manually
 pref("browser.cache.auto_delete_cache_version", 1);
 // Play with different values of the decay time and get telemetry,
 // 0 means to randomize (and persist) the experiment value in users' profiles,
 // -1 means no experiment is run and we use the preferred value for frecency (6h)
 pref("browser.cache.frecency_experiment", 0);
 
+pref("browser.translation.detectLanguage", false);
+
 // Telemetry experiments settings.
 pref("experiments.enabled", false);
 pref("experiments.manifest.fetchIntervalSeconds", 86400);
 pref("experiments.manifest.uri", "https://telemetry-experiment.cdn.mozilla.net/manifest/v1/firefox/%VERSION%/%CHANNEL%");
 pref("experiments.manifest.certs.1.commonName", "*.cdn.mozilla.net");
 pref("experiments.manifest.certs.1.issuerName", "CN=Cybertrust Public SureServer SV CA,O=Cybertrust Inc");
 // Whether experiments are supported by the current application profile.
 pref("experiments.supported", true);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -142,16 +142,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource:///modules/BrowserNewTabPreloader.jsm", "BrowserNewTabPreloader");
 
 XPCOMUtils.defineLazyModuleGetter(this, "gCustomizationTabPreloader",
   "resource:///modules/CustomizationTabPreloader.jsm", "CustomizationTabPreloader");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "Translation",
+  "resource:///modules/translation/Translation.jsm");
+
 XPCOMUtils.defineLazyModuleGetter(this, "SitePermissions",
   "resource:///modules/SitePermissions.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
   "resource:///modules/sessionstore/SessionStore.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
   "resource://gre/modules/FxAccounts.jsm");
@@ -1028,16 +1031,17 @@ var gBrowserInit = {
     Services.obs.addObserver(gFormSubmitObserver, "invalidformsubmit", false);
 
     BrowserOffline.init();
     OfflineApps.init();
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
     gRemoteTabsUI.init();
     gPageStyleMenu.init();
+    LanguageDetectionListener.init();
 
     // Initialize the full zoom setting.
     // We do this before the session restore service gets initialized so we can
     // apply full zoom settings to tabs restored by the session restore service.
     FullZoom.init();
     PanelUI.init();
     LightweightThemeListener.init();
     WebrtcIndicator.init();
@@ -4459,19 +4463,16 @@ var TabsInTitlebar = {
     for (let something in this._disallowed) {
       allowed = false;
       break;
     }
 
     let titlebar = $("titlebar");
     let titlebarContent = $("titlebar-content");
     let menubar = $("toolbar-menubar");
-#ifdef XP_MACOSX
-    let secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
-#endif
 
     if (allowed) {
       // We set the tabsintitlebar attribute first so that our CSS for
       // tabsintitlebar manifests before we do our measurements.
       document.documentElement.setAttribute("tabsintitlebar", "true");
       updateTitlebarDisplay();
 
       // Try to avoid reflows in this code by calculating dimensions first and
@@ -4479,16 +4480,17 @@ var TabsInTitlebar = {
 
       // Get the full height of the tabs toolbar:
       let tabsToolbar = $("TabsToolbar");
       let fullTabsHeight = rect(tabsToolbar).height;
       // Buttons first:
       let captionButtonsBoxWidth = rect($("titlebar-buttonbox-container")).width;
 
 #ifdef XP_MACOSX
+      let secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
       // No need to look up the menubar stuff on OS X:
       let menuHeight = 0;
       let fullMenuHeight = 0;
       // Instead, look up the titlebar padding:
       let titlebarPadding = parseInt(window.getComputedStyle(titlebar).paddingTop, 10);
 #else
       // Otherwise, get the height and margins separately for the menubar
       let menuHeight = rect(menubar).height;
@@ -4553,16 +4555,19 @@ var TabsInTitlebar = {
         titlebarContentHeight += extraMargin;
       }
 
       // Then we bring up the titlebar by the same amount, but we add any negative margin:
       titlebar.style.marginBottom = "-" + titlebarContentHeight + "px";
 
 
       // Finally, size the placeholders:
+#ifdef XP_MACOSX
+      this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
+#endif
       this._sizePlaceholder("caption-buttons", captionButtonsBoxWidth);
 
       if (!this._draghandles) {
         this._draghandles = {};
         let tmp = {};
         Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
 
         let mouseDownCheck = function () {
@@ -4574,26 +4579,26 @@ var TabsInTitlebar = {
 
         this._draghandles.navToolbox = new tmp.WindowDraggingElement(gNavToolbox);
         this._draghandles.navToolbox.mouseDownCheck = mouseDownCheck;
       }
     } else {
       document.documentElement.removeAttribute("tabsintitlebar");
       updateTitlebarDisplay();
 
+#ifdef XP_MACOSX
+      let secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
+      this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
+#endif
       // Reset the margins and padding that might have been modified:
       titlebarContent.style.marginTop = "";
       titlebarContent.style.marginBottom = "";
       titlebar.style.marginBottom = "";
       menubar.style.paddingBottom = "";
     }
-
-#ifdef XP_MACOSX
-    this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
-#endif
   },
 
   _sizePlaceholder: function (type, width) {
     Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='"+ type +"']"),
                   function (node) { node.width = width; });
   },
 #endif
 
@@ -5337,16 +5342,25 @@ function stylesheetSwitchAll(contentWind
   gPageStyleMenu.switchStyleSheet(title);
 }
 function setStyleDisabled(disabled) {
   if (disabled)
     gPageStyleMenu.disableStyle();
 }
 
 
+var LanguageDetectionListener = {
+  init: function() {
+    window.messageManager.addMessageListener("LanguageDetection:Result", msg => {
+      Translation.languageDetected(msg.target, msg.data);
+    });
+  }
+};
+
+
 var BrowserOffline = {
   _inited: false,
 
   /////////////////////////////////////////////////////////////////////////////
   // BrowserOffline Public Methods
   init: function ()
   {
     if (!this._uiElement)
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -7,16 +7,18 @@ let Cc = Components.classes;
 let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentLinkHandler",
   "resource:///modules/ContentLinkHandler.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
+  "resource:///modules/translation/LanguageDetector.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
   "resource://gre/modules/LoginManagerContent.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "InsecurePasswordUtils",
   "resource://gre/modules/InsecurePasswordUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UITour",
   "resource:///modules/UITour.jsm");
@@ -382,8 +384,54 @@ let PageStyleHandler = {
       result.push({title: currentStyleSheet.title,
                    disabled: currentStyleSheet.disabled});
     }
 
     return result;
   },
 };
 PageStyleHandler.init();
+
+let TranslationHandler = {
+  init: function() {
+    let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIWebProgress);
+    webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
+  },
+
+  /* nsIWebProgressListener implementation */
+  onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
+    if (!aWebProgress.isTopLevel ||
+        !(aStateFlags & Ci.nsIWebProgressListener.STATE_STOP))
+      return;
+
+    let url = aRequest.name;
+    if (!url.startsWith("http://") && !url.startsWith("https://"))
+      return;
+
+    // Grab a 60k sample of text from the page.
+    let encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
+                    .createInstance(Ci.nsIDocumentEncoder);
+    encoder.init(content.document, "text/plain", encoder.SkipInvisibleContent);
+    let string = encoder.encodeToStringWithMaxLength(60 * 1024);
+
+    // Language detection isn't reliable on very short strings.
+    if (string.length < 100)
+      return;
+
+    LanguageDetector.detectLanguage(string).then(result => {
+      if (result.confident)
+        sendAsyncMessage("LanguageDetection:Result", result.language);
+    });
+  },
+
+  // Unused methods.
+  onProgressChange: function() {},
+  onLocationChange: function() {},
+  onStatusChange:   function() {},
+  onSecurityChange: function() {},
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+                                         Ci.nsISupportsWeakReference])
+};
+
+if (Services.prefs.getBoolPref("browser.translation.detectLanguage"))
+  TranslationHandler.init();
--- a/browser/components/preferences/in-content/main.xul
+++ b/browser/components/preferences/in-content/main.xul
@@ -29,24 +29,24 @@
                 name="browser.privatebrowsing.autostart"
                 type="bool"
                 onchange="gMainPane.updateBrowserStartupLastSession();"/>
 
     <!-- Downloads -->
     <preference id="browser.download.useDownloadDir"
                 name="browser.download.useDownloadDir"
                 type="bool"/>
+
+    <preference id="browser.download.folderList"
+                name="browser.download.folderList"
+                type="int"/>
     <preference id="browser.download.dir"
                 name="browser.download.dir"
                 type="file"
                 onchange="gMainPane.displayDownloadDirPref();"/>
-    <preference id="browser.download.folderList"
-                name="browser.download.folderList"
-                type="int"/>
-
     <!-- Tab preferences 
     Preferences:
 
     browser.link.open_newwindow
         1 opens such links in the most recent window or tab,
         2 opens such links in a new window,
         3 opens such links in a new tab
     browser.tabs.loadInBackground
--- a/browser/components/translation/Translation.jsm
+++ b/browser/components/translation/Translation.jsm
@@ -6,63 +6,69 @@
 
 this.EXPORTED_SYMBOLS = ["Translation"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "LanguageDetector",
-  "resource:///modules/translation/LanguageDetector.jsm");
+
+this.Translation = {
+  supportedSourceLanguages: ["en", "zh", "ja", "es", "de", "fr", "ru", "ar", "ko", "pt"],
+  supportedTargetLanguages: ["en", "pl", "tr", "vi"],
 
-/* Create an object keeping the information related to translation for
+  _defaultTargetLanguage: "",
+  get defaultTargetLanguage() {
+    if (!this._defaultTargetLanguage) {
+      this._defaultTargetLanguage = Cc["@mozilla.org/chrome/chrome-registry;1"]
+                                      .getService(Ci.nsIXULChromeRegistry)
+                                      .getSelectedLocale("global")
+                                      .split("-")[0];
+    }
+    return this._defaultTargetLanguage;
+  },
+
+  languageDetected: function(aBrowser, aDetectedLanguage) {
+    if (this.supportedSourceLanguages.indexOf(aDetectedLanguage) != -1 &&
+        aDetectedLanguage != this.defaultTargetLanguage) {
+      if (!aBrowser.translationUI)
+        aBrowser.translationUI = new TranslationUI(aBrowser);
+
+      aBrowser.translationUI.showTranslationUI(aDetectedLanguage);
+    }
+  }
+};
+
+/* TranslationUI objects keep the information related to translation for
  * a specific browser.  This object is passed to the translation
  * infobar so that it can initialize itself.  The properties exposed to
  * the infobar are:
- * - supportedSourceLanguages, array of supported source language codes
- * - supportedTargetLanguages, array of supported target language codes
  * - detectedLanguage, code of the language detected on the web page.
- * - defaultTargetLanguage, code of the language to use by default for
- *   translation.
  * - state, the state in which the infobar should be displayed
  * - STATE_{OFFER,TRANSLATING,TRANSLATED,ERROR} constants.
  * - translatedFrom, if already translated, source language code.
  * - translatedTo, if already translated, target language code.
  * - translate, method starting the translation of the current page.
  * - showOriginalContent, method showing the original page content.
  * - showTranslatedContent, method showing the translation for an
  *   already translated page whose original content is shown.
  * - originalShown, boolean indicating if the original or translated
  *   version of the page is shown.
  */
-this.Translation = function(aBrowser) {
+function TranslationUI(aBrowser) {
   this.browser = aBrowser;
-};
+}
 
-this.Translation.prototype = {
-  supportedSourceLanguages: ["en", "zh", "ja", "es", "de", "fr", "ru", "ar", "ko", "pt"],
-  supportedTargetLanguages: ["en", "pl", "tr", "vi"],
-
+TranslationUI.prototype = {
   STATE_OFFER: 0,
   STATE_TRANSLATING: 1,
   STATE_TRANSLATED: 2,
   STATE_ERROR: 3,
 
-  _defaultTargetLanguage: "",
-  get defaultTargetLanguage() {
-    if (!this._defaultTargetLanguage) {
-      this._defaultTargetLanguage = Cc["@mozilla.org/chrome/chrome-registry;1"]
-                                      .getService(Ci.nsIXULChromeRegistry)
-                                      .getSelectedLocale("global")
-                                      .split("-")[0];
-    }
-    return this._defaultTargetLanguage;
-  },
-
   get doc() this.browser.contentDocument,
 
   translate: function(aFrom, aTo) {
     this.state = this.STATE_TRANSLATING;
     this.translatedFrom = aFrom;
     this.translatedTo = aTo;
   },
 
--- a/browser/components/translation/test/browser_translation_infobar.js
+++ b/browser/components/translation/test/browser_translation_infobar.js
@@ -24,18 +24,16 @@ function waitForCondition(condition, nex
       moveOn();
     }
     tries++;
   }, 100);
   var moveOn = function() { clearInterval(interval); nextTest(); };
 }
 
 var TranslationStub = {
-  __proto__: Translation.prototype,
-
   translate: function(aFrom, aTo) {
     this.state = this.STATE_TRANSLATING;
     this.translatedFrom = aFrom;
     this.translatedTo = aTo;
   },
 
   _reset: function() {
     this.translatedFrom = "";
@@ -49,16 +47,24 @@ var TranslationStub = {
 
   finishTranslation: function() {
     this.showTranslatedContent();
     this.state = this.STATE_TRANSLATED;
     this._reset();
   }
 };
 
+function showTranslationUI(aDetectedLanguage) {
+  let browser = gBrowser.selectedBrowser;
+  Translation.languageDetected(browser, aDetectedLanguage);
+  let ui = browser.translationUI;
+  for (let name of ["translate", "_reset", "failTranslation", "finishTranslation"])
+    ui[name] = TranslationStub[name];
+  return ui.notificationBox.getNotificationWithValue("translation");
+}
 
 function test() {
   waitForExplicitFinish();
 
   let tab = gBrowser.addTab();
   gBrowser.selectedTab = tab;
   tab.linkedBrowser.addEventListener("load", function onload() {
     tab.linkedBrowser.removeEventListener("load", onload, true);
@@ -78,45 +84,45 @@ function checkURLBarIcon(aExpectTranslat
   is(!PopupNotifications.getNotification("translate"), aExpectTranslated,
      "translate icon " + (aExpectTranslated ? "not " : "") + "shown");
   is(!!PopupNotifications.getNotification("translated"), aExpectTranslated,
      "translated icon " + (aExpectTranslated ? "" : "not ") + "shown");
 }
 
 function run_tests(aFinishCallback) {
   info("Show an info bar saying the current page is in French");
-  let notif = TranslationStub.showTranslationUI("fr");
-  is(notif.state, TranslationStub.STATE_OFFER, "the infobar is offering translation");
+  let notif = showTranslationUI("fr");
+  is(notif.state, notif.translation.STATE_OFFER, "the infobar is offering translation");
   is(notif._getAnonElt("detectedLanguage").value, "fr", "The detected language is displayed");
   checkURLBarIcon();
 
   info("Click the 'Translate' button");
   notif._getAnonElt("translate").click();
-  is(notif.state, TranslationStub.STATE_TRANSLATING, "the infobar is in the translating state");
-  ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
-  is(TranslationStub.translatedFrom, "fr", "from language correct");
-  is(TranslationStub.translatedTo, TranslationStub.defaultTargetLanguage, "from language correct");
+  is(notif.state, notif.translation.STATE_TRANSLATING, "the infobar is in the translating state");
+  ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
+  is(notif.translation.translatedFrom, "fr", "from language correct");
+  is(notif.translation.translatedTo, Translation.defaultTargetLanguage, "from language correct");
   checkURLBarIcon();
 
   info("Make the translation fail and check we are in the error state.");
-  TranslationStub.failTranslation();
-  is(notif.state, TranslationStub.STATE_ERROR, "infobar in the error state");
+  notif.translation.failTranslation();
+  is(notif.state, notif.translation.STATE_ERROR, "infobar in the error state");
   checkURLBarIcon();
 
   info("Click the try again button");
   notif._getAnonElt("tryAgain").click();
-  is(notif.state, TranslationStub.STATE_TRANSLATING, "infobar in the translating state");
-  ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
-  is(TranslationStub.translatedFrom, "fr", "from language correct");
-  is(TranslationStub.translatedTo, TranslationStub.defaultTargetLanguage, "from language correct");
+  is(notif.state, notif.translation.STATE_TRANSLATING, "infobar in the translating state");
+  ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
+  is(notif.translation.translatedFrom, "fr", "from language correct");
+  is(notif.translation.translatedTo, Translation.defaultTargetLanguage, "from language correct");
   checkURLBarIcon();
 
   info("Make the translation succeed and check we are in the 'translated' state.");
-  TranslationStub.finishTranslation();
-  is(notif.state, TranslationStub.STATE_TRANSLATED, "infobar in the translated state");
+  notif.translation.finishTranslation();
+  is(notif.state, notif.translation.STATE_TRANSLATED, "infobar in the translated state");
   checkURLBarIcon(true);
 
   info("Test 'Show original' / 'Show Translation' buttons.");
   // First check 'Show Original' is visible and 'Show Translation' is hidden.
   ok(!notif._getAnonElt("showOriginal").hidden, "'Show Original' button visible");
   ok(notif._getAnonElt("showTranslation").hidden, "'Show Translation' button hidden");
   // Click the button.
   notif._getAnonElt("showOriginal").click();
@@ -132,55 +138,55 @@ function run_tests(aFinishCallback) {
   // Check that the 'Show Original' button is visible again.
   ok(!notif._getAnonElt("showOriginal").hidden, "'Show Original' button visible");
   ok(notif._getAnonElt("showTranslation").hidden, "'Show Translation' button hidden");
 
   info("Check that changing the source language causes a re-translation");
   let from = notif._getAnonElt("fromLanguage");
   from.value = "es";
   from.doCommand();
-  is(notif.state, TranslationStub.STATE_TRANSLATING, "infobar in the translating state");
-  ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
-  is(TranslationStub.translatedFrom, "es", "from language correct");
-  is(TranslationStub.translatedTo, TranslationStub.defaultTargetLanguage, "to language correct");
+  is(notif.state, notif.translation.STATE_TRANSLATING, "infobar in the translating state");
+  ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
+  is(notif.translation.translatedFrom, "es", "from language correct");
+  is(notif.translation.translatedTo, Translation.defaultTargetLanguage, "to language correct");
   // We want to show the 'translated' icon while re-translating,
   // because we are still displaying the previous translation.
   checkURLBarIcon(true);
-  TranslationStub.finishTranslation();
+  notif.translation.finishTranslation();
   checkURLBarIcon(true);
 
   info("Check that changing the target language causes a re-translation");
   let to = notif._getAnonElt("toLanguage");
   to.value = "pl";
   to.doCommand();
-  is(notif.state, TranslationStub.STATE_TRANSLATING, "infobar in the translating state");
-  ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
-  is(TranslationStub.translatedFrom, "es", "from language correct");
-  is(TranslationStub.translatedTo, "pl", "to language correct");
+  is(notif.state, notif.translation.STATE_TRANSLATING, "infobar in the translating state");
+  ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
+  is(notif.translation.translatedFrom, "es", "from language correct");
+  is(notif.translation.translatedTo, "pl", "to language correct");
   checkURLBarIcon(true);
-  TranslationStub.finishTranslation();
+  notif.translation.finishTranslation();
   checkURLBarIcon(true);
 
   // Cleanup.
   notif.close();
 
   info("Reopen the info bar to check that it's possible to override the detected language.");
-  notif = TranslationStub.showTranslationUI("fr");
-  is(notif.state, TranslationStub.STATE_OFFER, "the infobar is offering translation");
+  notif = showTranslationUI("fr");
+  is(notif.state, notif.translation.STATE_OFFER, "the infobar is offering translation");
   is(notif._getAnonElt("detectedLanguage").value, "fr", "The detected language is displayed");
   // Change the language and click 'Translate'
   notif._getAnonElt("detectedLanguage").value = "ja";
   notif._getAnonElt("translate").click();
-  is(notif.state, TranslationStub.STATE_TRANSLATING, "the infobar is in the translating state");
-  ok(!!TranslationStub.translatedFrom, "Translation.translate has been called");
-  is(TranslationStub.translatedFrom, "ja", "from language correct");
+  is(notif.state, notif.translation.STATE_TRANSLATING, "the infobar is in the translating state");
+  ok(!!notif.translation.translatedFrom, "Translation.translate has been called");
+  is(notif.translation.translatedFrom, "ja", "from language correct");
   notif.close();
 
   info("Reopen to check the 'Not Now' button closes the notification.");
-  notif = TranslationStub.showTranslationUI("fr");
+  notif = showTranslationUI("fr");
   let notificationBox = gBrowser.getNotificationBox();
   ok(!!notificationBox.getNotificationWithValue("translation"), "there's a 'translate' notification");
   notif._getAnonElt("notNow").click();
   ok(!notificationBox.getNotificationWithValue("translation"), "no 'translate' notification after clicking 'not now'");
 
   info("Check that clicking the url bar icon reopens the info bar");
   checkURLBarIcon();
   // Clicking the anchor element causes a 'showing' event to be sent
--- a/browser/components/translation/translation-infobar.xml
+++ b/browser/components/translation/translation-infobar.xml
@@ -97,30 +97,30 @@
             this.translation = aTranslation;
             let bundle = Cc["@mozilla.org/intl/stringbundle;1"]
                            .getService(Ci.nsIStringBundleService)
                            .createBundle("chrome://global/locale/languageNames.properties");
 
             // Fill the lists of supported source languages.
             let detectedLanguage = this._getAnonElt("detectedLanguage");
             let fromLanguage = this._getAnonElt("fromLanguage");
-            for (let code of this.translation.supportedSourceLanguages) {
+            for (let code of Translation.supportedSourceLanguages) {
               let name = bundle.GetStringFromName(code);
               detectedLanguage.appendItem(name, code);
               fromLanguage.appendItem(name, code);
             }
             detectedLanguage.value = this.translation.detectedLanguage;
 
             // translatedFrom is only set if we have already translated this page.
             if (aTranslation.translatedFrom)
               fromLanguage.value = aTranslation.translatedFrom;
 
             // Fill the list of supporter target languages.
             let toLanguage = this._getAnonElt("toLanguage");
-            for (let code of this.translation.supportedTargetLanguages)
+            for (let code of Translation.supportedTargetLanguages)
               toLanguage.appendItem(bundle.GetStringFromName(code), code);
 
             if (aTranslation.translatedTo)
               toLanguage.value = aTranslation.translatedTo;
 
             if (aTranslation.state)
               this.state = aTranslation.state;
 
@@ -138,17 +138,17 @@
 
       <method name="translate">
         <body>
           <![CDATA[
             if (this.state == this.translation.STATE_OFFER) {
               this._getAnonElt("fromLanguage").value =
                 this._getAnonElt("detectedLanguage").value;
               this._getAnonElt("toLanguage").value =
-                this.translation.defaultTargetLanguage;
+                Translation.defaultTargetLanguage;
             }
 
             this._handleButtonHiding(false);
             this.translation.translate(this._getAnonElt("fromLanguage").value,
                                        this._getAnonElt("toLanguage").value);
           ]]>
         </body>
       </method>
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -247,16 +247,20 @@ let Experiments = {
  * The policy object allows us to inject fake enviroment data from the
  * outside by monkey-patching.
  */
 
 Experiments.Policy = function () {
   this._log = Log.repository.getLoggerWithMessagePrefix(
     "Browser.Experiments.Policy",
     "Policy #" + gPolicyCounter++ + "::");
+
+  // Set to true to ignore hash verification on downloaded XPIs. This should
+  // not be used outside of testing.
+  this.ignoreHashes = false;
 };
 
 Experiments.Policy.prototype = {
   now: function () {
     return new Date();
   },
 
   random: function () {
@@ -367,29 +371,34 @@ Experiments.Experiments.prototype = {
     gPrefs.observe(PREF_MANIFEST_URI, this.updateManifest, this);
     gPrefs.observe(PREF_ENABLED, this._toggleExperimentsEnabled, this);
 
     gPrefsTelemetry.observe(PREF_TELEMETRY_ENABLED, this._telemetryStatusChanged, this);
 
     AsyncShutdown.profileBeforeChange.addBlocker("Experiments.jsm shutdown",
       this.uninit.bind(this));
 
-    this._startWatchingAddons();
+    this._registerWithAddonManager();
 
-    this._loadTask = Task.spawn(this._loadFromCache.bind(this));
+    let deferred = Promise.defer();
+
+    this._loadTask = this._loadFromCache();
     this._loadTask.then(
       () => {
         this._log.trace("_loadTask finished ok");
         this._loadTask = null;
-        this._run();
+        this._run().then(deferred.resolve, deferred.reject);
       },
       (e) => {
         this._log.error("_loadFromCache caught error: " + e);
+        deferred.reject(e);
       }
     );
+
+    return deferred.promise;
   },
 
   /**
    * Uninitialize this instance.
    *
    * This function is susceptible to race conditions. If it is called multiple
    * times before the previous uninit() has completed or if it is called while
    * an init() operation is being performed, the object may get in bad state
@@ -397,17 +406,17 @@ Experiments.Experiments.prototype = {
    *
    * @return Promise<>
    *         The promise is fulfilled when all pending tasks are finished.
    */
   uninit: Task.async(function* () {
     yield this._loadTask;
 
     if (!this._shutdown) {
-      this._stopWatchingAddons();
+      this._unregisterWithAddonManager();
 
       gPrefs.ignore(PREF_LOGGING, configureLogging);
       gPrefs.ignore(PREF_MANIFEST_URI, this.updateManifest, this);
       gPrefs.ignore(PREF_ENABLED, this._toggleExperimentsEnabled, this);
 
       gPrefsTelemetry.ignore(PREF_TELEMETRY_ENABLED, this._telemetryStatusChanged, this);
 
       if (this._timer) {
@@ -418,22 +427,24 @@ Experiments.Experiments.prototype = {
     this._shutdown = true;
     if (this._mainTask) {
       yield this._mainTask;
     }
 
     this._log.info("Completed uninitialization.");
   }),
 
-  _startWatchingAddons: function () {
+  _registerWithAddonManager: function () {
+    this._log.trace("Registering instance with Addon Manager.");
+
     AddonManager.addAddonListener(this);
     AddonManager.addInstallListener(this);
   },
 
-  _stopWatchingAddons: function () {
+  _unregisterWithAddonManager: function () {
     AddonManager.removeInstallListener(this);
     AddonManager.removeAddonListener(this);
   },
 
   /**
    * Throws an exception if we've already shut down.
    */
   _checkForShutdown: function() {
@@ -807,27 +818,27 @@ Experiments.Experiments.prototype = {
     yield OS.File.writeAtomic(path, data, options);
     this._dirty = false;
     this._log.debug("_saveToCache saved to " + path);
   },
 
   /*
    * Task function, load the cached experiments manifest file from disk.
    */
-  _loadFromCache: function*() {
+  _loadFromCache: Task.async(function* () {
     this._log.trace("_loadFromCache");
     let path = this._cacheFilePath;
     try {
       let result = yield loadJSONAsync(path, { compression: "lz4" });
       this._populateFromCache(result);
     } catch (e if e instanceof OS.File.Error && e.becauseNoSuchFile) {
       // No cached manifest yet.
       this._experiments = new Map();
     }
-  },
+  }),
 
   _populateFromCache: function (data) {
     this._log.trace("populateFromCache() - data: " + JSON.stringify(data));
 
     // If the user has a newer cache version than we can understand, we fail
     // hard; no experiments should be active in this older client.
     if (CACHE_VERSION !== data.version) {
       throw new Error("Experiments::_populateFromCache() - invalid cache version");
@@ -1493,18 +1504,19 @@ Experiments.ExperimentEntry.prototype = 
       gPrefs.set(PREF_ACTIVE_EXPERIMENT, true);
     }.bind(this));
   },
 
   // Async install of the addon for this experiment, part of the start task above.
   _installAddon: function* () {
     let deferred = Promise.defer();
 
-    let install = yield addonInstallForURL(this._manifestData.xpiURL,
-                                           this._manifestData.xpiHash);
+    let hash = this._policy.ignoreHashes ? null : this._manifestData.xpiHash;
+
+    let install = yield addonInstallForURL(this._manifestData.xpiURL, hash);
     gActiveInstallURLs.add(install.sourceURI.spec);
 
     let failureHandler = (install, handler) => {
       let message = "AddonInstall " + handler + " for " + this.id + ", state=" +
                    (install.state || "?") + ", error=" + install.error;
       this._log.error("_installAddon() - " + message);
       this._failedStart = true;
       gActiveInstallURLs.delete(install.sourceURI.spec);
--- a/browser/experiments/test/xpcshell/test_activate.js
+++ b/browser/experiments/test/xpcshell/test_activate.js
@@ -135,9 +135,28 @@ add_task(function* test_startStop() {
   defineNow(gPolicy, futureDate(endDate, MS_IN_ONE_DAY));
   result = yield experiment._shouldStop();
   Assert.equal(result.shouldStop, true, "shouldStop should now be true.");
   maybeStop = yield experiment.maybeStop();
   Assert.equal(maybeStop, true, "Experiment should have been stopped.");
   Assert.equal(experiment.enabled, false, "Experiment should be disabled.");
   addons = yield getExperimentAddons();
   Assert.equal(addons.length, 0, "Experiment add-on is uninstalled.");
+
+  // Ensure hash validation works.
+  // We set an incorrect hash and expect the install to fail.
+  experiment._manifestData.xpiHash = "sha1:41014dcc66b4dcedcd973491a1530a32f0517d8a";
+  let errored = false;
+  try {
+    yield experiment.start();
+  } catch (ex) {
+    errored = true;
+  }
+  Assert.ok(experiment._failedStart, "Experiment failed to start.");
+  Assert.ok(errored, "start() threw an exception.");
+
+  // Make sure "ignore hashes" mode works.
+  gPolicy.ignoreHashes = true;
+  let changes = yield experiment.start();
+  Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL);
+  yield experiment.stop();
+  gPolicy.ignoreHashes = false;
 });
--- a/browser/experiments/test/xpcshell/test_api.js
+++ b/browser/experiments/test/xpcshell/test_api.js
@@ -1361,19 +1361,19 @@ add_task(function* test_unexpectedUninst
 // uninstalled.
 add_task(function* testUnknownExperimentsUninstalled() {
   let experiments = new Experiments.Experiments(gPolicy);
 
   let addons = yield getExperimentAddons();
   Assert.equal(addons.length, 0, "Precondition: No experiment add-ons are present.");
 
   // Simulate us not listening.
-  experiments._stopWatchingAddons();
+  experiments._unregisterWithAddonManager();
   yield AddonTestUtils.installXPIFromURL(gDataRoot + EXPERIMENT1_XPI_NAME, EXPERIMENT1_XPI_SHA1);
-  experiments._startWatchingAddons();
+  experiments._registerWithAddonManager();
 
   addons = yield getExperimentAddons();
   Assert.equal(addons.length, 1, "Experiment 1 installed via AddonManager");
 
   // Simulate no known experiments.
   gManifestObject = {
     "version": 1,
     experiments: [],
@@ -1447,19 +1447,19 @@ add_task(function* testEnabledAfterResta
   let fromManifest = yield experiments.getExperiments();
   Assert.equal(fromManifest.length, 1, "A single experiment is known.");
 
   addons = yield getExperimentAddons();
   Assert.equal(addons.length, 1, "A single experiment add-on is installed.");
   Assert.ok(addons[0].isActive, "That experiment is active.");
 
   dump("Restarting Addon Manager\n");
-  experiments._stopWatchingAddons();
+  experiments._unregisterWithAddonManager();
   restartManager();
-  experiments._startWatchingAddons();
+  experiments._registerWithAddonManager();
 
   addons = yield getExperimentAddons();
   Assert.equal(addons.length, 1, "The experiment is still there after restart.");
   Assert.ok(addons[0].userDisabled, "But it is disabled.");
   Assert.equal(addons[0].isActive, false, "And not active.");
 
   yield experiments.updateManifest();
   Assert.ok(addons[0].isActive, "It activates when the manifest is evaluated.");
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -50,17 +50,17 @@
 }
 
 @keyframes moveX {
   /* These values are adjusted for the padding on the panel. */
   from { margin-left: -15px; } to { margin-left: calc(100% - 49px); }
 }
 @keyframes moveY {
   /* These values are adjusted for the padding and height of the panel. */
-  from { margin-top: -6px; } to { margin-top: 58px; }
+  from { margin-top: -.5em; } to { margin-top: calc(64px - .5em); }
 }
 
 #PanelUI-button {
   background-image: linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 30%, hsla(0,0%,100%,.3) 70%, hsla(0,0%,100%,0)),
                     linear-gradient(to bottom, hsla(210,54%,20%,0), hsla(210,54%,20%,.3) 30%, hsla(210,54%,20%,.3) 70%, hsla(210,54%,20%,0)),
                     linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 30%, hsla(0,0%,100%,.3) 70%, hsla(0,0%,100%,0));
   background-size: 1px calc(100% - 1px), 1px calc(100% - 1px), 1px  calc(100% - 1px) !important;
   background-position: 0px 0px, 1px 0px, 2px 0px;
--- a/content/base/public/nsIDocumentEncoder.idl
+++ b/content/base/public/nsIDocumentEncoder.idl
@@ -30,17 +30,17 @@ interface nsIDocumentEncoderNodeFixup : 
    * @param [OUT] aSerializeCloneKids True if the document encoder should
    * apply recursive serialization to the children of the fixed up node
    * instead of the children of the original node.
    * @return The resulting fixed up node.
    */
   nsIDOMNode fixupNode(in nsIDOMNode aNode, out boolean aSerializeCloneKids);
 };
 
-[scriptable, uuid(7222bdf1-c2b9-41f1-a40a-a3d65283a95b)]
+[scriptable, uuid(1158bd7e-a08b-4ff6-9417-6f99144cfccc)]
 interface nsIDocumentEncoder : nsISupports
 {
   // Output methods flag bits. There are a frightening number of these,
   // because everyone wants something a little bit different
    
 
   /** 
    * Output only the selection (as opposed to the whole document).
@@ -325,13 +325,28 @@ interface nsIDocumentEncoder : nsISuppor
    *              be stored.
    * @return The document encoded as a string.
    * 
    */
   AString encodeToStringWithContext( out AString aContextString,
                                      out AString aInfoString);
 
   /**
+   * Encode the document into a string of limited size.
+   * @param aMaxLength After aMaxLength characters, the encoder will stop
+   *                   encoding new data.
+   *                   Only values > 0 will be considered.
+   *                   The returned string may be slightly larger than
+   *                   aMaxLength because some serializers (eg. HTML)
+   *                   may need to close some tags after they stop
+   *                   encoding new data, or finish a line (72 columns
+   *                   by default for the plain text serializer).
+   *
+   * @return The document encoded into a string.
+   */
+  AString encodeToStringWithMaxLength(in unsigned long aMaxLength);
+
+  /**
    * Set the fixup object associated with node persistence.
    * @param aFixup The fixup object.
    */
   void setNodeFixup(in nsIDocumentEncoderNodeFixup aFixup);
 };
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -76,17 +76,18 @@ public:
 
 protected:
   void Initialize(bool aClearCachedSerializer = true);
   nsresult SerializeNodeStart(nsINode* aNode, int32_t aStartOffset,
                               int32_t aEndOffset, nsAString& aStr,
                               nsINode* aOriginalNode = nullptr);
   nsresult SerializeToStringRecursive(nsINode* aNode,
                                       nsAString& aStr,
-                                      bool aDontSerializeRoot);
+                                      bool aDontSerializeRoot,
+                                      uint32_t aMaxLength = 0);
   nsresult SerializeNodeEnd(nsINode* aNode, nsAString& aStr);
   // This serializes the content of aNode.
   nsresult SerializeToStringIterative(nsINode* aNode,
                                       nsAString& aStr);
   nsresult SerializeRangeToString(nsRange *aRange,
                                   nsAString& aOutputString);
   nsresult SerializeRangeNodes(nsRange* aRange, 
                                nsINode* aNode, 
@@ -445,18 +446,23 @@ nsDocumentEncoder::SerializeNodeEnd(nsIN
     mSerializer->AppendElementEnd(aNode->AsElement(), aStr);
   }
   return NS_OK;
 }
 
 nsresult
 nsDocumentEncoder::SerializeToStringRecursive(nsINode* aNode,
                                               nsAString& aStr,
-                                              bool aDontSerializeRoot)
+                                              bool aDontSerializeRoot,
+                                              uint32_t aMaxLength)
 {
+  if (aMaxLength > 0 && aStr.Length() >= aMaxLength) {
+    return NS_OK;
+  }
+
   if (!IsVisibleNode(aNode))
     return NS_OK;
 
   nsresult rv = NS_OK;
   bool serializeClonedChildren = false;
   nsINode* maybeFixedNode = nullptr;
 
   // Keep the node from FixupNode alive.
@@ -482,26 +488,31 @@ nsDocumentEncoder::SerializeToStringRecu
         if (!isSelectable){
           aDontSerializeRoot = true;
         }
       }
     }
   }
 
   if (!aDontSerializeRoot) {
-    rv = SerializeNodeStart(maybeFixedNode, 0, -1, aStr, aNode);
+    int32_t endOffset = -1;
+    if (aMaxLength > 0) {
+      MOZ_ASSERT(aMaxLength >= aStr.Length());
+      endOffset = aMaxLength - aStr.Length();
+    }
+    rv = SerializeNodeStart(maybeFixedNode, 0, endOffset, aStr, aNode);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsINode* node = serializeClonedChildren ? maybeFixedNode : aNode;
 
   for (nsINode* child = nsNodeUtils::GetFirstChildOfTemplateOrNode(node);
        child;
        child = child->GetNextSibling()) {
-    rv = SerializeToStringRecursive(child, aStr, false);
+    rv = SerializeToStringRecursive(child, aStr, false, aMaxLength);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (!aDontSerializeRoot) {
     rv = SerializeNodeEnd(node, aStr);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
@@ -1012,16 +1023,23 @@ nsDocumentEncoder::SerializeRangeToStrin
   NS_ENSURE_SUCCESS(rv, rv);
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsDocumentEncoder::EncodeToString(nsAString& aOutputString)
 {
+  return EncodeToStringWithMaxLength(0, aOutputString);
+}
+
+NS_IMETHODIMP
+nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
+                                               nsAString& aOutputString)
+{
   if (!mDocument)
     return NS_ERROR_NOT_INITIALIZED;
 
   aOutputString.Truncate();
 
   nsString output;
   static const size_t bufferSize = 2048;
   if (!mCachedBuffer) {
@@ -1141,17 +1159,17 @@ nsDocumentEncoder::EncodeToString(nsAStr
     } else {
       rv = SerializeToStringRecursive(mNode, output, mNodeIsContainer);
     }
     mNode = nullptr;
   } else {
     rv = mSerializer->AppendDocumentStart(mDocument, output);
 
     if (NS_SUCCEEDED(rv)) {
-      rv = SerializeToStringRecursive(mDocument, output, false);
+      rv = SerializeToStringRecursive(mDocument, output, false, aMaxLength);
     }
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   rv = mSerializer->Flush(output);
  
   mCachedBuffer = nsStringBuffer::FromString(output);
   // We have to be careful how we set aOutputString, because we don't
--- a/content/base/src/nsPlainTextSerializer.cpp
+++ b/content/base/src/nsPlainTextSerializer.cpp
@@ -273,17 +273,18 @@ nsPlainTextSerializer::AppendText(nsICon
   nsresult rv = NS_OK;
 
   nsIContent* content = aText;
   const nsTextFragment* frag;
   if (!content || !(frag = content->GetText())) {
     return NS_ERROR_FAILURE;
   }
   
-  int32_t endoffset = (aEndOffset == -1) ? frag->GetLength() : aEndOffset;
+  int32_t fragLength = frag->GetLength();
+  int32_t endoffset = (aEndOffset == -1) ? fragLength : std::min(aEndOffset, fragLength);
   NS_ASSERTION(aStartOffset <= endoffset, "A start offset is beyond the end of the text fragment!");
 
   int32_t length = endoffset - aStartOffset;
   if (length <= 0) {
     return NS_OK;
   }
 
   nsAutoString textstr;
--- a/content/base/src/nsXMLContentSerializer.cpp
+++ b/content/base/src/nsXMLContentSerializer.cpp
@@ -133,17 +133,18 @@ nsXMLContentSerializer::AppendTextData(n
                                        bool aTranslateEntities)
 {
   nsIContent* content = aNode;
   const nsTextFragment* frag;
   if (!content || !(frag = content->GetText())) {
     return NS_ERROR_FAILURE;
   }
 
-  int32_t endoffset = (aEndOffset == -1) ? frag->GetLength() : aEndOffset;
+  int32_t fragLength = frag->GetLength();
+  int32_t endoffset = (aEndOffset == -1) ? fragLength : std::min(aEndOffset, fragLength);
   int32_t length = endoffset - aStartOffset;
 
   NS_ASSERTION(aStartOffset >= 0, "Negative start offset for text fragment!");
   NS_ASSERTION(aStartOffset <= endoffset, "A start offset is beyond the end of the text fragment!");
 
   if (length <= 0) {
     // XXX Zero is a legal value, maybe non-zero values should be an
     // error.
@@ -295,22 +296,26 @@ nsXMLContentSerializer::AppendComment(ns
   nsCOMPtr<nsIDOMComment> comment = do_QueryInterface(aComment);
   NS_ENSURE_ARG(comment);
   nsresult rv;
   nsAutoString data;
 
   rv = comment->GetData(data);
   if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
 
-  if (aStartOffset || (aEndOffset != -1)) {
-    int32_t length = (aEndOffset == -1) ? data.Length() : aEndOffset;
+  int32_t dataLength = data.Length();
+  if (aStartOffset || (aEndOffset != -1 && aEndOffset < dataLength)) {
+    int32_t length =
+      (aEndOffset == -1) ? dataLength : std::min(aEndOffset, dataLength);
     length -= aStartOffset;
 
     nsAutoString frag;
-    data.Mid(frag, aStartOffset, length);
+    if (length > 0) {
+      data.Mid(frag, aStartOffset, length);
+    }
     data.Assign(frag);
   }
 
   MaybeAddNewlineForRootNode(aStr);
 
   NS_NAMED_LITERAL_STRING(startComment, "<!--");
 
   if (mPreLevel > 0 || mDoRaw) {
--- a/content/base/test/delayedServerEvents.sjs
+++ b/content/base/test/delayedServerEvents.sjs
@@ -1,12 +1,12 @@
 // this will take strings_to_send.length*500 ms = 5 sec
 
 var timer = null;
-var strings_to_send = ["data\r\n\nda", "ta", ":", "de", "layed1\n\n",
+var strings_to_send = ["retry:999999999\ndata\r\n\nda", "ta", ":", "de", "layed1\n\n",
                        "",
                        "",
                        "data:delayed2\n\n", "", ""];
 var resp = null;
 
 function sendNextString()
 {
   if (strings_to_send.length == 0) {
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -554,16 +554,17 @@ skip-if = (buildapp == 'b2g' && toolkit 
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 904183 # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_copypaste.xhtml]
 skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(bug 904183) b2g-debug(bug 904183) b2g-desktop(bug 904183)
 [test_createHTMLDocument.html]
 [test_declare_stylesheet_obsolete.html]
 [test_domparser_null_char.html]
 [test_domparsing.html]
 [test_elementTraversal.html]
+[test_encodeToStringWithMaxLength.html]
 [test_fileapi.html]
 skip-if = e10s
 [test_fileapi_slice.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 775227
 [test_getElementById.html]
 [test_html_colors_quirks.html]
 [test_html_colors_standards.html]
 [test_html_in_xhr.html]
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_encodeToStringWithMaxLength.html
@@ -0,0 +1,64 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=995321
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 995321 - encodeToStringWithMaxLength</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+  function getEncoder() {
+    const de = SpecialPowers.Ci.nsIDocumentEncoder;
+    const Cc = SpecialPowers.Cc;
+
+    // Create a plaintext encoder without flags.
+    var encoder = Cc["@mozilla.org/layout/documentEncoder;1?type=text/plain"]
+                  .createInstance(de);
+    encoder.init(document, "text/plain", 0);
+    return encoder;
+  }
+
+  function testPlaintextSerializerWithMaxLength() {
+    var string = getEncoder().encodeToString();
+
+    var shorterString = getEncoder().encodeToStringWithMaxLength(1);
+    ok(shorterString.length < 1 + 72,
+       "test length is in the expected range after limiting the length to 1");
+    ok(string.startsWith(shorterString.trimRight()),
+       "the shorter string has the expected content");
+
+    shorterString = getEncoder().encodeToStringWithMaxLength(300);
+    ok(shorterString.length < 300 + 72,
+       "test length is in the expected range after limiting the length to 300");
+    ok(string.startsWith(shorterString.trimRight()),
+       "the shorter string has the expected content");
+
+    is(getEncoder().encodeToStringWithMaxLength(0), string,
+       "limiting the length to 0 should be ignored");
+
+    is(getEncoder().encodeToStringWithMaxLength(10000), string,
+       "limiting the length to a huge value should return the whole page");
+
+    SimpleTest.finish();
+  }
+
+  addLoadEvent(testPlaintextSerializerWithMaxLength);
+  SimpleTest.waitForExplicitFinish();
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=995321">Mozilla Bug 995321</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+The <em>Mozilla</em> project is a global community of <strong>people</strong> who believe that openness, innovation, and opportunity are key to the continued health of the Internet. We have worked together since 1998 to ensure that the Internet is developed in a way that benefits everyone. We are best known for creating the Mozilla Firefox web browser.
+
+The Mozilla project uses a community-based approach to create world-class open source software and to develop new types of collaborative activities. We create communities of people involved in making the Internet experience better for all of us.
+
+As a result of these efforts, we have distilled a set of principles that we believe are critical for the Internet to continue to benefit the public good as well as commercial aspects of life. We set out these principles below.
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/media/RtspMediaResource.cpp
+++ b/content/media/RtspMediaResource.cpp
@@ -32,17 +32,17 @@ namespace mozilla {
 
 /* class RtspTrackBuffer: a ring buffer implementation for audio/video track
  * un-decoded data.
  * The ring buffer is divided into BUFFER_SLOT_NUM slots,
  * and each slot's size is fixed(mSlotSize).
  * Even though the ring buffer is divided into fixed size slots, it still can
  * store the data which size is larger than one slot size.
  * */
-#define BUFFER_SLOT_NUM 8192
+#define BUFFER_SLOT_NUM 512
 #define BUFFER_SLOT_DEFAULT_SIZE 256
 #define BUFFER_SLOT_MAX_SIZE 8192
 #define BUFFER_SLOT_INVALID -1
 #define BUFFER_SLOT_EMPTY 0
 
 struct BufferSlotData {
   int32_t mLength;
   uint64_t mTime;
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -3,17 +3,16 @@
  * 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/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/PopupNotifications.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PeerConnectionIdp",
   "resource://gre/modules/media/PeerConnectionIdp.jsm");
 
 const PC_CONTRACT = "@mozilla.org/dom/peerconnection;1";
 const PC_OBS_CONTRACT = "@mozilla.org/dom/peerconnectionobserver;1";
 const PC_ICE_CONTRACT = "@mozilla.org/dom/rtcicecandidate;1";
 const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
--- a/gfx/2d/DrawTargetCG.cpp
+++ b/gfx/2d/DrawTargetCG.cpp
@@ -224,17 +224,21 @@ GetRetainedImageFromSourceSurface(Source
   }
 
   MOZ_CRASH("unsupported source surface");
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
-  return nullptr;
+  if (aSurface->GetType() == SurfaceType::COREGRAPHICS_IMAGE ||
+      aSurface->GetType() == SurfaceType::COREGRAPHICS_CGCONTEXT) {
+    return aSurface;
+  }
+  return aSurface->GetDataSurface();
 }
 
 class UnboundnessFixer
 {
     CGRect mClipBounds;
     CGLayerRef mLayer;
     CGContextRef mCg;
   public:
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -1199,18 +1199,37 @@ DrawTargetD2D::CreateSourceSurfaceFromDa
   }
 
   return newSurf;
 }
 
 TemporaryRef<SourceSurface> 
 DrawTargetD2D::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
-  // Unsupported!
-  return nullptr;
+  if (aSurface->GetType() == SurfaceType::D2D1_BITMAP ||
+      aSurface->GetType() == SurfaceType::D2D1_DRAWTARGET) {
+    return aSurface;
+  }
+
+  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
+
+  DataSourceSurface::MappedSurface map;
+  if (!data->Map(DataSourceSurface::MapType::READ, &map)) {
+    return nullptr;
+  }
+
+  RefPtr<SourceSurfaceD2D> newSurf = new SourceSurfaceD2D();
+  bool success = newSurf->InitFromData(map.mData, data->GetSize(), map.mStride, data->GetFormat(), mRT);
+
+  data->Unmap();
+
+  if (!success) {
+    return nullptr;
+  }
+  return newSurf;
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
 {
   if (aSurface.mType != NativeSurfaceType::D3D10_TEXTURE) {
     gfxDebug() << *this << ": Failure to create source surface from non-D3D10 texture native surface.";
     return nullptr;
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -916,16 +916,44 @@ DrawTargetD2D1::GetImageForSurface(Sourc
       return image;
     }
     break;
   }
 
   return image;
 }
 
+TemporaryRef<SourceSurface>
+DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const
+{
+  if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) {
+    return aSurface;
+  }
+
+  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
+
+  DataSourceSurface::MappedSurface map;
+  if (!data->Map(DataSourceSurface::MapType::READ, &map)) {
+    return nullptr;
+  }
+
+  RefPtr<ID2D1Bitmap1> bitmap;
+  HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.mData, map.mStride,
+                                 D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())),
+                                 byRef(bitmap));
+
+  data->Unmap();
+
+  if (!bitmap) {
+    return nullptr;
+  }
+
+  return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize());
+}
+
 void
 DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
 {
   D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
 
   if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) {
     options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
   }
--- a/gfx/2d/DrawTargetD2D1.h
+++ b/gfx/2d/DrawTargetD2D1.h
@@ -99,17 +99,17 @@ public:
   virtual void PushClip(const Path *aPath);
   virtual void PushClipRect(const Rect &aRect);
   virtual void PopClip();
 
   virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
                                                                   const IntSize &aSize,
                                                                   int32_t aStride,
                                                                   SurfaceFormat aFormat) const;
-  virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const { return nullptr; }
+  virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const;
 
   virtual TemporaryRef<SourceSurface>
     CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const { return nullptr; }
   
   virtual TemporaryRef<DrawTarget>
     CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
 
   virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const;
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -597,26 +597,17 @@ DrawTargetSkia::CreateSimilarDrawTarget(
 
 TemporaryRef<SourceSurface>
 DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const
 {
   if (aSurface->GetType() == SurfaceType::SKIA) {
     return aSurface;
   }
 
-  if (aSurface->GetType() != SurfaceType::DATA) {
-    return nullptr;
-  }
-
-  RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
-  RefPtr<SourceSurface> surface = CreateSourceSurfaceFromData(data->GetData(),
-                                                              data->GetSize(),
-                                                              data->Stride(),
-                                                              data->GetFormat());
-  return data.forget();
+  return aSurface->GetDataSurface();
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
 {
   return nullptr;
 }
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -427,17 +427,17 @@ public:
     }
 
 
 public:
 
     template<size_t N>
     static void InitializeExtensionsBitSet(std::bitset<N>& extensionsBitset, const char* extStr, const char** extList, bool verbose = false)
     {
-        char* exts = strdup(extStr);
+        char* exts = ::strdup(extStr);
 
         if (verbose)
             printf_stderr("Extensions: %s\n", exts);
 
         char* cur = exts;
         bool done = false;
         while (!done) {
             char* space = strchr(cur, ' ');
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -6019,25 +6019,30 @@ static unsigned
 StackArgBytes(const VectorT &argTypes)
 {
     ABIArgIter<VectorT> iter(argTypes);
     while (!iter.done())
         iter++;
     return iter.stackBytesConsumedSoFar();
 }
 
+static unsigned
+StackDecrementForCall(MacroAssembler &masm, unsigned bytesToPush)
+{
+    // Include extra padding so that, after pushing the bytesToPush,
+    // the stack is aligned for a call instruction.
+    unsigned alreadyPushed = AlignmentAtPrologue + masm.framePushed();
+    return AlignBytes(alreadyPushed + bytesToPush, StackAlignment) - alreadyPushed;
+}
+
 template <class VectorT>
 static unsigned
 StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned extraBytes = 0)
 {
-    // Include extra padding so that, after pushing the arguments and
-    // extraBytes, the stack is aligned for a call instruction.
-    unsigned argBytes = StackArgBytes(argTypes);
-    unsigned alreadyPushed = AlignmentAtPrologue + masm.framePushed();
-    return AlignBytes(alreadyPushed + extraBytes + argBytes, StackAlignment) - alreadyPushed;
+    return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes);
 }
 
 static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
                                              NonVolatileRegs.fpus().size() * sizeof(double);
 
 static bool
 GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc)
 {
@@ -6295,33 +6300,35 @@ FillArgumentArray(ModuleCompiler &m, con
 static void
 GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                            unsigned exitIndex, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     m.setInterpExitOffset(exitIndex);
     masm.setFramePushed(0);
-
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+#if defined(JS_CODEGEN_ARM)
+    masm.Push(lr);
+#endif
+
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
     // Reserve space for a call to InvokeFromAsmJS_* and an array of values
     // passed to this FFI call.
     unsigned arraySize = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
     unsigned stackDec = StackDecrementForCall(masm, invokeArgTypes, arraySize);
     masm.reserveStack(stackDec);
 
     // Fill the argument array.
-    unsigned offsetToCallerStackArgs = NativeFrameSize + masm.framePushed();
+    unsigned offsetToCallerStackArgs = AlignmentAtPrologue + masm.framePushed();
     unsigned offsetToArgv = StackArgBytes(invokeArgTypes);
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
     FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
 
     // Prepare the arguments for the call to InvokeFromAsmJS_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
     LoadAsmJSActivationIntoRegister(masm, activation);
@@ -6382,86 +6389,30 @@ GenerateFFIInterpreterExit(ModuleCompile
         MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
         break;
     }
 
     // Note: the caller is IonMonkey code which means there are no non-volatile
     // registers to restore.
     masm.freeStack(stackDec);
     masm.ret();
-#else
-    const unsigned arrayLength = Max<size_t>(1, exit.sig().args().length());
-    const unsigned arraySize = arrayLength * sizeof(Value);
-    const unsigned reserveSize = AlignBytes(arraySize, StackAlignment) +
-        ShadowStackSpace;
-    const unsigned callerArgsOffset = reserveSize + NativeFrameSize + sizeof(int32_t);
-    masm.setFramePushed(0);
-    masm.Push(lr);
-    masm.reserveStack(reserveSize + sizeof(int32_t));
-
-    // Store arguments
-    FillArgumentArray(m, exit.sig().args(), ShadowStackSpace, callerArgsOffset, IntArgReg0);
-
-    // argument 0: cx
-    Register activation = IntArgReg3;
-    LoadAsmJSActivationIntoRegister(masm, activation);
-
-    LoadJSContextFromActivation(masm, activation, IntArgReg0);
-
-    // argument 1: exitIndex
-    masm.mov(ImmWord(exitIndex), IntArgReg1);
-
-    // argument 2: argc
-    masm.mov(ImmWord(exit.sig().args().length()), IntArgReg2);
-
-    // argument 3: argv
-    Address argv(StackPointer, ShadowStackSpace);
-    masm.lea(Operand(argv), IntArgReg3);
-
-    AssertStackAlignment(masm);
-    switch (exit.sig().retType().which()) {
-      case RetType::Void:
-        masm.call(AsmJSImm_InvokeFromAsmJS_Ignore);
-        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
-        break;
-      case RetType::Signed:
-        masm.call(AsmJSImm_InvokeFromAsmJS_ToInt32);
-        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
-        masm.unboxInt32(argv, ReturnReg);
-        break;
-      case RetType::Double:
-        masm.call(AsmJSImm_InvokeFromAsmJS_ToNumber);
-        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
-        masm.loadDouble(argv, ReturnFloatReg);
-        break;
-      case RetType::Float:
-        MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
-        break;
-    }
-
-    masm.freeStack(reserveSize + sizeof(int32_t));
-    masm.ret();
-#endif
 }
 
 static void
 GenerateOOLConvert(ModuleCompiler &m, RetType retType, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
 
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer }; // argv
     MIRTypeVector callArgTypes(m.cx());
     callArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
-    // Reserve space for a call to InvokeFromAsmJS_* and an array of values
-    // passed to this FFI call.
-    unsigned arraySize = sizeof(Value);
-    unsigned stackDec = StackDecrementForCall(masm, callArgTypes, arraySize);
-    masm.reserveStack(stackDec);
+    // The stack is assumed to be aligned.  The frame is allocated by GenerateFFIIonExit and
+    // the stack usage here needs to kept in sync with GenerateFFIIonExit.
 
     // Store value
     unsigned offsetToArgv = StackArgBytes(callArgTypes);
     masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv));
 
     // Store real arguments
     ABIArgMIRTypeIter i(callArgTypes);
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
@@ -6499,52 +6450,78 @@ GenerateOOLConvert(ModuleCompiler &m, Re
       case RetType::Double:
           masm.call(AsmJSImm_CoerceInPlace_ToNumber);
           masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
           masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnFloatReg);
           break;
       default:
           MOZ_ASSUME_UNREACHABLE("Unsupported convert type");
     }
-
-    masm.freeStack(stackDec);
 }
 
 static void
 GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                          unsigned exitIndex, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     m.setIonExitOffset(exitIndex);
     masm.setFramePushed(0);
 
-    RegisterSet restoreSet = RegisterSet::Intersect(RegisterSet::All(),
-                                                    RegisterSet::Not(RegisterSet::Volatile()));
-#if defined(JS_CODEGEN_ARM)
-    masm.Push(lr);
+#if defined(JS_CODEGEN_X64)
+    masm.Push(HeapReg);
+#elif defined(JS_CODEGEN_ARM)
+    // The lr register holds the return address and needs to be saved.  The GlobalReg
+    // (r10) and HeapReg (r11) also need to be restored before returning to asm.js code.
+    // The NANReg also needs to be restored, but is a constant and is reloaded before
+    // returning to asm.js code.
+    masm.PushRegsInMask(RegisterSet(GeneralRegisterSet((1<<GlobalReg.code()) |
+                                                       (1<<HeapReg.code()) |
+                                                       (1<<lr.code())),
+                                    FloatRegisterSet(uint32_t(0))));
 #endif
-    masm.PushRegsInMask(restoreSet);
-
-    // Arguments are in the following order on the stack:
+
+    // The stack frame is used for the call into Ion and also for calls into C for OOL
+    // conversion of the result.  A frame large enough for both is allocated.
+    //
+    // Arguments to the Ion function are in the following order on the stack:
     // descriptor | callee | argc | this | arg1 | arg2 | ...
-
-    // Reserve and align space for the arguments
-    MIRTypeVector emptyVector(m.cx());
     unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
-    unsigned extraBytes = 0;
+
+    // On ARM, we call with ma_callIonNoPush which, following the Ion calling convention,
+    // stores the return address into *sp. This means we need to include an extra word of
+    // space before the arguments in the stack allocation. (On x86/x64, the call
+    // instruction does the push itself and the ABI just requires us to be aligned before
+    // the call instruction.)
+    unsigned offsetToArgs = 0;
 #if defined(JS_CODEGEN_ARM)
-    extraBytes += sizeof(size_t);
+    offsetToArgs += sizeof(size_t);
 #endif
-    unsigned stackDec = StackDecrementForCall(masm, emptyVector, argBytes + extraBytes);
-    masm.reserveStack(stackDec - extraBytes);
+
+    unsigned stackDecForIonCall = StackDecrementForCall(masm, argBytes + offsetToArgs);
+
+    // Reserve space for a call to AsmJSImm_CoerceInPlace_* and an array of values used by
+    // OOLConvert which reuses the same frame. This code needs to be kept in sync with the
+    // stack usage in GenerateOOLConvert.
+    MIRType typeArray[] = { MIRType_Pointer, MIRType_Pointer }; // cx, argv
+    MIRTypeVector callArgTypes(m.cx());
+    callArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
+    unsigned stackDecForOOLCall = StackDecrementForCall(masm, callArgTypes, sizeof(Value));
+
+    // Allocate a frame large enough for both of the above calls.
+    unsigned stackDec = Max(stackDecForIonCall, stackDecForOOLCall);
+
+    masm.reserveStack(stackDec);
+    AssertStackAlignment(masm);
 
     // 1. Descriptor
-    uint32_t descriptor = MakeFrameDescriptor(masm.framePushed() + extraBytes, JitFrame_Entry);
-    masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, 0));
+    size_t argOffset = offsetToArgs;
+    uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_Entry);
+    masm.storePtr(ImmWord(uintptr_t(descriptor)), Address(StackPointer, argOffset));
+    argOffset += sizeof(size_t);
 
     // 2. Callee
     Register callee = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
 
     // 2.1. Get ExitDatum
     unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
 #if defined(JS_CODEGEN_X64)
@@ -6556,75 +6533,135 @@ GenerateFFIIonExit(ModuleCompiler &m, co
 #else
     masm.lea(Operand(GlobalReg, globalDataOffset), callee);
 #endif
 
     // 2.2. Get callee
     masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
 
     // 2.3. Save callee
-    masm.storePtr(callee, Address(StackPointer, sizeof(size_t)));
+    masm.storePtr(callee, Address(StackPointer, argOffset));
+    argOffset += sizeof(size_t);
 
     // 3. Argc
     unsigned argc = exit.sig().args().length();
-    masm.storePtr(ImmWord(uintptr_t(argc)), Address(StackPointer, 2 * sizeof(size_t)));
+    masm.storePtr(ImmWord(uintptr_t(argc)), Address(StackPointer, argOffset));
+    argOffset += sizeof(size_t);
 
     // 4. |this| value
-    masm.storeValue(UndefinedValue(), Address(StackPointer, 3 * sizeof(size_t)));
+    masm.storeValue(UndefinedValue(), Address(StackPointer, argOffset));
+    argOffset += sizeof(Value);
 
     // 5. Fill the arguments
-    unsigned offsetToArgs = 3 * sizeof(size_t) + sizeof(Value);
     unsigned offsetToCallerStackArgs = masm.framePushed();
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     offsetToCallerStackArgs += NativeFrameSize;
-#else
-    offsetToCallerStackArgs += ShadowStackSpace;
 #endif
-    FillArgumentArray(m, exit.sig().args(), offsetToArgs, offsetToCallerStackArgs, scratch);
+    FillArgumentArray(m, exit.sig().args(), argOffset, offsetToCallerStackArgs, scratch);
+    argOffset += exit.sig().args().length() * sizeof(Value);
+    JS_ASSERT(argOffset == offsetToArgs + argBytes);
 
     // Get the pointer to the ion code
     Label done, oolConvert;
     Label *maybeDebugBreakpoint = nullptr;
 
 #ifdef DEBUG
     Label ionFailed;
     maybeDebugBreakpoint = &ionFailed;
     masm.branchIfFunctionHasNoScript(callee, &ionFailed);
 #endif
 
-    masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), scratch);
-    masm.loadBaselineOrIonNoArgCheck(scratch, scratch, SequentialExecution, maybeDebugBreakpoint);
-
-    LoadAsmJSActivationIntoRegister(masm, callee);
-    masm.push(scratch);
-    masm.setupUnalignedABICall(1, scratch);
-    masm.passABIArg(callee);
-    masm.callWithABI(AsmJSImm_EnableActivationFromAsmJS);
-    masm.pop(scratch);
+    masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), callee);
+    masm.loadBaselineOrIonNoArgCheck(callee, callee, SequentialExecution, maybeDebugBreakpoint);
+
+    AssertStackAlignment(masm);
+
+    {
+        // Enable Activation.
+        //
+        // This sequence requires four registers, and needs to preserve the 'callee'
+        // register, so there are five live registers.
+        JS_ASSERT(callee == AsmJSIonExitRegCallee);
+        Register reg0 = AsmJSIonExitRegE0;
+        Register reg1 = AsmJSIonExitRegE1;
+        Register reg2 = AsmJSIonExitRegE2;
+        Register reg3 = AsmJSIonExitRegE3;
+
+        LoadAsmJSActivationIntoRegister(masm, reg0);
+
+        // The following is inlined:
+        //   JSContext *cx = activation->cx();
+        //   Activation *act = cx->mainThread().activation();
+        //   act.active_ = true;
+        //   act.prevIonTop_ = cx->mainThread().ionTop;
+        //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
+        //   cx->mainThread().jitJSContext = cx;
+        // On the ARM store8() uses the secondScratchReg (lr) as a temp.
+        size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
+                                    PerThreadData::offsetOfActivation();
+        size_t offsetOfIonTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, ionTop);
+        size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
+                                      offsetof(PerThreadData, jitJSContext);
+        masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
+        masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
+        masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
+        masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8()));
+        masm.loadPtr(Address(reg0, offsetOfIonTop), reg2);
+        masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevIonTop()));
+        masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2);
+        masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext()));
+        masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext));
+    }
 
     // 2. Call
-#if defined(JS_CODEGEN_ARM) && defined(DEBUG)
-    // ARM still needs to push, before stack is aligned
-    masm.Push(scratch);
+    AssertStackAlignment(masm);
+#if defined(JS_CODEGEN_ARM)
+    masm.ma_callIonNoPush(callee);
+    // The return address has been popped from the stack, so adjust the stack
+    // without changing the frame-pushed counter to keep the stack aligned.
+    masm.subPtr(Imm32(4), sp);
+#else
+    masm.callIon(callee);
 #endif
     AssertStackAlignment(masm);
-#if defined(JS_CODEGEN_ARM) && defined(DEBUG)
-    masm.freeStack(sizeof(size_t));
-#endif
-    masm.callIon(scratch);
-    masm.freeStack(stackDec - extraBytes);
-
-    masm.push(JSReturnReg_Type);
-    masm.push(JSReturnReg_Data);
-    LoadAsmJSActivationIntoRegister(masm, callee);
-    masm.setupUnalignedABICall(1, scratch);
-    masm.passABIArg(callee);
-    masm.callWithABI(AsmJSImm_DisableActivationFromAsmJS);
-    masm.pop(JSReturnReg_Data);
-    masm.pop(JSReturnReg_Type);
+
+    {
+        // Disable Activation.
+        //
+        // This sequence needs three registers, and must preserve the JSReturnReg_Data and
+        // JSReturnReg_Type, so there are five live registers.
+        JS_ASSERT(JSReturnReg_Data == AsmJSIonExitRegReturnData);
+        JS_ASSERT(JSReturnReg_Type == AsmJSIonExitRegReturnType);
+        Register reg0 = AsmJSIonExitRegD0;
+        Register reg1 = AsmJSIonExitRegD1;
+        Register reg2 = AsmJSIonExitRegD2;
+
+        LoadAsmJSActivationIntoRegister(masm, reg0);
+
+        // The following is inlined:
+        //   JSContext *cx = activation->cx();
+        //   Activation *act = cx->mainThread().activation();
+        //   act.active_ = false;
+        //   cx->mainThread().ionTop = prevIonTop_;
+        //   cx->mainThread().jitJSContext = prevJitJSContext_;
+        // On the ARM store8() uses the secondScratchReg (lr) as a temp.
+        size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
+                                    PerThreadData::offsetOfActivation();
+        size_t offsetOfIonTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, ionTop);
+        size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
+                                      offsetof(PerThreadData, jitJSContext);
+        masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg0);
+        masm.loadPtr(Address(reg0, JSContext::offsetOfRuntime()), reg0);
+        masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
+        masm.store8(Imm32(0), Address(reg1, JitActivation::offsetOfActiveUint8()));
+        masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevIonTop()), reg2);
+        masm.storePtr(reg2, Address(reg0, offsetOfIonTop));
+        masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitJSContext()), reg2);
+        masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext));
+    }
 
 #ifdef DEBUG
     masm.branchTestMagicValue(Assembler::Equal, JSReturnOperand, JS_ION_ERROR, throwLabel);
     masm.branchTestMagic(Assembler::Equal, JSReturnOperand, &ionFailed);
 #else
     masm.branchTestMagic(Assembler::Equal, JSReturnOperand, throwLabel);
 #endif
 
@@ -6640,18 +6677,30 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         masm.convertValueToDouble(JSReturnOperand, ReturnFloatReg, &oolConvert);
         break;
       case RetType::Float:
         MOZ_ASSUME_UNREACHABLE("Float shouldn't be returned from a FFI");
         break;
     }
 
     masm.bind(&done);
-    masm.PopRegsInMask(restoreSet);
+    masm.freeStack(stackDec);
+#if defined(JS_CODEGEN_ARM)
+    masm.ma_vimm(GenericNaN(), NANReg);
+    masm.PopRegsInMask(RegisterSet(GeneralRegisterSet((1<<GlobalReg.code()) |
+                                                      (1<<HeapReg.code()) |
+                                                      (1<<pc.code())),
+                                   FloatRegisterSet(uint32_t(0))));
+#else
+# if defined(JS_CODEGEN_X64)
+    masm.Pop(HeapReg);
+# endif
     masm.ret();
+#endif
+    JS_ASSERT(masm.framePushed() == 0);
 
     // oolConvert
     if (oolConvert.used()) {
         masm.bind(&oolConvert);
         masm.setFramePushed(oolConvertFramePushed);
         GenerateOOLConvert(m, exit.sig().retType(), throwLabel);
         masm.setFramePushed(0);
         masm.jump(&done);
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -144,34 +144,16 @@ CoerceInPlace_ToNumber(JSContext *cx, Mu
     double dbl;
     if (!ToNumber(cx, val, &dbl))
         return false;
     val.set(DoubleValue(dbl));
 
     return true;
 }
 
-static void
-EnableActivationFromAsmJS(AsmJSActivation *activation)
-{
-    JSContext *cx = activation->cx();
-    Activation *act = cx->mainThread().activation();
-    JS_ASSERT(act->isJit());
-    act->asJit()->setActive(cx);
-}
-
-static void
-DisableActivationFromAsmJS(AsmJSActivation *activation)
-{
-    JSContext *cx = activation->cx();
-    Activation *act = cx->mainThread().activation();
-    JS_ASSERT(act->isJit());
-    act->asJit()->setActive(cx, false);
-}
-
 namespace js {
 
 // Defined in AsmJS.cpp:
 
 int32_t
 InvokeFromAsmJS_Ignore(JSContext *cx, int32_t exitIndex, int32_t argc, Value *argv);
 
 int32_t
@@ -237,20 +219,16 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
       case AsmJSImm_InvokeFromAsmJS_ToNumber:
         return RedirectCall(FuncCast(InvokeFromAsmJS_ToNumber), Args_General4);
       case AsmJSImm_CoerceInPlace_ToInt32:
         return RedirectCall(FuncCast(CoerceInPlace_ToInt32), Args_General2);
       case AsmJSImm_CoerceInPlace_ToNumber:
         return RedirectCall(FuncCast(CoerceInPlace_ToNumber), Args_General2);
       case AsmJSImm_ToInt32:
         return RedirectCall(FuncCast<int32_t (double)>(js::ToInt32), Args_Int_Double);
-      case AsmJSImm_EnableActivationFromAsmJS:
-        return RedirectCall(FuncCast(EnableActivationFromAsmJS), Args_General1);
-      case AsmJSImm_DisableActivationFromAsmJS:
-        return RedirectCall(FuncCast(DisableActivationFromAsmJS), Args_General1);
 #if defined(JS_CODEGEN_ARM)
       case AsmJSImm_aeabi_idivmod:
         return RedirectCall(FuncCast(__aeabi_idivmod), Args_General2);
       case AsmJSImm_aeabi_uidivmod:
         return RedirectCall(FuncCast(__aeabi_uidivmod), Args_General2);
 #endif
       case AsmJSImm_ModD:
         return RedirectCall(FuncCast(NumberMod), Args_Double_DoubleDouble);
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -75,17 +75,16 @@ class ABIArgGenerator
 
   public:
     ABIArgGenerator();
     ABIArg next(MIRType argType);
     ABIArg &current() { return current_; }
     uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
     static const Register NonArgReturnVolatileReg0;
     static const Register NonArgReturnVolatileReg1;
-
 };
 
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = r1;
 
 static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg };
 
 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = r3;
@@ -93,16 +92,32 @@ static MOZ_CONSTEXPR_VAR Register JSRetu
 static MOZ_CONSTEXPR_VAR Register StackPointer = sp;
 static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg;
 static MOZ_CONSTEXPR_VAR Register ReturnReg = r0;
 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::d0 };
 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::d15 };
 
 static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::d14 };
 
+// Registers used in the GenerateFFIIonExit Enable Activation block.
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r4;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = r0;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = r1;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = r2;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = r3;
+
+// Registers used in the GenerateFFIIonExit Disable Activation block.
+// None of these may be the second scratch register (lr).
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = r2;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = r3;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = r0;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = r1;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = r4;
+
+
 static MOZ_CONSTEXPR_VAR FloatRegister d0  = {FloatRegisters::d0};
 static MOZ_CONSTEXPR_VAR FloatRegister d1  = {FloatRegisters::d1};
 static MOZ_CONSTEXPR_VAR FloatRegister d2  = {FloatRegisters::d2};
 static MOZ_CONSTEXPR_VAR FloatRegister d3  = {FloatRegisters::d3};
 static MOZ_CONSTEXPR_VAR FloatRegister d4  = {FloatRegisters::d4};
 static MOZ_CONSTEXPR_VAR FloatRegister d5  = {FloatRegisters::d5};
 static MOZ_CONSTEXPR_VAR FloatRegister d6  = {FloatRegisters::d6};
 static MOZ_CONSTEXPR_VAR FloatRegister d7  = {FloatRegisters::d7};
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -685,18 +685,16 @@ enum AsmJSImmKind
     AsmJSImm_ReportOverRecursed,
     AsmJSImm_HandleExecutionInterrupt,
     AsmJSImm_InvokeFromAsmJS_Ignore,
     AsmJSImm_InvokeFromAsmJS_ToInt32,
     AsmJSImm_InvokeFromAsmJS_ToNumber,
     AsmJSImm_CoerceInPlace_ToInt32,
     AsmJSImm_CoerceInPlace_ToNumber,
     AsmJSImm_ToInt32,
-    AsmJSImm_EnableActivationFromAsmJS,
-    AsmJSImm_DisableActivationFromAsmJS,
 #if defined(JS_CODEGEN_ARM)
     AsmJSImm_aeabi_idivmod,
     AsmJSImm_aeabi_uidivmod,
 #endif
     AsmJSImm_ModD,
     AsmJSImm_SinD,
     AsmJSImm_CosD,
     AsmJSImm_TanD,
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -131,16 +131,30 @@ static MOZ_CONSTEXPR_VAR FloatRegister F
 
 // The convention used by the ForkJoinGetSlice stub. None of these can be rax
 // or rdx, which the stub also needs for cmpxchg and div, respectively.
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_cx = rdi;
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp0 = rbx;
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp1 = rcx;
 static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_output = rsi;
 
+// Registers used in the GenerateFFIIonExit Enable Activation block.
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r10;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = rax;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = rdi;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = rbx;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = rsi;
+
+// Registers used in the GenerateFFIIonExit Disable Activation block.
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = ecx;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = ecx;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = rax;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = rdi;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = rbx;
+
 class ABIArgGenerator
 {
 #if defined(XP_WIN)
     unsigned regIndex_;
 #else
     unsigned intRegIndex_;
     unsigned floatRegIndex_;
 #endif
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -82,16 +82,30 @@ class ABIArgGenerator
     static const Register NonArgReturnVolatileReg0;
     static const Register NonArgReturnVolatileReg1;
     static const Register NonVolatileReg;
 };
 
 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = edx;
 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = edx;
 
+// Registers used in the GenerateFFIIonExit Enable Activation block.
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = ecx;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = edi;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = eax;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = ebx;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = edx;
+
+// Registers used in the GenerateFFIIonExit Disable Activation block.
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = edx;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = ecx;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = edi;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = eax;
+static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = esi;
+
 // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in
 // jitted code.
 #if defined(__GNUC__)
 static const uint32_t StackAlignment = 16;
 #else
 static const uint32_t StackAlignment = 4;
 #endif
 static const bool StackKeptAligned = false;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -403,16 +403,20 @@ struct JSContext : public js::ExclusiveC
                    public mozilla::LinkedListElement<JSContext>
 {
     explicit JSContext(JSRuntime *rt);
     ~JSContext();
 
     JSRuntime *runtime() const { return runtime_; }
     js::PerThreadData &mainThread() const { return runtime()->mainThread; }
 
+    static size_t offsetOfRuntime() {
+        return offsetof(JSContext, runtime_);
+    }
+
     friend class js::ExclusiveContext;
     friend class JS::AutoSaveExceptionState;
 
   private:
     /* Exception state -- the exception member is a GC root by definition. */
     bool                throwing;            /* is there a pending exception? */
     js::Value           unwrappedException_; /* most-recently-thrown exception */
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -578,16 +578,19 @@ class PerThreadData : public PerThreadDa
 
   public:
     js::Activation *const *addressOfActivation() const {
         return &activation_;
     }
     static unsigned offsetOfAsmJSActivationStackReadOnly() {
         return offsetof(PerThreadData, asmJSActivationStack_);
     }
+    static unsigned offsetOfActivation() {
+        return offsetof(PerThreadData, activation_);
+    }
 
     js::AsmJSActivation *asmJSActivationStackFromAnyThread() const {
         return asmJSActivationStack_;
     }
     js::AsmJSActivation *asmJSActivationStackFromOwnerThread() const {
         return asmJSActivationStack_;
     }
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1511,16 +1511,19 @@ jit::JitActivation::JitActivation(JSCont
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         cx_->mainThread().ionTop = prevIonTop_;
         cx_->mainThread().jitJSContext = prevJitJSContext_;
     }
 }
 
+// setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
+// changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
+// and disable activation instruction sequences.
 void
 jit::JitActivation::setActive(JSContext *cx, bool active)
 {
     // Only allowed to deactivate/activate if activation is top.
     // (Not tested and will probably fail in other situations.)
     JS_ASSERT(cx->mainThread().activation_ == this);
     JS_ASSERT(active != active_);
     active_ = active;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1330,16 +1330,26 @@ class JitActivation : public Activation
         return prevIonTop_;
     }
     JSCompartment *compartment() const {
         return compartment_;
     }
     bool firstFrameIsConstructing() const {
         return firstFrameIsConstructing_;
     }
+    static size_t offsetOfPrevIonTop() {
+        return offsetof(JitActivation, prevIonTop_);
+    }
+    static size_t offsetOfPrevJitJSContext() {
+        return offsetof(JitActivation, prevJitJSContext_);
+    }
+    static size_t offsetOfActiveUint8() {
+        JS_ASSERT(sizeof(bool) == 1);
+        return offsetof(JitActivation, active_);
+    }
 
 #ifdef CHECK_OSIPOINT_REGISTERS
     void setCheckRegs(bool check) {
         checkRegs_ = check;
     }
     static size_t offsetOfCheckRegs() {
         return offsetof(JitActivation, checkRegs_);
     }
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -371,29 +371,16 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
 
         MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(parent),
                    "Xray wrapper being used to parent XPCWrappedNative?");
 
         ac.construct(static_cast<JSContext*>(cx), parent);
 
         if (parent != plannedParent) {
             XPCWrappedNativeScope* betterScope = GetObjectScope(parent);
-            if (MOZ_UNLIKELY(!betterScope)) {
-                printf_stderr("Uh oh, hit an object without a scope! Crashing shortly.\n");
-                printf_stderr("IsMainThread: %u\n", (uint32_t) NS_IsMainThread());
-                char* className = nullptr;
-                sciWrapper.GetCallback()->GetClassName(&className);
-                printf_stderr("SH Class Name: %s\n", className);
-                nsMemory::Free(className);
-                printf_stderr("plannedParent object class: %s\n", js::GetObjectClass(plannedParent)->name);
-                printf_stderr("plannedParent Global class: %s\n", js::GetObjectClass(js::GetGlobalForObjectCrossCompartment(plannedParent))->name);
-                printf_stderr("parent Object class: %s\n", js::GetObjectClass(parent)->name);
-                printf_stderr("parent Global class: %s\n", js::GetObjectClass(js::GetGlobalForObjectCrossCompartment(parent))->name);
-                MOZ_CRASH();
-            }
             if (betterScope != Scope)
                 return GetNewOrUsed(helper, betterScope, Interface, resultWrapper);
 
             newParentVal = OBJECT_TO_JSVAL(parent);
         }
 
         // Take the performance hit of checking the hashtable again in case
         // the preCreate call caused the wrapper to get created through some
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -733,17 +733,17 @@ protected:
   bool ParseQuotes();
   bool ParseSize();
   bool ParseTextAlign(nsCSSValue& aValue,
                       const KTableValue aTable[]);
   bool ParseTextAlign(nsCSSValue& aValue);
   bool ParseTextAlignLast(nsCSSValue& aValue);
   bool ParseTextDecoration();
   bool ParseTextDecorationLine(nsCSSValue& aValue);
-  bool ParseTextCombineHorizontal(nsCSSValue& aValue);
+  bool ParseTextCombineUpright(nsCSSValue& aValue);
   bool ParseTextOverflow(nsCSSValue& aValue);
   bool ParseTouchAction(nsCSSValue& aValue);
 
   bool ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow);
   bool ParseShadowList(nsCSSProperty aProperty);
   bool ParseTransitionProperty();
   bool ParseTransitionTimingFunctionValues(nsCSSValue& aValue);
   bool ParseTransitionTimingFunctionValueComponent(float& aComponent,
@@ -9317,18 +9317,18 @@ CSSParserImpl::ParseSingleValueProperty(
       case eCSSProperty_marks:
         return ParseMarks(aValue);
       case eCSSProperty_text_align:
         return ParseTextAlign(aValue);
       case eCSSProperty_text_align_last:
         return ParseTextAlignLast(aValue);
       case eCSSProperty_text_decoration_line:
         return ParseTextDecorationLine(aValue);
-      case eCSSProperty_text_combine_horizontal:
-        return ParseTextCombineHorizontal(aValue);
+      case eCSSProperty_text_combine_upright:
+        return ParseTextCombineUpright(aValue);
       case eCSSProperty_text_overflow:
         return ParseTextOverflow(aValue);
       case eCSSProperty_touch_action:
         return ParseTouchAction(aValue);
       default:
         NS_ABORT_IF_FALSE(false, "should not reach here");
         return false;
     }
@@ -12428,39 +12428,39 @@ CSSParserImpl::ParseTouchAction(nsCSSVal
 
     aValue.SetIntValue(nextIntValue | intValue, eCSSUnit_Enumerated);
   }
 
   return true;
 }
 
 bool
-CSSParserImpl::ParseTextCombineHorizontal(nsCSSValue& aValue)
+CSSParserImpl::ParseTextCombineUpright(nsCSSValue& aValue)
 {
   if (!ParseVariant(aValue, VARIANT_HK,
-                    nsCSSProps::kTextCombineHorizontalKTable)) {
+                    nsCSSProps::kTextCombineUprightKTable)) {
     return false;
   }
 
   // if 'digits', need to check for an explicit number [2, 3, 4]
   if (eCSSUnit_Enumerated == aValue.GetUnit() &&
-      aValue.GetIntValue() == NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_2) {
+      aValue.GetIntValue() == NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
     if (!GetToken(true)) {
       return true;
     }
     if (mToken.mType == eCSSToken_Number && mToken.mIntegerValid) {
       switch (mToken.mInteger) {
         case 2:  // already set, nothing to do
           break;
         case 3:
-          aValue.SetIntValue(NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_3,
+          aValue.SetIntValue(NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3,
                              eCSSUnit_Enumerated);
           break;
         case 4:
-          aValue.SetIntValue(NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_4,
+          aValue.SetIntValue(NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_4,
                              eCSSUnit_Enumerated);
           break;
         default:
           // invalid digits value
           return false;
       }
     } else {
       UngetToken();
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3006,25 +3006,25 @@ CSS_PROP_TEXT(
     eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
     text-decoration,
     text_decoration,
     TextDecoration,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
 CSS_PROP_TEXT(
-    text-combine-horizontal,
-    text_combine_horizontal,
-    TextCombineHorizontal,
+    text-combine-upright,
+    text_combine_upright,
+    TextCombineUpright,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_PARSER_FUNCTION,
     "layout.css.vertical-text.enabled",
     0,
-    kTextCombineHorizontalKTable,
-    offsetof(nsStyleText, mTextCombineHorizontal),
+    kTextCombineUprightKTable,
+    offsetof(nsStyleText, mTextCombineUpright),
     eStyleAnimType_EnumU8)
 CSS_PROP_TEXTRESET(
     -moz-text-decoration-color,
     text_decoration_color,
     CSS_PROP_DOMPROP_PREFIXED(TextDecorationColor),
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1565,20 +1565,20 @@ KTableValue nsCSSProps::kTextAlignLastKT
   eCSSKeyword_center, NS_STYLE_TEXT_ALIGN_CENTER,
   eCSSKeyword_justify, NS_STYLE_TEXT_ALIGN_JUSTIFY,
   eCSSKeyword_start, NS_STYLE_TEXT_ALIGN_DEFAULT,
   eCSSKeyword_end, NS_STYLE_TEXT_ALIGN_END,
   eCSSKeyword_true, NS_STYLE_TEXT_ALIGN_TRUE,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const KTableValue nsCSSProps::kTextCombineHorizontalKTable[] = {
-  eCSSKeyword_none, NS_STYLE_TEXT_COMBINE_HORIZ_NONE,
-  eCSSKeyword_all, NS_STYLE_TEXT_COMBINE_HORIZ_ALL,
-  eCSSKeyword_digits, NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_2,  // w/o number ==> 2
+const KTableValue nsCSSProps::kTextCombineUprightKTable[] = {
+  eCSSKeyword_none, NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE,
+  eCSSKeyword_all, NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL,
+  eCSSKeyword_digits, NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2,  // w/o number ==> 2
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kTextDecorationLineKTable[] = {
   eCSSKeyword_none, NS_STYLE_TEXT_DECORATION_LINE_NONE,
   eCSSKeyword_underline, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
   eCSSKeyword_overline, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE,
   eCSSKeyword_line_through, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -613,17 +613,17 @@ public:
   static const KTableValue kSpeakPunctuationKTable[];
   static const KTableValue kSpeechRateKTable[];
   static const KTableValue kStackSizingKTable[];
   static const KTableValue kTableLayoutKTable[];
   // Not const because we modify its entries when the pref
   // "layout.css.text-align-true-value.enabled" changes:
   static KTableValue kTextAlignKTable[];
   static KTableValue kTextAlignLastKTable[];
-  static const KTableValue kTextCombineHorizontalKTable[];
+  static const KTableValue kTextCombineUprightKTable[];
   static const KTableValue kTextDecorationLineKTable[];
   static const KTableValue kTextDecorationStyleKTable[];
   static const KTableValue kTextOrientationKTable[];
   static const KTableValue kTextOverflowKTable[];
   static const KTableValue kTextTransformKTable[];
   static const KTableValue kTouchActionKTable[];
   static const KTableValue kTransitionTimingFunctionKTable[];
   static const KTableValue kUnicodeBidiKTable[];
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -948,23 +948,23 @@ nsCSSValue::AppendToString(nsCSSProperty
   else if (eCSSUnit_Integer == unit) {
     aResult.AppendInt(GetIntValue(), 10);
   }
   else if (eCSSUnit_Enumerated == unit) {
     int32_t intValue = GetIntValue();
     switch(aProperty) {
 
 
-    case eCSSProperty_text_combine_horizontal:
-      if (intValue <= NS_STYLE_TEXT_COMBINE_HORIZ_ALL) {
+    case eCSSProperty_text_combine_upright:
+      if (intValue <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
         AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, intValue),
                            aResult);
-      } else if (intValue == NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_2) {
+      } else if (intValue == NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
         aResult.AppendLiteral("digits 2");
-      } else if (intValue == NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_3) {
+      } else if (intValue == NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
         aResult.AppendLiteral("digits 3");
       } else {
         aResult.AppendLiteral("digits 4");
       }
       break;
 
     case eCSSProperty_text_decoration_line:
       if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3120,28 +3120,28 @@ CSSValue*
 nsComputedDOMStyle::DoGetTextAlignLast()
 {
   const nsStyleText* style = StyleText();
   return CreateTextAlignValue(style->mTextAlignLast, style->mTextAlignLastTrue,
                               nsCSSProps::kTextAlignLastKTable);
 }
 
 CSSValue*
-nsComputedDOMStyle::DoGetTextCombineHorizontal()
+nsComputedDOMStyle::DoGetTextCombineUpright()
 {
   nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
-  uint8_t tch = StyleText()->mTextCombineHorizontal;
-
-  if (tch <= NS_STYLE_TEXT_COMBINE_HORIZ_ALL) {
+  uint8_t tch = StyleText()->mTextCombineUpright;
+
+  if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
     val->SetIdent(
       nsCSSProps::ValueToKeywordEnum(tch,
-                                     nsCSSProps::kTextCombineHorizontalKTable));
-  } else if (tch <= NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_2) {
+                                     nsCSSProps::kTextCombineUprightKTable));
+  } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
     val->SetString(NS_LITERAL_STRING("digits 2"));
-  } else if (tch <= NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_3) {
+  } else if (tch <= NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
     val->SetString(NS_LITERAL_STRING("digits 3"));
   } else {
     val->SetString(NS_LITERAL_STRING("digits 4"));
   }
 
   return val;
 }
 
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -371,17 +371,17 @@ private:
   mozilla::dom::CSSValue* DoGetListStylePosition();
   mozilla::dom::CSSValue* DoGetListStyleType();
   mozilla::dom::CSSValue* DoGetImageRegion();
 
   /* Text Properties */
   mozilla::dom::CSSValue* DoGetLineHeight();
   mozilla::dom::CSSValue* DoGetTextAlign();
   mozilla::dom::CSSValue* DoGetTextAlignLast();
-  mozilla::dom::CSSValue* DoGetTextCombineHorizontal();
+  mozilla::dom::CSSValue* DoGetTextCombineUpright();
   mozilla::dom::CSSValue* DoGetTextDecoration();
   mozilla::dom::CSSValue* DoGetTextDecorationColor();
   mozilla::dom::CSSValue* DoGetTextDecorationLine();
   mozilla::dom::CSSValue* DoGetTextDecorationStyle();
   mozilla::dom::CSSValue* DoGetTextIndent();
   mozilla::dom::CSSValue* DoGetTextOrientation();
   mozilla::dom::CSSValue* DoGetTextOverflow();
   mozilla::dom::CSSValue* DoGetTextTransform();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -190,17 +190,17 @@ COMPUTED_STYLE_PROP(perspective_origin, 
 COMPUTED_STYLE_PROP(pointer_events,                PointerEvents)
 COMPUTED_STYLE_PROP(position,                      Position)
 COMPUTED_STYLE_PROP(quotes,                        Quotes)
 COMPUTED_STYLE_PROP(resize,                        Resize)
 COMPUTED_STYLE_PROP(right,                         Right)
 //// COMPUTED_STYLE_PROP(size,                     Size)
 COMPUTED_STYLE_PROP(table_layout,                  TableLayout)
 COMPUTED_STYLE_PROP(text_align,                    TextAlign)
-COMPUTED_STYLE_PROP(text_combine_horizontal,       TextCombineHorizontal)
+COMPUTED_STYLE_PROP(text_combine_upright,          TextCombineUpright)
 COMPUTED_STYLE_PROP(text_decoration,               TextDecoration)
 COMPUTED_STYLE_PROP(text_indent,                   TextIndent)
 COMPUTED_STYLE_PROP(text_orientation,              TextOrientation)
 COMPUTED_STYLE_PROP(text_overflow,                 TextOverflow)
 COMPUTED_STYLE_PROP(text_shadow,                   TextShadow)
 COMPUTED_STYLE_PROP(text_transform,                TextTransform)
 COMPUTED_STYLE_PROP(top,                           Top)
 COMPUTED_STYLE_PROP(touch_action,                  TouchAction)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -4256,23 +4256,23 @@ nsRuleNode::ComputeTextData(void* aStart
 
   // text-orientation: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForTextOrientation(), text->mTextOrientation,
               canStoreInRuleTree,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
               parentText->mTextOrientation,
               NS_STYLE_TEXT_ORIENTATION_AUTO, 0, 0, 0, 0);
 
-  // text-combine-horizontal: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForTextCombineHorizontal(),
-              text->mTextCombineHorizontal,
+  // text-combine-upright: enum, inherit, initial
+  SetDiscrete(*aRuleData->ValueForTextCombineUpright(),
+              text->mTextCombineUpright,
               canStoreInRuleTree,
               SETDSC_ENUMERATED | SETDSC_UNSET_INHERIT,
-              parentText->mTextCombineHorizontal,
-              NS_STYLE_TEXT_COMBINE_HORIZ_NONE, 0, 0, 0, 0);
+              parentText->mTextCombineUpright,
+              NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE, 0, 0, 0, 0);
 
   COMPUTE_END_INHERITED(Text, text)
 }
 
 const void*
 nsRuleNode::ComputeTextResetData(void* aStartStruct,
                                  const nsRuleData* aRuleData,
                                  nsStyleContext* aContext,
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -838,21 +838,21 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_TEXT_SIZE_ADJUST_AUTO          1
 
 // See nsStyleText
 #define NS_STYLE_TEXT_ORIENTATION_AUTO          0
 #define NS_STYLE_TEXT_ORIENTATION_UPRIGHT       1
 #define NS_STYLE_TEXT_ORIENTATION_SIDEWAYS      2
 
 // See nsStyleText
-#define NS_STYLE_TEXT_COMBINE_HORIZ_NONE        0
-#define NS_STYLE_TEXT_COMBINE_HORIZ_ALL         1
-#define NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_2    2
-#define NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_3    3
-#define NS_STYLE_TEXT_COMBINE_HORIZ_DIGITS_4    4
+#define NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE        0
+#define NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL         1
+#define NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2    2
+#define NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3    3
+#define NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_4    4
 
 // See nsStyleText
 #define NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT       0
 
 // See nsStyleText
 #define NS_STYLE_UNICODE_BIDI_NORMAL            0x0
 #define NS_STYLE_UNICODE_BIDI_EMBED             0x1
 #define NS_STYLE_UNICODE_BIDI_ISOLATE           0x2
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3053,17 +3053,17 @@ nsStyleText::nsStyleText(void)
   mTextAlignLastTrue = false;
   mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
   mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
   mWordBreak = NS_STYLE_WORDBREAK_NORMAL;
   mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
   mHyphens = NS_STYLE_HYPHENS_MANUAL;
   mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
   mTextOrientation = NS_STYLE_TEXT_ORIENTATION_AUTO;
-  mTextCombineHorizontal = NS_STYLE_TEXT_COMBINE_HORIZ_NONE;
+  mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE;
   mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
 
   mLetterSpacing.SetNormalValue();
   mLineHeight.SetNormalValue();
   mTextIndent.SetCoordValue(0);
   mWordSpacing = 0;
 
   mTextShadow = nullptr;
@@ -3077,17 +3077,17 @@ nsStyleText::nsStyleText(const nsStyleTe
     mTextAlignLastTrue(false),
     mTextTransform(aSource.mTextTransform),
     mWhiteSpace(aSource.mWhiteSpace),
     mWordBreak(aSource.mWordBreak),
     mWordWrap(aSource.mWordWrap),
     mHyphens(aSource.mHyphens),
     mTextSizeAdjust(aSource.mTextSizeAdjust),
     mTextOrientation(aSource.mTextOrientation),
-    mTextCombineHorizontal(aSource.mTextCombineHorizontal),
+    mTextCombineUpright(aSource.mTextCombineUpright),
     mControlCharacterVisibility(aSource.mControlCharacterVisibility),
     mTabSize(aSource.mTabSize),
     mWordSpacing(aSource.mWordSpacing),
     mLetterSpacing(aSource.mLetterSpacing),
     mLineHeight(aSource.mLineHeight),
     mTextIndent(aSource.mTextIndent),
     mTextShadow(aSource.mTextShadow)
 {
@@ -3102,17 +3102,17 @@ nsStyleText::~nsStyleText(void)
 nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
 {
   if (WhiteSpaceOrNewlineIsSignificant() !=
       aOther.WhiteSpaceOrNewlineIsSignificant()) {
     // This may require construction of suppressed text frames
     return NS_STYLE_HINT_FRAMECHANGE;
   }
 
-  if (mTextCombineHorizontal != aOther.mTextCombineHorizontal ||
+  if (mTextCombineUpright != aOther.mTextCombineUpright ||
       mControlCharacterVisibility != aOther.mControlCharacterVisibility) {
     return nsChangeHint_ReconstructFrame;
   }
 
   if ((mTextAlign != aOther.mTextAlign) ||
       (mTextAlignLast != aOther.mTextAlignLast) ||
       (mTextAlignTrue != aOther.mTextAlignTrue) ||
       (mTextAlignLastTrue != aOther.mTextAlignLastTrue) ||
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1521,17 +1521,17 @@ struct nsStyleText {
   bool mTextAlignLastTrue : 1;          // [inherited] see nsStyleConsts.h
   uint8_t mTextTransform;               // [inherited] see nsStyleConsts.h
   uint8_t mWhiteSpace;                  // [inherited] see nsStyleConsts.h
   uint8_t mWordBreak;                   // [inherited] see nsStyleConsts.h
   uint8_t mWordWrap;                    // [inherited] see nsStyleConsts.h
   uint8_t mHyphens;                     // [inherited] see nsStyleConsts.h
   uint8_t mTextSizeAdjust;              // [inherited] see nsStyleConsts.h
   uint8_t mTextOrientation;             // [inherited] see nsStyleConsts.h
-  uint8_t mTextCombineHorizontal;       // [inherited] see nsStyleConsts.h
+  uint8_t mTextCombineUpright;          // [inherited] see nsStyleConsts.h
   uint8_t mControlCharacterVisibility;  // [inherited] see nsStyleConsts.h
   int32_t mTabSize;                     // [inherited] see nsStyleConsts.h
 
   nscoord mWordSpacing;                 // [inherited]
   nsStyleCoord  mLetterSpacing;         // [inherited] coord, normal
   nsStyleCoord  mLineHeight;            // [inherited] coord, factor, normal
   nsStyleCoord  mTextIndent;            // [inherited] coord, percent, calc
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4393,18 +4393,18 @@ if (SpecialPowers.getBoolPref("layout.cs
 		"text-orientation": {
 			domProp: "textOrientation",
 			inherited: true,
 			type: CSS_TYPE_LONGHAND,
 			initial_values: [ "auto" ],
 			other_values: [ "upright", "sideways" ],
 			invalid_values: [ "none", "3em" ]
 		},
-		"text-combine-horizontal": {
-			domProp: "textCombineHorizontal",
+		"text-combine-upright": {
+			domProp: "textCombineUpright",
 			inherited: true,
 			type: CSS_TYPE_LONGHAND,
 			initial_values: [ "none" ],
 			other_values: [ "all", "digits", "digits 2", "digits 3", "digits 4", "digits     3" ],
 			invalid_values: [ "auto", "all 2", "none all", "digits -3", "digits 0",
 			                  "digits 12", "none 3", "digits 3.1415", "digits3", "digits 1",
 			                  "digits 3 all", "digits foo", "digits all", "digits 3.0" ]
 		}
--- a/layout/style/test/test_computed_style_prefs.html
+++ b/layout/style/test/test_computed_style_prefs.html
@@ -63,17 +63,17 @@ function step() {
   gPrefsPushed = true;
   SpecialPowers.pushPrefEnv(gTests[gTestIndex].settings,
                             function() { fn(); SimpleTest.executeSoon(step); });
 }
 
 // ----
 
 var gProps = {
-  "layout.css.vertical-text.enabled": ["text-combine-horizontal", "text-orientation", "writing-mode"],
+  "layout.css.vertical-text.enabled": ["text-combine-upright", "text-orientation", "writing-mode"],
   "layout.css.font-features.enabled": ["font-kerning", "font-synthesis", "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", "font-variant-position"],
   "layout.css.image-orientation.enabled": ["image-orientation"],
   "layout.css.mix-blend-mode.enabled": ["mix-blend-mode"],
   "layout.css.masking.enabled": ["mask-type"],
   "layout.css.touch_action.enabled": ["touch-action"]
 };
 
 var gCS = getComputedStyle(document.body, "");
--- a/layout/tools/reftest/reftest.js
+++ b/layout/tools/reftest/reftest.js
@@ -1682,16 +1682,21 @@ function RecordResult(testRunTime, error
         default:
             throw "Unexpected state.";
     }
 }
 
 function LoadFailed(why)
 {
     ++gTestResults.FailedLoad;
+    // Once bug 896840 is fixed, this can go away, but for now it will give log
+    // output that is TBPL starable for bug 789751 and bug 720452.
+    if (!why) {
+        gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | load failed with unknown reason\n");
+    }
     gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | " +
          gURLs[0]["url" + gState].spec + " | load failed: " + why + "\n");
     FlushTestLog();
     FinishTestItem();
 }
 
 function RemoveExpectedCrashDumpFiles()
 {
--- a/mobile/android/base/tests/testPictureLinkContextMenu.java
+++ b/mobile/android/base/tests/testPictureLinkContextMenu.java
@@ -5,41 +5,39 @@ public class testPictureLinkContextMenu 
 
     // Test website strings
     private static String PICTURE_PAGE_URL;
     private static String BLANK_PAGE_URL;
     private static final String PICTURE_PAGE_TITLE = "Picture Link";
     private static final String tabs [] = { "Image", "Link" };
     private static final String photoMenuItems [] = { "Copy Image Location", "Share Image", "Set Image As", "Save Image" };
     private static final String linkMenuItems [] = { "Open Link in New Tab", "Open Link in Private Tab", "Copy Link", "Share Link", "Bookmark Link"};
-    private static final String linkTitle = "^Link$";
+    private static final String imageTitle = "^Image$";
 
     public void testPictureLinkContextMenu() {
         blockForGeckoReady();
 
         PICTURE_PAGE_URL=getAbsoluteUrl("/robocop/robocop_picture_link.html");
         BLANK_PAGE_URL=getAbsoluteUrl("/robocop/robocop_blank_02.html");
         loadAndPaint(PICTURE_PAGE_URL);
         verifyPageTitle(PICTURE_PAGE_TITLE);
 
+        switchTabs(imageTitle);
         verifyContextMenuItems(photoMenuItems);
         verifyTabs(tabs);
+        switchTabs(imageTitle);
         verifyCopyOption(photoMenuItems[0], "Firefox.jpg"); // Test the "Copy Image Location" option
+        switchTabs(imageTitle);
         verifyShareOption(photoMenuItems[1], PICTURE_PAGE_TITLE); // Test the "Share Image" option
 
-        switchTabs(linkTitle);
         verifyContextMenuItems(linkMenuItems);
         openTabFromContextMenu(linkMenuItems[0],2); // Test the "Open in New Tab" option - expecting 2 tabs: the original and the new one
-        switchTabs(linkTitle);
         openTabFromContextMenu(linkMenuItems[1],2); // Test the "Open in Private Tab" option - expecting only 2 tabs in normal mode
-        switchTabs(linkTitle);
         verifyCopyOption(linkMenuItems[2], BLANK_PAGE_URL); // Test the "Copy Link" option
-        switchTabs(linkTitle);
         verifyShareOption(linkMenuItems[3], PICTURE_PAGE_TITLE); // Test the "Share Link" option
-        switchTabs(linkTitle);
         verifyBookmarkLinkOption(linkMenuItems[4],BLANK_PAGE_URL); // Test the "Bookmark Link" option
     }
 
     @Override
     public void tearDown() throws Exception {
         mDatabaseHelper.deleteBookmark(BLANK_PAGE_URL);
         super.tearDown();
     }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2097,16 +2097,21 @@ var NativeWindow = {
     },
 
     set _target(aTarget) {
       if (aTarget)
         this._targetRef = Cu.getWeakReference(aTarget);
       else this._targetRef = null;
     },
 
+    get defaultContext() {
+      delete this.defaultContext;
+      return this.defaultContext = Strings.browser.GetStringFromName("browser.menu.context.default");
+    },
+
     /* Gets menuitems for an arbitrary node
      * Parameters:
      *   element - The element to look at. If this element has a contextmenu attribute, the
      *             corresponding contextmenu will be used.
      */
     _getHTMLContextMenuItemsForElement: function(element) {
       let htmlMenu = element.contextMenu;
       if (!htmlMenu) {
@@ -2178,17 +2183,17 @@ var NativeWindow = {
       }
 
       // Otherwise we try the nodeName
       try {
         return Strings.browser.GetStringFromName("browser.menu.context." + element.nodeName.toLowerCase());
       } catch(ex) { }
 
       // Fallback to the default
-      return Strings.browser.GetStringFromName("browser.menu.context.default");
+      return this.defaultContext;
     },
 
     // Adds context menu items added through the add-on api
     _getNativeContextMenuItems: function(element, x, y) {
       let res = [];
       for (let itemId of Object.keys(this.items)) {
         let item = this.items[itemId];
 
@@ -2333,17 +2338,18 @@ var NativeWindow = {
      * menus, will return an array with appropriate tabs/items inside it. i.e. :
      * [
      *    { label: "link", items: [...] },
      *    { label: "image", items: [...] }
      * ]
      */
     _reformatList: function(target) {
       let contexts = Object.keys(this.menus);
-      if (contexts.length == 1) {
+
+      if (contexts.length === 1) {
         // If there's only one context, we'll only show a single flat single select list
         return this._reformatMenuItems(target, this.menus[contexts[0]]);
       }
 
       // If there are multiple contexts, we'll only show a tabbed ui with multiple lists
       return this._reformatListAsTabs(target, this.menus);
     },
 
@@ -2352,22 +2358,34 @@ var NativeWindow = {
      * { link: [...], image: [...] } becomes
      * [ { label: "link", items: [...] } ]
      *
      * Also reformats items and resolves any parmaeters that aren't known until display time
      * (for instance Helper app menu items adjust their title to reflect what Helper App can be used for this link).
      */
     _reformatListAsTabs: function(target, menus) {
       let itemArray = [];
-      for (let context in menus) {
+
+      // Sort the keys so that "link" is always first
+      let contexts = Object.keys(this.menus);
+      contexts.sort((context1, context2) => {
+        if (context1 === this.defaultContext) {
+          return -1;
+        } else if (context2 === this.defaultContext) {
+          return 1;
+        }
+        return 0;
+      });
+
+      contexts.forEach(context => {
         itemArray.push({
           label: context,
           items: this._reformatMenuItems(target, menus[context])
         });
-      }
+      });
 
       return itemArray;
     },
 
     /* Reformats an array of ContextMenuItems into an array that can be handled by Prompt.jsm. Also reformats items
      * and resolves any parmaeters that aren't known until display time
      * (for instance Helper app menu items adjust their title to reflect what Helper App can be used for this link).
      */
@@ -8381,18 +8399,20 @@ HTMLContextMenuItem.prototype = Object.c
 
           let elt = this.menuElementRef.get();
           let target = this.targetElementRef.get();
           if (!elt) {
             return;
           }
 
           var items = NativeWindow.contextmenus._getHTMLContextMenuItemsForMenu(elt, target);
+          // This menu will always only have one context, but we still make sure its the "right" one.
+          var context = NativeWindow.contextmenus._getContextType(target);
           if (items.length > 0) {
-            NativeWindow.contextmenus._addMenuItems(items, "link");
+            NativeWindow.contextmenus._addMenuItems(items, context);
           }
 
         } catch(ex) {
           Cu.reportError(ex);
         }
       } else {
         // otherwise just click the menu item
         elt.click();
--- a/netwerk/protocol/rtsp/rtsp/RTSPConnectionHandler.h
+++ b/netwerk/protocol/rtsp/rtsp/RTSPConnectionHandler.h
@@ -121,16 +121,17 @@ struct RtspConnectionHandler : public AH
           mNetLooper(new ALooper),
           mConn(new ARTSPConnection(mUIDValid, mUID)),
           mRTPConn(new ARTPConnection),
           mOriginalSessionURL(url),
           mSessionURL(url),
           mSetupTracksSuccessful(false),
           mSeekPending(false),
           mPausePending(false),
+          mAborted(false),
           mFirstAccessUnit(true),
           mNTPAnchorUs(-1),
           mMediaAnchorUs(-1),
           mLastMediaTimeUs(0),
           mNumAccessUnitsReceived(0),
           mCheckPending(false),
           mCheckGeneration(0),
           mTryTCPInterleaving(false),
@@ -407,16 +408,17 @@ struct RtspConnectionHandler : public AH
     }
 
     virtual void onMessageReceived(const sp<AMessage> &msg) {
         switch (msg->what()) {
             case 'conn':
             {
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
+                mAborted = false;
 
                 LOGI("connection request completed with result %d (%s)",
                      result, strerror(-result));
 
                 if (result == OK) {
                     AString request;
                     request = "DESCRIBE ";
                     request.append(mSessionURL);
@@ -454,16 +456,20 @@ struct RtspConnectionHandler : public AH
 
             case 'desc':
             {
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
 
                 LOGI("DESCRIBE completed with result %d (%s)",
                      result, strerror(-result));
+                if (mAborted) {
+                  LOGV("we're aborted, dropping stale packet.");
+                  break;
+                }
 
                 if (result == OK) {
                     sp<RefBase> obj;
                     CHECK(msg->findObject("response", &obj));
                     sp<ARTSPResponse> response =
                         static_cast<ARTSPResponse *>(obj.get());
 
                     if (response->mStatusCode == 302) {
@@ -573,16 +579,20 @@ struct RtspConnectionHandler : public AH
                     track = &mTracks.editItemAt(trackIndex);
                 }
 
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
 
                 LOGI("SETUP(%d) completed with result %d (%s)",
                      index, result, strerror(-result));
+                if (mAborted) {
+                  LOGV("we're aborted, dropping stale packet.");
+                  break;
+                }
 
                 if (result == OK) {
                     CHECK(track != NULL);
 
                     sp<RefBase> obj;
                     CHECK(msg->findObject("response", &obj));
                     sp<ARTSPResponse> response =
                         static_cast<ARTSPResponse *>(obj.get());
@@ -706,16 +716,20 @@ struct RtspConnectionHandler : public AH
                  break;
             case 'play':
             {
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
 
                 LOGI("PLAY completed with result %d (%s)",
                      result, strerror(-result));
+                if (mAborted) {
+                  LOGV("we're aborted, dropping stale packet.");
+                  break;
+                }
 
                 if (result == OK) {
                     sp<RefBase> obj;
                     CHECK(msg->findObject("response", &obj));
                     sp<ARTSPResponse> response =
                         static_cast<ARTSPResponse *>(obj.get());
 
                     if (response->mStatusCode != 200) {
@@ -811,16 +825,17 @@ struct RtspConnectionHandler : public AH
                 mPausePending = false;
                 mFirstAccessUnit = true;
                 mNTPAnchorUs = -1;
                 mMediaAnchorUs = -1;
                 mNumAccessUnitsReceived = 0;
                 mReceivedFirstRTCPPacket = false;
                 mReceivedFirstRTPPacket = false;
                 mSeekable = false;
+                mAborted = true;
 
                 sp<AMessage> reply = new AMessage('tear', id());
 
                 int32_t reconnect;
                 if (msg->findInt32("reconnect", &reconnect) && reconnect) {
                     reply->setInt32("reconnect", true);
                 }
 
@@ -950,16 +965,21 @@ struct RtspConnectionHandler : public AH
                     break;
                 }
 
                 if (mPausePending) {
                     LOGV("we're pausing, dropping stale packet.");
                     break;
                 }
 
+                if (mAborted) {
+                  LOGV("we're aborted, dropping stale packet.");
+                  break;
+                }
+
                 if (seqNum < track->mFirstSeqNumInSegment) {
                     LOGV("dropping stale access-unit (%d < %d)",
                          seqNum, track->mFirstSeqNumInSegment);
                     break;
                 }
 
                 if (track->mNewSegment) {
                     track->mNewSegment = false;
@@ -1042,16 +1062,20 @@ struct RtspConnectionHandler : public AH
             {
                 CHECK(mSeekPending);
 
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
 
                 LOGI("PLAY completed with result %d (%s)",
                      result, strerror(-result));
+                if (mAborted) {
+                  LOGV("we're aborted, dropping stale packet.");
+                  break;
+                }
 
                 mCheckPending = false;
                 postAccessUnitTimeoutCheck();
 
                 if (result == OK) {
                     sp<RefBase> obj;
                     CHECK(msg->findObject("response", &obj));
                     sp<ARTSPResponse> response =
@@ -1296,16 +1320,17 @@ private:
     AString mOriginalSessionURL;  // This one still has user:pass@
     AString mSessionURL;
     AString mSessionHost;
     AString mBaseURL;
     AString mSessionID;
     bool mSetupTracksSuccessful;
     bool mSeekPending;
     bool mPausePending;
+    bool mAborted;
     bool mFirstAccessUnit;
 
     int64_t mNTPAnchorUs;
     int64_t mMediaAnchorUs;
     int64_t mLastMediaTimeUs;
 
     int64_t mNumAccessUnitsReceived;
     bool mCheckPending;
index 75caa046e715eb63c24749cfaf688bf3efad0325..0243a84c873b939bcf190c0d02f47b869f5da899
GIT binary patch
literal 121856
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
W1fCmc>;t(>RP#Z`k@^2k_<sO@{$)7;
--- a/other-licenses/7zstub/src/7zip/Bundles/SFXSetup-moz/Main.cpp
+++ b/other-licenses/7zstub/src/7zip/Bundles/SFXSetup-moz/Main.cpp
@@ -237,20 +237,26 @@ int APIENTRY WinMain(
   {
     assumeYes = true;
     switches = switches.Mid(2);
     switches.Trim();
   }
 
   /* BEGIN Mozilla customizations */
   bool showProgress = true;
+  bool extractOnly = false;
   if (switches.Left(3).CompareNoCase(UString(L"-ms")) == 0 ||
-	  switches.Left(4).CompareNoCase(UString(L"/INI")) == 0 ||
-	  switches.Left(2).CompareNoCase(UString(L"/S")) == 0)
+      switches.Left(4).CompareNoCase(UString(L"/ini")) == 0 ||
+      switches.Left(2).CompareNoCase(UString(L"/s")) == 0) {
     showProgress = false;
+  } else if (switches.Left(12).CompareNoCase(UString(L"/extractdir=")) == 0) {
+    assumeYes = true;
+    showProgress = false;
+    extractOnly = true;
+  }
   /* END Mozilla customizations */
 
   AString config;
   if (!ReadDataString(fullPath, kStartID, kEndID, config))
   {
     if (!assumeYes)
       MyMessageBox(L"Can't load config info");
     return 1;
@@ -285,26 +291,30 @@ int APIENTRY WinMain(
     
     #ifdef _SHELL_EXECUTE
     executeFile = GetTextConfigValue(pairs, L"ExecuteFile");
     executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches;
     #endif
   }
 
   NFile::NDirectory::CTempDirectory tempDir;
-  if (!tempDir.Create(kTempDirPrefix))
+  /* Mozilla customizations - Added !extractOnly */
+  if (!extractOnly && !tempDir.Create(kTempDirPrefix))
   {
     if (!assumeYes)
       MyMessageBox(L"Can not create temp folder archive");
     return 1;
   }
 
+  /* BEGIN Mozilla customizations */
+  UString tempDirPath = (extractOnly ? switches.Mid(12) : GetUnicodeString(tempDir.GetPath()));
+  /* END Mozilla customizations */
+
   COpenCallbackGUI openCallback;
 
-  UString tempDirPath = GetUnicodeString(tempDir.GetPath());
   bool isCorrupt = false;
   UString errorMessage;
   HRESULT result = ExtractArchive(fullPath, tempDirPath, &openCallback, showProgress, 
       isCorrupt, errorMessage);
 
   if (result != S_OK)
   {
     if (!assumeYes)
@@ -315,16 +325,23 @@ int APIENTRY WinMain(
         result = E_FAIL;
       }
       if (result != E_ABORT && !errorMessage.IsEmpty())
         ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
     }
     return 1;
   }
 
+  /* BEGIN Mozilla customizations */
+  // The code immediately above handles the error case for extraction.
+  if (extractOnly) {
+    return 0;
+  }
+  /* END Mozilla customizations */
+
   CCurrentDirRestorer currentDirRestorer;
 
   if (!SetCurrentDirectory(tempDir.GetPath()))
     return 1;
   
   HANDLE hProcess = 0;
 #ifdef _SHELL_EXECUTE
   if (!executeFile.IsEmpty())
--- a/other-licenses/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.cpp
+++ b/other-licenses/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.cpp
@@ -159,17 +159,17 @@ bool CProgressDialog::OnButtonClicked(in
   switch(buttonID)
   {
     case IDCANCEL:
     {
       bool paused = ProgressSynch.GetPaused();;
       ProgressSynch.SetPaused(true);
       int res = ::MessageBoxW(HWND(*this), 
           L"Are you sure you want to cancel?", 
-          _title, MB_YESNOCANCEL);
+          _title, MB_YESNO);
       ProgressSynch.SetPaused(paused);
-      if (res == IDCANCEL || res == IDNO)
+      if (res == IDNO)
         return true;
       break;
     }
   }
   return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
 }
--- a/services/fxaccounts/FxAccounts.jsm
+++ b/services/fxaccounts/FxAccounts.jsm
@@ -11,17 +11,16 @@ Cu.import("resource://gre/modules/Promis
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Timer.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
-Cu.import("resource://gre/modules/FxAccountsUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsClient",
   "resource://gre/modules/FxAccountsClient.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
   "resource://gre/modules/identity/jwcrypto.jsm");
 
 // All properties exposed by the public FxAccounts API.
@@ -196,31 +195,72 @@ AccountState.prototype = {
                "reason and rejecting it due to a different user being signed in." +
                "Originally rejected with: " + reason);
       return Promise.reject(new Error("A different user signed in"));
     }
     return Promise.reject(error);
   },
 
 }
+
+/**
+ * Copies properties from a given object to another object.
+ *
+ * @param from (object)
+ *        The object we read property descriptors from.
+ * @param to (object)
+ *        The object that we set property descriptors on.
+ * @param options (object) (optional)
+ *        {keys: [...]}
+ *          Lets the caller pass the names of all properties they want to be
+ *          copied. Will copy all properties of the given source object by
+ *          default.
+ *        {bind: object}
+ *          Lets the caller specify the object that will be used to .bind()
+ *          all function properties we find to. Will bind to the given target
+ *          object by default.
+ */
+function copyObjectProperties(from, to, opts = {}) {
+  let keys = (opts && opts.keys) || Object.keys(from);
+  let thisArg = (opts && opts.bind) || to;
+
+  for (let prop of keys) {
+    let desc = Object.getOwnPropertyDescriptor(from, prop);
+
+    if (typeof(desc.value) == "function") {
+      desc.value = desc.value.bind(thisArg);
+    }
+
+    if (desc.get) {
+      desc.get = desc.get.bind(thisArg);
+    }
+
+    if (desc.set) {
+      desc.set = desc.set.bind(thisArg);
+    }
+
+    Object.defineProperty(to, prop, desc);
+  }
+}
+
 /**
  * The public API's constructor.
  */
 this.FxAccounts = function (mockInternal) {
   let internal = new FxAccountsInternal();
   let external = {};
 
   // Copy all public properties to the 'external' object.
   let prototype = FxAccountsInternal.prototype;
   let options = {keys: publicProperties, bind: internal};
-  FxAccountsUtils.copyObjectProperties(prototype, external, options);
+  copyObjectProperties(prototype, external, options);
 
   // Copy all of the mock's properties to the internal object.
   if (mockInternal && !mockInternal.onlySetInternal) {
-    FxAccountsUtils.copyObjectProperties(mockInternal, internal);
+    copyObjectProperties(mockInternal, internal);
   }
 
   if (mockInternal) {
     // Exposes the internal object for testing only.
     external.internal = internal;
   }
 
   return Object.freeze(external);
deleted file mode 100644
--- a/services/fxaccounts/FxAccountsUtils.jsm
+++ /dev/null
@@ -1,49 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-this.EXPORTED_SYMBOLS = ["FxAccountsUtils"];
-
-this.FxAccountsUtils = Object.freeze({
-  /**
-   * Copies properties from a given object to another object.
-   *
-   * @param from (object)
-   *        The object we read property descriptors from.
-   * @param to (object)
-   *        The object that we set property descriptors on.
-   * @param options (object) (optional)
-   *        {keys: [...]}
-   *          Lets the caller pass the names of all properties they want to be
-   *          copied. Will copy all properties of the given source object by
-   *          default.
-   *        {bind: object}
-   *          Lets the caller specify the object that will be used to .bind()
-   *          all function properties we find to. Will bind to the given target
-   *          object by default.
-   */
-  copyObjectProperties: function (from, to, opts = {}) {
-    let keys = (opts && opts.keys) || Object.keys(from);
-    let thisArg = (opts && opts.bind) || to;
-
-    for (let prop of keys) {
-      let desc = Object.getOwnPropertyDescriptor(from, prop);
-
-      if (typeof(desc.value) == "function") {
-        desc.value = desc.value.bind(thisArg);
-      }
-
-      if (desc.get) {
-        desc.get = desc.get.bind(thisArg);
-      }
-
-      if (desc.set) {
-        desc.set = desc.set.bind(thisArg);
-      }
-
-      Object.defineProperty(to, prop, desc);
-    }
-  }
-});
--- a/services/fxaccounts/moz.build
+++ b/services/fxaccounts/moz.build
@@ -7,15 +7,14 @@
 PARALLEL_DIRS += ['interfaces']
 
 TEST_DIRS += ['tests']
 
 EXTRA_JS_MODULES += [
   'Credentials.jsm',
   'FxAccounts.jsm',
   'FxAccountsClient.jsm',
-  'FxAccountsCommon.js',
-  'FxAccountsUtils.jsm'
+  'FxAccountsCommon.js'
 ]
 
 # For now, we will only be using the FxA manager in B2G.
 if CONFIG['MOZ_B2G']:
   EXTRA_JS_MODULES += ['FxAccountsManager.jsm']
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -497,16 +497,23 @@ this.ErrorHandler = function ErrorHandle
 ErrorHandler.prototype = {
   MINIMUM_ALERT_INTERVAL_MSEC: 604800000,   // One week.
 
   /**
    * Flag that turns on error reporting for all errors, incl. network errors.
    */
   dontIgnoreErrors: false,
 
+  /**
+   * Flag that indicates if we have already reported a prolonged failure.
+   * Once set, we don't report it again, meaning this error is only reported
+   * one per run.
+   */
+  didReportProlongedError: false,
+
   init: function init() {
     Svc.Obs.add("weave:engine:sync:applied", this);
     Svc.Obs.add("weave:engine:sync:error", this);
     Svc.Obs.add("weave:service:login:error", this);
     Svc.Obs.add("weave:service:sync:error", this);
     Svc.Obs.add("weave:service:sync:finish", this);
 
     this.initLogs();
@@ -767,17 +774,23 @@ ErrorHandler.prototype = {
     if (this.dontIgnoreErrors) {
       return true;
     }
 
     let lastSync = Svc.Prefs.get("lastSync");
     if (lastSync && ((Date.now() - Date.parse(lastSync)) >
         Svc.Prefs.get("errorhandler.networkFailureReportTimeout") * 1000)) {
       Status.sync = PROLONGED_SYNC_FAILURE;
-      this._log.trace("shouldReportError: true (prolonged sync failure).");
+      if (this.didReportProlongedError) {
+        this._log.trace("shouldReportError: false (prolonged sync failure, but" +
+                        " we've already reported it).");
+        return false;
+      }
+      this._log.trace("shouldReportError: true (first prolonged sync failure).");
+      this.didReportProlongedError = true;
       return true;
     }
 
     // We got a 401 mid-sync. Wait for the next sync before actually handling
     // an error. This assumes that we'll get a 401 again on a login fetch in
     // order to report the error.
     if (!this.service.clusterURL) {
       this._log.trace("shouldReportError: false (no cluster URL; " +
--- a/services/sync/tests/unit/test_errorhandler.js
+++ b/services/sync/tests/unit/test_errorhandler.js
@@ -145,16 +145,17 @@ function generateAndUploadKeys() {
   serverKeys.encrypt(Service.identity.syncKeyBundle);
   return serverKeys.upload(Service.resource(Service.cryptoKeysURL)).success;
 }
 
 function clean() {
   Service.startOver();
   Status.resetSync();
   Status.resetBackoff();
+  errorHandler.didReportProlongedError = false;
 }
 
 add_identity_test(this, function test_401_logout() {
   let server = sync_httpd_setup();
   yield setUp(server);
 
   // By calling sync, we ensure we're logged in.
   Service.sync();
@@ -292,129 +293,161 @@ add_identity_test(this, function test_sh
   // Test dontIgnoreErrors, network, prolonged, sync error reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = true;
   Status.sync = LOGIN_FAILED_NETWORK_ERROR;
   do_check_true(errorHandler.shouldReportError());
 
   // Test non-network, prolonged, login error reported
+  do_check_false(errorHandler.didReportProlongedError);
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.login = LOGIN_FAILED_NO_PASSWORD;
   do_check_true(errorHandler.shouldReportError());
+  do_check_true(errorHandler.didReportProlongedError);
+
+  // Second time with prolonged error and without resetting
+  // didReportProlongedError, sync error should not be reported.
+  Status.resetSync();
+  setLastSync(PROLONGED_ERROR_DURATION);
+  errorHandler.dontIgnoreErrors = false;
+  Status.login = LOGIN_FAILED_NO_PASSWORD;
+  do_check_false(errorHandler.shouldReportError());
+  do_check_true(errorHandler.didReportProlongedError);
 
   // Test non-network, prolonged, sync error reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
+  errorHandler.didReportProlongedError = false;
   Status.sync = CREDENTIALS_CHANGED;
   do_check_true(errorHandler.shouldReportError());
+  do_check_true(errorHandler.didReportProlongedError);
+  errorHandler.didReportProlongedError = false;
 
   // Test network, prolonged, login error reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.login = LOGIN_FAILED_NETWORK_ERROR;
   do_check_true(errorHandler.shouldReportError());
+  do_check_true(errorHandler.didReportProlongedError);
+  errorHandler.didReportProlongedError = false;
 
   // Test network, prolonged, sync error reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.sync = LOGIN_FAILED_NETWORK_ERROR;
   do_check_true(errorHandler.shouldReportError());
+  do_check_true(errorHandler.didReportProlongedError);
+  errorHandler.didReportProlongedError = false;
 
   // Test non-network, non-prolonged, login error reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.login = LOGIN_FAILED_NO_PASSWORD;
   do_check_true(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test non-network, non-prolonged, sync error reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.sync = CREDENTIALS_CHANGED;
   do_check_true(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test network, non-prolonged, login error reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.login = LOGIN_FAILED_NETWORK_ERROR;
   do_check_false(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test network, non-prolonged, sync error reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.sync = LOGIN_FAILED_NETWORK_ERROR;
   do_check_false(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test server maintenance, sync errors are not reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.sync = SERVER_MAINTENANCE;
   do_check_false(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test server maintenance, login errors are not reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.login = SERVER_MAINTENANCE;
   do_check_false(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test prolonged, server maintenance, sync errors are reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.sync = SERVER_MAINTENANCE;
   do_check_true(errorHandler.shouldReportError());
+  do_check_true(errorHandler.didReportProlongedError);
+  errorHandler.didReportProlongedError = false;
 
   // Test prolonged, server maintenance, login errors are reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = false;
   Status.login = SERVER_MAINTENANCE;
   do_check_true(errorHandler.shouldReportError());
+  do_check_true(errorHandler.didReportProlongedError);
+  errorHandler.didReportProlongedError = false;
 
   // Test dontIgnoreErrors, server maintenance, sync errors are reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = true;
   Status.sync = SERVER_MAINTENANCE;
   do_check_true(errorHandler.shouldReportError());
+  // dontIgnoreErrors means we don't set didReportProlongedError
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test dontIgnoreErrors, server maintenance, login errors are reported
   Status.resetSync();
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = true;
   Status.login = SERVER_MAINTENANCE;
   do_check_true(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test dontIgnoreErrors, prolonged, server maintenance,
   // sync errors are reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = true;
   Status.sync = SERVER_MAINTENANCE;
   do_check_true(errorHandler.shouldReportError());
+  do_check_false(errorHandler.didReportProlongedError);
 
   // Test dontIgnoreErrors, prolonged, server maintenance,
   // login errors are reported
   Status.resetSync();
   setLastSync(PROLONGED_ERROR_DURATION);
   errorHandler.dontIgnoreErrors = true;
   Status.login = SERVER_MAINTENANCE;
   do_check_true(errorHandler.shouldReportError());
-
+  do_check_false(errorHandler.didReportProlongedError);
 });
 
 add_identity_test(this, function test_shouldReportError_master_password() {
   _("Test error ignored due to locked master password");
   let server = sync_httpd_setup();
   yield setUp(server);
 
   // Monkey patch Service.verifyLogin to imitate
@@ -620,16 +653,17 @@ add_task(function test_login_prolonged_n
   let server = sync_httpd_setup();
   yield setUp(server);
   Service.identity.basicPassword = null;
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
   yield deferred.promise;
@@ -646,16 +680,17 @@ add_task(function test_sync_prolonged_no
   do_check_true(Service.isLoggedIn);
 
   generateCredentialsChangedFailure();
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:sync:error", onSyncError);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
   yield deferred.promise;
@@ -666,16 +701,17 @@ add_identity_test(this, function test_lo
   yield configureIdentity({username: "johndoe"});
   Service.serverURL  = FAKE_SERVER_URL;
   Service.clusterURL = FAKE_SERVER_URL;
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     deferred.resolve();
   });
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
   yield deferred.promise;
@@ -683,16 +719,17 @@ add_identity_test(this, function test_lo
 
 add_test(function test_sync_prolonged_network_error() {
   // Test prolonged, network errors are reported
   Services.io.offline = true;
 
   Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:sync:error", onSyncError);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     Services.io.offline = false;
     clean();
     run_next_test();
   });
 
   setLastSync(PROLONGED_ERROR_DURATION);
   Service.sync();
@@ -703,16 +740,17 @@ add_task(function test_login_non_network
   let server = sync_httpd_setup();
   yield setUp(server);
   Service.identity.basicPassword = null;
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:login:error", onSyncError);
     do_check_eq(Status.login, LOGIN_FAILED_NO_PASSWORD);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
   yield deferred.promise;
@@ -729,16 +767,17 @@ add_task(function test_sync_non_network_
   do_check_true(Service.isLoggedIn);
 
   generateCredentialsChangedFailure();
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:error", function onSyncError() {
     Svc.Obs.remove("weave:ui:sync:error", onSyncError);
     do_check_eq(Status.sync, CREDENTIALS_CHANGED);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
   yield deferred.promise;
@@ -750,16 +789,17 @@ add_identity_test(this, function test_lo
   Service.clusterURL = FAKE_SERVER_URL;
 
   let deferred = Promise.defer();
   // Test network errors are not reported.
   Svc.Obs.add("weave:ui:clear-error", function onClearError() {
     Svc.Obs.remove("weave:ui:clear-error", onClearError);
 
     do_check_eq(Status.login, LOGIN_FAILED_NETWORK_ERROR);
+    do_check_false(errorHandler.didReportProlongedError);
 
     Services.io.offline = false;
     clean();
     deferred.resolve()
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
@@ -768,16 +808,17 @@ add_identity_test(this, function test_lo
 
 add_test(function test_sync_network_error() {
   // Test network errors are not reported.
   Services.io.offline = true;
 
   Svc.Obs.add("weave:ui:sync:finish", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:sync:finish", onUIUpdate);
     do_check_eq(Status.sync, LOGIN_FAILED_NETWORK_ERROR);
+    do_check_false(errorHandler.didReportProlongedError);
 
     Services.io.offline = false;
     clean();
     run_next_test();
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
@@ -802,16 +843,17 @@ add_identity_test(this, function test_sy
   do_check_eq(Status.service, STATUS_OK);
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:finish", function onSyncFinish() {
     Svc.Obs.remove("weave:ui:sync:finish", onSyncFinish);
 
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
     do_check_eq(Status.sync, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     Svc.Obs.remove("weave:ui:sync:error", onSyncError);
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
@@ -845,16 +887,17 @@ add_identity_test(this, function test_in
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
     Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
 
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
@@ -887,16 +930,17 @@ add_identity_test(this, function test_me
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
     Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
 
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
@@ -932,16 +976,17 @@ add_identity_test(this, function test_cr
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:clear-error", function onLoginFinish() {
     Svc.Obs.remove("weave:ui:clear-error", onLoginFinish);
 
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     clean();
     server.stop(deferred.resolve);
   });
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
   Service.sync();
@@ -959,16 +1004,17 @@ add_task(function test_sync_prolonged_se
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
@@ -993,16 +1039,17 @@ add_identity_test(this, function test_in
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1028,16 +1075,17 @@ add_identity_test(this, function test_me
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1065,16 +1113,17 @@ add_identity_test(this, function test_do
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1100,16 +1149,17 @@ add_identity_test(this, function test_up
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1136,16 +1186,17 @@ add_identity_test(this, function test_wi
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1178,16 +1229,17 @@ add_identity_test(this, function test_wi
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, PROLONGED_SYNC_FAILURE);
     do_check_eq(Svc.Prefs.get("firstSync"), "wipeRemote");
+    do_check_true(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1209,16 +1261,17 @@ add_task(function test_sync_syncAndRepor
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
     do_check_eq(Status.sync, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(NON_PROLONGED_ERROR_DURATION);
@@ -1244,16 +1297,17 @@ add_identity_test(this, function test_in
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1280,16 +1334,17 @@ add_identity_test(this, function test_me
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1318,16 +1373,17 @@ add_identity_test(this, function test_do
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1354,16 +1410,17 @@ add_identity_test(this, function test_up
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1390,16 +1447,17 @@ add_identity_test(this, function test_wi
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1431,16 +1489,17 @@ add_identity_test(this, function test_wi
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, SYNC_FAILED);
     do_check_eq(Status.sync, SERVER_MAINTENANCE);
     do_check_eq(Svc.Prefs.get("firstSync"), "wipeRemote");
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1462,16 +1521,19 @@ add_task(function test_sync_syncAndRepor
   engine.exception = {status: 503,
                       headers: {"retry-after": BACKOFF}};
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:sync:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:sync:error", onUIUpdate);
     do_check_eq(Status.service, SYNC_FAILED_PARTIAL);
     do_check_eq(Status.sync, SERVER_MAINTENANCE);
+    // syncAndReportErrors means dontIgnoreErrors, which means
+    // didReportProlongedError not touched.
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_eq(Status.service, STATUS_OK);
 
   setLastSync(PROLONGED_ERROR_DURATION);
@@ -1497,16 +1559,19 @@ add_identity_test(this, function test_in
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    // syncAndReportErrors means dontIgnoreErrors, which means
+    // didReportProlongedError not touched.
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1533,16 +1598,19 @@ add_identity_test(this, function test_me
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    // syncAndReportErrors means dontIgnoreErrors, which means
+    // didReportProlongedError not touched.
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1571,16 +1639,19 @@ add_identity_test(this, function test_do
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    // syncAndReportErrors means dontIgnoreErrors, which means
+    // didReportProlongedError not touched.
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1607,16 +1678,19 @@ add_identity_test(this, function test_up
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    // syncAndReportErrors means dontIgnoreErrors, which means
+    // didReportProlongedError not touched.
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
@@ -1643,16 +1717,19 @@ add_identity_test(this, function test_wi
 
   let deferred = Promise.defer();
   Svc.Obs.add("weave:ui:login:error", function onUIUpdate() {
     Svc.Obs.remove("weave:ui:login:error", onUIUpdate);
     do_check_true(Status.enforceBackoff);
     do_check_eq(backoffInterval, 42);
     do_check_eq(Status.service, LOGIN_FAILED);
     do_check_eq(Status.login, SERVER_MAINTENANCE);
+    // syncAndReportErrors means dontIgnoreErrors, which means
+    // didReportProlongedError not touched.
+    do_check_false(errorHandler.didReportProlongedError);
 
     clean();
     server.stop(deferred.resolve);
   });
 
   do_check_false(Status.enforceBackoff);
   do_check_eq(Status.service, STATUS_OK);
 
--- a/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm
+++ b/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm
@@ -74,14 +74,23 @@ var Authentication = {
       return fxAccounts.setSignedInUser(credentials);
     }).then(() => {
       cb(null, true);
     }, error => {
       cb(error, false);
     });
 
     try {
-      return cb.wait();
+      cb.wait();
+
+      if (Weave.Status.login !== Weave.LOGIN_SUCCEEDED) {
+        Logger.logInfo("Logging into Weave.");
+        Weave.Service.login();
+        Logger.AssertEqual(Weave.Status.login, Weave.LOGIN_SUCCEEDED,
+                           "Weave logged in");
+      }
+
+      return true;
     } catch (error) {
-      throw new Error("signIn() failed with: " + JSON.stringify(error));
+      throw new Error("signIn() failed with: " + error.message);
     }
   }
 };
--- a/services/sync/tps/extensions/tps/resource/auth/sync.jsm
+++ b/services/sync/tps/extensions/tps/resource/auth/sync.jsm
@@ -63,15 +63,22 @@ var Authentication = {
     Logger.AssertTrue(account["passphrase"], "Passphrase has been found");
 
     Logger.logInfo("Logging in user: " + account["username"]);
 
     Weave.Service.identity.account = account["username"];
     Weave.Service.identity.basicPassword = account["password"];
     Weave.Service.identity.syncKey = account["passphrase"];
 
-    // Fake the login
-    Weave.Service.login();
-    Weave.Svc.Obs.notify("weave:service:setup-complete");
+    if (Weave.Status.login !== Weave.LOGIN_SUCCEEDED) {
+      Logger.logInfo("Logging into Weave.");
+      Weave.Service.login();
+      Logger.AssertEqual(Weave.Status.login, Weave.LOGIN_SUCCEEDED,
+                         "Weave logged in");
+
+      // Bug 997279: Temporary workaround until we can ensure that Sync itself
+      // sends this notification for the first login attempt by TPS
+      Weave.Svc.Obs.notify("weave:service:setup-complete");
+    }
 
     return true;
   }
 };
--- a/services/sync/tps/extensions/tps/resource/tps.jsm
+++ b/services/sync/tps/extensions/tps/resource/tps.jsm
@@ -832,17 +832,16 @@ let TPS = {
     if (Authentication.isLoggedIn && !force) {
       return;
     }
 
     Logger.logInfo("Setting client credentials and login.");
     let account = this.fxaccounts_enabled ? this.config.fx_account
                                           : this.config.sync_account;
     Authentication.signIn(account);
-
     this.waitForSetupComplete();
     Logger.AssertEqual(Weave.Status.service, Weave.STATUS_OK, "Weave status OK");
     this.waitForTracking();
   },
 
   /**
    * Triggers a sync operation
    *
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -74,25 +74,23 @@ StartupCache::CollectReports(nsIHandleRe
          "This memory is likely to be swapped out shortly after start-up.");
 
   REPORT("explicit/startup-cache/data", KIND_HEAP,
          HeapSizeOfIncludingThis(StartupCacheMallocSizeOf),
          "Memory used by the startup cache for things other than the file "
          "mapping.");
 
   return NS_OK;
-};
+}
 
 static const char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN;
 #if defined(XP_WIN) && defined(MOZ_METRO)
 static const char sMetroStartupCacheName[] = "metroStartupCache." SC_WORDSIZE "." SC_ENDIAN;
 #endif
 
-static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
-
 StartupCache*
 StartupCache::GetSingleton()
 {
   if (!gStartupCache) {
     if (XRE_GetProcessType() != GeckoProcessType_Default) {
       return nullptr;
     }
 
--- a/toolkit/mozapps/extensions/test/browser/browser_experiments.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_experiments.js
@@ -2,174 +2,155 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 let gManagerWindow;
 let gCategoryUtilities;
 let gInstalledAddons = [];
 let gContext = this;
 
-function test() {
-  waitForExplicitFinish();
-
-  open_manager(null, (win) => {
-    gManagerWindow = win;
-    gCategoryUtilities = new CategoryUtilities(win);
-
-    // The Experiments Manager will interfere with us by preventing installs
-    // of experiments it doesn't know about. We remove it from the equation
-    // because here we are only concerned with core Addon Manager operation,
-    // not the superset Experiments Manager has imposed.
-    if ("@mozilla.org/browser/experiments-service;1" in Components.classes) {
-      Components.utils.import("resource:///modules/experiments/Experiments.jsm", gContext);
+add_task(function* initializeState() {
+  gManagerWindow = yield open_manager();
+  gCategoryUtilities = new CategoryUtilities(gManagerWindow);
 
-      // There is a race condition between XPCOM service initialization and
-      // this test running. We have to initialize the instance first, then
-      // uninitialize it to prevent this.
-      let instance = gContext.Experiments.instance();
-      instance.uninit().then(run_next_test);
-    } else {
-      run_next_test();
-    }
-  });
-}
+  // The Experiments Manager will interfere with us by preventing installs
+  // of experiments it doesn't know about. We remove it from the equation
+  // because here we are only concerned with core Addon Manager operation,
+  // not the superset Experiments Manager has imposed.
+  if ("@mozilla.org/browser/experiments-service;1" in Components.classes) {
+    Components.utils.import("resource:///modules/experiments/Experiments.jsm", gContext);
 
-function end_test() {
-  for (let addon of gInstalledAddons) {
-    addon.uninstall();
+    // There is a race condition between XPCOM service initialization and
+    // this test running. We have to initialize the instance first, then
+    // uninitialize it to prevent this.
+    let instance = gContext.Experiments.instance();
+    yield instance.uninit();
   }
-
-  close_manager(gManagerWindow, () => {
-    if ("@mozilla.org/browser/experiments-service;1" in Components.classes) {
-      gContext.Experiments.instance().init();
-      finish();
-    } else {
-      finish();
-    }
-  });
-}
+});
 
 // On an empty profile with no experiments, the experiment category
 // should be hidden.
-add_test(function testInitialState() {
+add_task(function* testInitialState() {
   Assert.ok(gCategoryUtilities.get("experiment", false), "Experiment tab is defined.");
 
   Assert.ok(!gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab hidden by default.");
-
-  run_next_test();
 });
 
-add_test(function testExperimentInfoNotVisible() {
-  gCategoryUtilities.openType("extension", () => {
-    let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
-    is_element_hidden(el, "Experiment info not visible on other types.");
-
-    run_next_test();
-  });
+add_task(function* testExperimentInfoNotVisible() {
+  yield gCategoryUtilities.openType("extension");
+  let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
+  is_element_hidden(el, "Experiment info not visible on other types.");
 });
 
 // If we have an active experiment, we should see the experiments tab
 // and that tab should have some messages.
-add_test(function testActiveExperiment() {
-  install_addon("addons/browser_experiment1.xpi", (addon) => {
-    gInstalledAddons.push(addon);
-
-    Assert.ok(addon.userDisabled, "Add-on is disabled upon initial install.");
-    Assert.equal(addon.isActive, false, "Add-on is not active.");
+add_task(function* testActiveExperiment() {
+  let addon = yield install_addon("addons/browser_experiment1.xpi");
+  gInstalledAddons.push(addon);
 
-    Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible.");
+  Assert.ok(addon.userDisabled, "Add-on is disabled upon initial install.");
+  Assert.equal(addon.isActive, false, "Add-on is not active.");
 
-    gCategoryUtilities.openType("experiment", (win) => {
-      let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
-      is_element_visible(el, "Experiment info is visible on experiment tab.");
+  Assert.ok(gCategoryUtilities.isTypeVisible("experiment"), "Experiment tab visible.");
 
-      run_next_test();
-    });
-  });
+  yield gCategoryUtilities.openType("experiment");
+  let el = gManagerWindow.document.getElementsByClassName("experiment-info-container")[0];
+  is_element_visible(el, "Experiment info is visible on experiment tab.");
 });
 
-add_test(function testExperimentLearnMore() {
+add_task(function* testExperimentLearnMore() {
   // Actual URL is irrelevant.
   Services.prefs.setCharPref("toolkit.telemetry.infoURL",
                              "http://mochi.test:8888/server.js");
 
-  gCategoryUtilities.openType("experiment", (win) => {
-    let btn = gManagerWindow.document.getElementById("experiments-learn-more");
+  yield gCategoryUtilities.openType("experiment");
+  let btn = gManagerWindow.document.getElementById("experiments-learn-more");
 
-    if (!gUseInContentUI) {
-      is_element_hidden(btn, "Learn more button hidden if not using in-content UI.");
-      Services.prefs.clearUserPref("toolkit.telemetry.infoURL");
+  if (!gUseInContentUI) {
+    is_element_hidden(btn, "Learn more button hidden if not using in-content UI.");
+    Services.prefs.clearUserPref("toolkit.telemetry.infoURL");
 
-      run_next_test();
-      return;
-    } else {
-      is_element_visible(btn, "Learn more button visible.");
-    }
+    return;
+  }
+
+  is_element_visible(btn, "Learn more button visible.");
 
-    window.addEventListener("DOMContentLoaded", function onLoad(event) {
-      info("Telemetry privacy policy window opened.");
-      window.removeEventListener("DOMContentLoaded", onLoad, false);
+  let deferred = Promise.defer();
+  window.addEventListener("DOMContentLoaded", function onLoad(event) {
+    info("Telemetry privacy policy window opened.");
+    window.removeEventListener("DOMContentLoaded", onLoad, false);
 
-      let browser = gBrowser.selectedTab.linkedBrowser;
-      let expected = Services.prefs.getCharPref("toolkit.telemetry.infoURL");
-      Assert.equal(browser.currentURI.spec, expected, "New tab should have loaded privacy policy.");
-      browser.contentWindow.close();
+    let browser = gBrowser.selectedTab.linkedBrowser;
+    let expected = Services.prefs.getCharPref("toolkit.telemetry.infoURL");
+    Assert.equal(browser.currentURI.spec, expected, "New tab should have loaded privacy policy.");
+    browser.contentWindow.close();
 
-      Services.prefs.clearUserPref("toolkit.telemetry.infoURL");
+    Services.prefs.clearUserPref("toolkit.telemetry.infoURL");
+
+    deferred.resolve();
+  }, false);
 
-      run_next_test();
-    }, false);
+  info("Opening telemetry privacy policy.");
+  EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow);
 
-    info("Opening telemetry privacy policy.");
-    EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow);
-  });
+  yield deferred.promise;
 });
 
-add_test(function testOpenPreferences() {
-  gCategoryUtilities.openType("experiment", (win) => {
-    let btn = gManagerWindow.document.getElementById("experiments-change-telemetry");
-    if (!gUseInContentUI) {
-      is_element_hidden(btn, "Change telemetry button not enabled in out of window UI.");
-      info("Skipping preferences open test because not using in-content UI.");
-      run_next_test();
-      return;
-    }
+add_task(function* testOpenPreferences() {
+  yield gCategoryUtilities.openType("experiment");
+  let btn = gManagerWindow.document.getElementById("experiments-change-telemetry");
+  if (!gUseInContentUI) {
+    is_element_hidden(btn, "Change telemetry button not enabled in out of window UI.");
+    info("Skipping preferences open test because not using in-content UI.");
+    return;
+  }
 
-    is_element_visible(btn, "Change telemetry button visible in in-content UI.");
+  is_element_visible(btn, "Change telemetry button visible in in-content UI.");
 
-    Services.obs.addObserver(function observer(prefWin, topic, data) {
-      Services.obs.removeObserver(observer, "advanced-pane-loaded");
+  let deferred = Promise.defer();
+  Services.obs.addObserver(function observer(prefWin, topic, data) {
+    Services.obs.removeObserver(observer, "advanced-pane-loaded");
 
-      info("Advanced preference pane opened.");
+    info("Advanced preference pane opened.");
 
-      // We want this test to fail if the preferences pane changes.
-      let el = prefWin.document.getElementById("dataChoicesPanel");
-      is_element_visible(el);
+    // We want this test to fail if the preferences pane changes.
+    let el = prefWin.document.getElementById("dataChoicesPanel");
+    is_element_visible(el);
 
-      prefWin.close();
-      info("Closed preferences pane.");
+    prefWin.close();
+    info("Closed preferences pane.");
 
-      run_next_test();
-    }, "advanced-pane-loaded", false);
+    deferred.resolve();
+  }, "advanced-pane-loaded", false);
 
-    info("Loading preferences pane.");
-    EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow);
-  });
+  info("Loading preferences pane.");
+  EventUtils.synthesizeMouseAtCenter(btn, {}, gManagerWindow);
+
+  yield deferred.promise;
 });
 
-add_test(function testButtonPresence() {
-  gCategoryUtilities.openType("experiment", (win) => {
-    let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org");
-    Assert.ok(item, "Got add-on element.");
+add_task(function* testButtonPresence() {
+  yield gCategoryUtilities.openType("experiment");
+  let item = get_addon_element(gManagerWindow, "test-experiment1@experiments.mozilla.org");
+  Assert.ok(item, "Got add-on element.");
 
-    let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
-    // Corresponds to the uninstall permission.
-    is_element_visible(el, "Remove button is visible.");
-    // Corresponds to lack of disable permission.
-    el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
-    is_element_hidden(el, "Disable button not visible.");
-    // Corresponds to lack of enable permission.
-    el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
-    is_element_hidden(el, "Enable button not visible.");
+  let el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "remove-btn");
+  // Corresponds to the uninstall permission.
+  is_element_visible(el, "Remove button is visible.");
+  // Corresponds to lack of disable permission.
+  el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "disable-btn");
+  is_element_hidden(el, "Disable button not visible.");
+  // Corresponds to lack of enable permission.
+  el = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "enable-btn");
+  is_element_hidden(el, "Enable button not visible.");
+});
 
-    run_next_test();
-  });
+add_task(function* testCleanup() {
+  for (let addon of gInstalledAddons) {
+    addon.uninstall();
+  }
+
+  yield close_manager(gManagerWindow);
+
+  if ("@mozilla.org/browser/experiments-service;1" in Components.classes) {
+    yield gContext.Experiments.instance().init();
+  }
 });
--- a/toolkit/mozapps/extensions/test/browser/head.js
+++ b/toolkit/mozapps/extensions/test/browser/head.js
@@ -278,73 +278,86 @@ function wait_for_manager_load(aManagerW
   info("Waiting for initialization");
   aManagerWindow.document.addEventListener("Initialized", function() {
     aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false);
     log_exceptions(aCallback, aManagerWindow);
   }, false);
 }
 
 function open_manager(aView, aCallback, aLoadCallback, aLongerTimeout) {
+  let deferred = Promise.defer();
+
   function setup_manager(aManagerWindow) {
     if (aLoadCallback)
       log_exceptions(aLoadCallback, aManagerWindow);
 
     if (aView)
       aManagerWindow.loadView(aView);
 
     ok(aManagerWindow != null, "Should have an add-ons manager window");
     is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI");
 
     waitForFocus(function() {
       wait_for_manager_load(aManagerWindow, function() {
         wait_for_view_load(aManagerWindow, function() {
           // Some functions like synthesizeMouse don't like to be called during
           // the load event so ensure that has completed
           executeSoon(function() {
-            log_exceptions(aCallback, aManagerWindow);
+            if (aCallback) {
+              log_exceptions(aCallback, aManagerWindow);
+            }
+            deferred.resolve(aManagerWindow);
           });
         }, null, aLongerTimeout);
       });
     }, aManagerWindow);
   }
 
   if (gUseInContentUI) {
     gBrowser.selectedTab = gBrowser.addTab();
     switchToTabHavingURI(MANAGER_URI, true);
-    
+
     // This must be a new load, else the ping/pong would have
     // found the window above.
     Services.obs.addObserver(function (aSubject, aTopic, aData) {
       Services.obs.removeObserver(arguments.callee, aTopic);
       if (aSubject.location.href != MANAGER_URI)
         return;
       setup_manager(aSubject);
     }, "EM-loaded", false);
-    return;
+    return deferred.promise;
   }
 
   openDialog(MANAGER_URI);
   Services.obs.addObserver(function (aSubject, aTopic, aData) {
     Services.obs.removeObserver(arguments.callee, aTopic);
     setup_manager(aSubject);
   }, "EM-loaded", false);
+
+  return deferred.promise;
 }
 
 function close_manager(aManagerWindow, aCallback, aLongerTimeout) {
+  let deferred = Promise.defer();
   requestLongerTimeout(aLongerTimeout ? aLongerTimeout : 2);
 
   ok(aManagerWindow != null, "Should have an add-ons manager window to close");
   is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI");
 
   aManagerWindow.addEventListener("unload", function() {
     this.removeEventListener("unload", arguments.callee, false);
-    log_exceptions(aCallback);
+    if (aCallback) {
+      log_exceptions(aCallback);
+    }
+    deferred.resolve();
   }, false);
 
   aManagerWindow.close();
+
+  return deferred.promise;
 }
 
 function restart_manager(aManagerWindow, aView, aCallback, aLoadCallback) {
   if (!aManagerWindow) {
     open_manager(aView, aCallback, aLoadCallback);
     return;
   }
 
@@ -419,27 +432,35 @@ function is_element_hidden(aElement, aMs
 }
 
 /**
  * Install an add-on and call a callback when complete.
  *
  * The callback will receive the Addon for the installed add-on.
  */
 function install_addon(path, cb, pathPrefix=TESTROOT) {
+  let deferred = Promise.defer();
+
   AddonManager.getInstallForURL(pathPrefix + path, (install) => {
     install.addListener({
       onInstallEnded: () => {
         executeSoon(() => {
-          cb(install.addon);
+          if (cb) {
+            cb(install.addon);
+          }
+
+          deferred.resolve(install.addon);
         });
       },
     });
 
     install.install();
   }, "application/x-xpinstall");
+
+  return deferred.promise;
 }
 
 function CategoryUtilities(aManagerWindow) {
   this.window = aManagerWindow;
 
   var self = this;
   this.window.addEventListener("unload", function() {
     self.window.removeEventListener("unload", arguments.callee, false);
@@ -491,27 +512,36 @@ CategoryUtilities.prototype = {
     return !is_hidden(aCategory);
   },
 
   isTypeVisible: function(aCategoryType) {
     return this.isVisible(this.get(aCategoryType));
   },
 
   open: function(aCategory, aCallback) {
+    let deferred = Promise.defer();
+
     isnot(this.window, null, "Should not open category when manager window is not loaded");
     ok(this.isVisible(aCategory), "Category should be visible if attempting to open it");
 
     EventUtils.synthesizeMouse(aCategory, 2, 2, { }, this.window);
 
-    if (aCallback)
-      wait_for_view_load(this.window, aCallback);
+    wait_for_view_load(this.window, (win) => {
+      if (aCallback) {
+        log_exceptions(aCallback, win);
+      }
+
+      deferred.resolve(win);
+    });
+
+    return deferred.promise;
   },
 
   openType: function(aCategoryType, aCallback) {
-    this.open(this.get(aCategoryType), aCallback);
+    return this.open(this.get(aCategoryType), aCallback);
   }
 }
 
 function CertOverrideListener(host, bits) {
   this.host = host;
   this.bits = bits;
 }
 
--- a/xpcom/glue/nsID.cpp
+++ b/xpcom/glue/nsID.cpp
@@ -1,23 +1,17 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 #include "nsID.h"
 #include "prprf.h"
 #include "nsMemory.h"
 
-static const char gIDFormat[] = 
-  "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
-
-static const char gIDFormat2[] = 
-  "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
-
-
 /**
  * Multiplies the_int_var with 16 (0x10) and adds the value of the
  * hexadecimal digit the_char. If it fails it returns false from
  * the function it's used in.
  */
 
 #define ADD_HEX_CHAR_TO_INT_OR_RETURN_FALSE(the_char, the_int_var) \
     the_int_var = (the_int_var << 4) + the_char; \
@@ -46,18 +40,18 @@ static const char gIDFormat2[] =
 
 /**
  * Parses a hyphen from the char_pointer string. If there is no hyphen there
  * the function returns false from the function it's used in. The
  * char_pointer is advanced one step.
  */
 
  #define PARSE_HYPHEN(char_pointer)   if(*(char_pointer++) != '-') return false
-    
-/* 
+
+/*
  * Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} string into
  * an nsID. It can also handle the old format without the { and }.
  */
 
 bool nsID::Parse(const char *aIDStr)
 {
   /* Optimized for speed */
   if(!aIDStr) {
@@ -76,29 +70,32 @@ bool nsID::Parse(const char *aIDStr)
   int i;
   for(i=0; i<2; i++)
     PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2);
   PARSE_HYPHEN(aIDStr);
   while(i < 8) {
     PARSE_CHARS_TO_NUM(aIDStr, m3[i], 2);
     i++;
   }
-  
+
   return expectFormat1 ? *aIDStr == '}' : true;
 }
 
 #ifndef XPCOM_GLUE_AVOID_NSPR
 
+static const char gIDFormat[] =
+  "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
+
 /*
  * Returns an allocated string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
  * format. The string is allocated with NS_Alloc and should be freed by
  * the caller.
  */
 
-char *nsID::ToString() const 
+char *nsID::ToString() const
 {
   char *res = (char*)NS_Alloc(NSID_LENGTH);
 
   if (res != nullptr) {
     PR_snprintf(res, NSID_LENGTH, gIDFormat,
                 m0, (uint32_t) m1, (uint32_t) m2,
                 (uint32_t) m3[0], (uint32_t) m3[1], (uint32_t) m3[2],
                 (uint32_t) m3[3], (uint32_t) m3[4], (uint32_t) m3[5],
--- a/xpcom/glue/nsVoidArray.cpp
+++ b/xpcom/glue/nsVoidArray.cpp
@@ -12,31 +12,29 @@
 #include "nsISupportsImpl.h" // for nsTraceRefcnt
 #include "nsAlgorithm.h"
 
 /**
  * Grow the array by at least this many elements at a time.
  */
 static const int32_t kMinGrowArrayBy = 8;
 static const int32_t kMaxGrowArrayBy = 1024;
-static const int32_t kAutoClearCompactSizeFactor = 4;
 
 /**
  * This is the threshold (in bytes) of the mImpl struct, past which
  * we'll force the array to grow geometrically
  */
 static const int32_t kLinearThreshold = 24 * sizeof(void *);
 
 /**
  * Compute the number of bytes requires for the mImpl struct that will
  * hold |n| elements.
  */
 #define SIZEOF_IMPL(n_) (sizeof(Impl) + sizeof(void *) * ((n_) - 1))
 
-
 /**
  * Compute the number of elements that an mImpl struct of |n| bytes
  * will hold.
  */
 #define CAPACITYOF_IMPL(n_) ((((n_) - sizeof(Impl)) / sizeof(void *)) + 1)
 
 #if DEBUG_VOIDARRAY
 #define MAXVOID 10