Merge the last PGO-green inbound chnageset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 25 Oct 2012 21:14:50 -0400
changeset 111453 5ecff3e46ed55a485c15ee12809f08e04b0f6114
parent 111360 58c8080a1a7c35e71fa839959bfe12baadb9baa0 (current diff)
parent 111452 04602cf8bff7e0a0c930fd299a933d5eb110ace8 (diff)
child 111476 3137b9aec214b7ea3c9579848a0bcfec65616656
push id23747
push userryanvm@gmail.com
push dateFri, 26 Oct 2012 01:15:16 +0000
treeherdermozilla-central@5ecff3e46ed5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone19.0a1
first release with
nightly linux32
5ecff3e46ed5 / 19.0a1 / 20121026030606 / files
nightly linux64
5ecff3e46ed5 / 19.0a1 / 20121026030606 / files
nightly mac
5ecff3e46ed5 / 19.0a1 / 20121026030606 / files
nightly win32
5ecff3e46ed5 / 19.0a1 / 20121026030606 / files
nightly win64
5ecff3e46ed5 / 19.0a1 / 20121026030606 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge the last PGO-green inbound chnageset to m-c.
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -268,17 +268,17 @@ pref("widget.ime.android.fullscreen_thre
 
 // optimize images' memory usage
 pref("image.mem.decodeondraw", true);
 pref("content.image.allow_locking", false);
 pref("image.mem.min_discard_timeout_ms", 10000);
 pref("image.mem.max_decoded_image_kb", 5120); /* 5MB */
 
 // enable touch events interfaces
-pref("dom.w3c_touch_events.enabled", true);
+pref("dom.w3c_touch_events.enabled", 1);
 pref("dom.w3c_touch_events.safetyX", 0); // escape borders in units of 1/240"
 pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240"
 
 #ifdef MOZ_SAFE_BROWSING
 // Safe browsing does nothing unless this pref is set
 pref("browser.safebrowsing.enabled", true);
 
 // Prevent loading of pages identified as malware
@@ -503,17 +503,17 @@ pref("dom.disable_window_showModalDialog
 
 // Enable new experimental html forms
 pref("dom.experimental_forms", true);
 
 // Turns on gralloc-based direct texturing for Gonk
 pref("gfx.gralloc.enabled", false);
 
 // XXXX REMOVE FOR PRODUCTION. Turns on GC and CC logging
-pref("javascript.options.mem.log", true);
+pref("javascript.options.mem.log", false);
 
 // Increase mark slice time from 10ms to 30ms
 pref("javascript.options.mem.gc_incremental_slice_ms", 30);
 
 pref("javascript.options.mem.gc_high_frequency_heap_growth_max", 120);
 pref("javascript.options.mem.gc_high_frequency_heap_growth_min", 101);
 pref("javascript.options.mem.gc_high_frequency_high_limit_mb", 40);
 pref("javascript.options.mem.gc_high_frequency_low_limit_mb", 10);
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -1,16 +1,24 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* 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;"
 
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cr = Components.results;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://gre/modules/Services.jsm');
+
 // Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget
 // is resolved this helper could be removed.
 var SettingsListener = {
   _callbacks: {},
 
   init: function sl_init() {
     if ('mozSettings' in navigator && navigator.mozSettings) {
       navigator.mozSettings.onsettingchange = this.onchange.bind(this);
@@ -54,17 +62,32 @@ SettingsListener.observe('audio.volume.m
     return;
 
   audioManager.masterVolume = Math.max(0.0, Math.min(value, 1.0));
 });
 
 
 // =================== Languages ====================
 SettingsListener.observe('language.current', 'en-US', function(value) {
-  Services.prefs.setCharPref('intl.accept_languages', value);
+  Services.prefs.setCharPref('general.useragent.locale', value);
+
+  let prefName = 'intl.accept_languages';
+  if (Services.prefs.prefHasUserValue(prefName)) {
+    Services.prefs.clearUserPref(prefName);
+  }
+
+  let intl = '';
+  try {
+    intl = Services.prefs.getComplexValue(prefName,
+                                          Ci.nsIPrefLocalizedString).data;
+  } catch(e) {}
+
+  if (!((new RegExp('^' + value + '[^a-z-_] *[,;]?', 'i')).test(intl))) {
+    Services.prefs.setCharPref(prefName, value + ', ' + intl);
+  }
 });
 
 
 // =================== RIL ====================
 (function RILSettingsToPrefs() {
   let strPrefs = ['ril.data.mmsc', 'ril.data.mmsproxy'];
   strPrefs.forEach(function(key) {
     SettingsListener.observe(key, "", function(value) {
@@ -91,18 +114,26 @@ Components.utils.import('resource://gre/
   let lock = gSettingsService.createLock();
   //MOZ_B2G_VERSION is set in b2g/confvars.sh, and is outputed as a #define value
   //from configure.in, defaults to 1.0.0 if this value is not exist
 #filter attemptSubstitution
   let os_version = '@MOZ_B2G_VERSION@';
 #unfilter attemptSubstitution
   lock.set('deviceinfo.os', os_version, null, null);
 
+  let appInfo = Cc["@mozilla.org/xre/app-info;1"]
+                  .getService(Ci.nsIXULAppInfo);
+  lock.set('deviceinfo.platform_version', appInfo.platformVersion, null, null);
+  lock.set('deviceinfo.platform_build_id', appInfo.platformBuildID, null, null);
+
+  let update_channel = Services.prefs.getCharPref('app.update.channel');
+  lock.set('deviceinfo.update_channel', update_channel, null, null);
+
   //Get the hardware info from android properties
-  var hardware_version = null;
+  let hardware_version = null;
   try {
     let cutils = ctypes.open('libcutils.so');
     let cbuf = ctypes.char.array(128)();
     let c_property_get = cutils.declare('property_get', ctypes.default_abi,
                                         ctypes.int,       // return value: length
                                         ctypes.char.ptr,  // key
                                         ctypes.char.ptr,  // value
                                         ctypes.char.ptr); // default
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1,21 +1,14 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* 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/. */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cr = Components.results;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
 Cu.import('resource://gre/modules/ContactService.jsm');
 Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
 #ifdef MOZ_B2G_FM
 Cu.import('resource://gre/modules/DOMFMRadioParent.jsm');
 #endif
 Cu.import('resource://gre/modules/AlarmService.jsm');
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
@@ -501,23 +494,20 @@ Services.obs.addObserver(function onWeba
   shell.sendChromeEvent({ type: 'webapps-registry-start' });
 }, 'webapps-registry-start', false);
 
 Services.obs.addObserver(function onWebappsReady(subject, topic, data) {
   shell.sendChromeEvent({ type: 'webapps-registry-ready' });
 }, 'webapps-registry-ready', false);
 
 Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) {
-  if (data == 'up') {
-    shell.sendChromeEvent({ type: 'volume-up-button-press' });
-    shell.sendChromeEvent({ type: 'volume-up-button-release' });
-  } else if (data == 'down') {
-    shell.sendChromeEvent({ type: 'volume-down-button-press' });
-    shell.sendChromeEvent({ type: 'volume-down-button-release' });
-  }
+  shell.sendChromeEvent({
+    type: "volumeset",
+    value: data
+  });
 }, 'bluetooth-volume-change', false);
 
 (function Repl() {
   if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) {
     return;
   }
   const prompt = 'JS> ';
   let output;
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -139,17 +139,17 @@ function setupSearchEngine()
   // Add search engine logo.
   if (searchEngineInfo.image) {
     let logoElt = document.getElementById("searchEngineLogo");
     logoElt.src = searchEngineInfo.image;
 #ifdef XP_MACOSX
     if (searchEngineInfo.imageHD && window.matchMedia("(min-resolution: 2dppx)"))
       logoElt.src = searchEngineInfo.imageHD;
 #endif
-    logoElt.alt = searchEngineInfo.name;
+    logoElt.alt = searchEngineName;
   }
 
   // The "autofocus" attribute doesn't focus the form element
   // immediately when the element is first drawn, so the
   // attribute is also used for styling when the page first loads.
   let searchText = document.getElementById("searchText");
   searchText.addEventListener("blur", function searchText_onBlur() {
     searchText.removeEventListener("blur", searchText_onBlur);
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -93,35 +93,40 @@ let SocialUI = {
     let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
     let label = gNavigatorBundle.getFormattedString("social.toggle.label",
                                                     [Social.provider.name,
                                                      brandShortName]);
     let accesskey = gNavigatorBundle.getString("social.toggle.accesskey");
     toggleCommand.setAttribute("label", label);
     toggleCommand.setAttribute("accesskey", accesskey);
 
+    let kbMenuitem = document.getElementById("menu_socialAmbientMenu");
+    kbMenuitem.hidden = !Social.enabled;
+    kbMenuitem.setAttribute("label", label);
+    kbMenuitem.setAttribute("accesskey", accesskey);
+
     SocialToolbar.init();
     SocialShareButton.init();
     SocialSidebar.init();
     SocialMenu.populate();
   },
 
   updateToggleCommand: function SocialUI_updateToggleCommand() {
     let toggleCommand = this.toggleCommand;
     // We only need to update the command itself - all our menu items use it.
     toggleCommand.setAttribute("checked", Services.prefs.getBoolPref("social.enabled"));
     toggleCommand.setAttribute("hidden", Social.active ? "false" : "true");
   },
 
   // This handles "ActivateSocialFeature" events fired against content documents
   // in this window.
   _activationEventHandler: function SocialUI_activationHandler(e) {
-    // Nothing to do if Social is already active, or we don't have a provider
+    // Nothing to do if Social is already enabled, or we don't have a provider
     // to enable yet.
-    if (Social.active || !Social.provider)
+    if (Social.enabled || !Social.provider)
       return;
 
     let targetDoc = e.target;
 
     // Event must be fired against the document
     if (!(targetDoc instanceof HTMLDocument))
       return;
 
@@ -613,35 +618,36 @@ let SocialShareButton = {
 
 var SocialMenu = {
   populate: function SocialMenu_populate() {
     // This menu is only accessible through keyboard navigation.
     let submenu = document.getElementById("menu_socialAmbientMenuPopup");
     let ambientMenuItems = submenu.getElementsByClassName("ambient-menuitem");
     for (let ambientMenuItem of ambientMenuItems)
       submenu.removeChild(ambientMenuItem);
+
+    let separator = document.getElementById("socialAmbientMenuSeparator");
+    separator.hidden = true;
     let provider = Social.provider;
     if (Social.active && provider) {
       let iconNames = Object.keys(provider.ambientNotificationIcons);
-      let separator = document.getElementById("socialAmbientMenuSeparator");
       for (let name of iconNames) {
         let icon = provider.ambientNotificationIcons[name];
         if (!icon.label || !icon.menuURL)
           continue;
+        separator.hidden = false;
         let menuitem = document.createElement("menuitem");
         menuitem.setAttribute("label", icon.label);
         menuitem.classList.add("ambient-menuitem");
         menuitem.addEventListener("command", function() {
           openUILinkIn(icon.menuURL, "tab");
         }, false);
         submenu.insertBefore(menuitem, separator);
       }
-      separator.hidden = !iconNames.length;
     }
-    document.getElementById("menu_socialAmbientMenu").hidden = !Social.enabled;
   }
 };
 
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialToolbar_init() {
     this.button.setAttribute("image", Social.provider.iconURL);
     this.updateButton();
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2049,17 +2049,17 @@
         <![CDATA[
           Array.forEach(this.tabs, function(tab) {
             if (aTabs.indexOf(tab) == -1)
               this.hideTab(tab);
             else
               this.showTab(tab);
           }, this);
 
-          this.tabContainer.mTabstrip.ensureElementIsVisible(this.selectedTab, false);
+          this.tabContainer._handleTabSelect(false);
         ]]>
         </body>
       </method>
 
       <method name="showTab">
         <parameter name="aTab"/>
         <body>
         <![CDATA[
@@ -2198,17 +2198,17 @@
           // bounds: .item() returns null (so it acts like appendChild), but [] throws
           this.tabContainer.insertBefore(aTab, this.tabs.item(aIndex));
 
           for (let i = 0; i < this.tabs.length; i++) {
             this.tabs[i]._tPos = i;
             this.tabs[i]._selected = false;
           }
           this.mCurrentTab._selected = true;
-          this.tabContainer.mTabstrip.ensureElementIsVisible(this.mCurrentTab, false);
+          this.tabContainer._handleTabSelect(false);
 
           if (aTab.pinned)
             this.tabContainer._positionPinnedTabs();
 
           var evt = document.createEvent("UIEvents");
           evt.initUIEvent("TabMove", true, false, window, oldPosition);
           aTab.dispatchEvent(evt);
         ]]>
@@ -2803,16 +2803,17 @@
       ]]></handler>
       <handler event="overflow"><![CDATA[
         if (event.detail == 0)
           return; // Ignore vertical events
 
         var tabs = document.getBindingParent(this);
         tabs.setAttribute("overflow", "true");
         tabs._positionPinnedTabs();
+        tabs._handleTabSelect(false);
       ]]></handler>
     </handlers>
   </binding>
 
   <binding id="tabbrowser-tabs"
            extends="chrome://global/content/bindings/tabbox.xml#tabs">
     <resources>
       <stylesheet src="chrome://browser/content/tabbrowser.css"/>
@@ -2999,18 +3000,20 @@
           }
           var tabstripClosebutton = document.getElementById("tabs-closebutton");
           if (tabstripClosebutton && tabstripClosebutton.parentNode == this._container)
             tabstripClosebutton.collapsed = this.mCloseButtons != 3;
         ]]></body>
       </method>
 
       <method name="_handleTabSelect">
+        <parameter name="aSmoothScroll"/>
         <body><![CDATA[
-          this.mTabstrip.ensureElementIsVisible(this.selectedItem);
+          if (this.getAttribute("overflow") == "true")
+            this.mTabstrip.ensureElementIsVisible(this.selectedItem, aSmoothScroll);
         ]]></body>
       </method>
 
       <method name="_fillTrailingGap">
         <body><![CDATA[
           try {
             // if we're at the right side (and not the logical end,
             // which is why this works for both LTR and RTL)
@@ -3118,16 +3121,17 @@
 
           if (this.hasAttribute("using-closing-tabs-spacer")) {
             this.removeAttribute("using-closing-tabs-spacer");
             this._closingTabsSpacer.style.width = 0;
           }
         ]]></body>
       </method>
 
+      <field name="_lastNumPinned">0</field>
       <method name="_positionPinnedTabs">
         <body><![CDATA[
           var numPinned = this.tabbrowser._numPinnedTabs;
           var doPosition = this.getAttribute("overflow") == "true" &&
                            numPinned > 0;
 
           if (doPosition) {
             this.setAttribute("positionpinnedtabs", "true");
@@ -3150,17 +3154,20 @@
             for (let i = 0; i < numPinned; i++) {
               let tab = this.childNodes[i];
               tab.style.MozMarginStart = "";
             }
 
             this.style.MozPaddingStart = "";
           }
 
-          this.mTabstrip.ensureElementIsVisible(this.selectedItem, false);
+          if (this._lastNumPinned != numPinned) {
+            this._lastNumPinned = numPinned;
+            this._handleTabSelect(false);
+          }
         ]]></body>
       </method>
 
       <method name="_animateTabMove">
         <parameter name="event"/>
         <body><![CDATA[
           let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
 
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -62,16 +62,38 @@ let gTests = [
     ok(snippetsElt, "Found snippets element");
     is(snippetsElt.getElementsByTagName("span").length, 1,
        "A default snippet is visible.");
     let storage = getStorage();
     storage.removeItem("snippets");
     executeSoon(runNextTest);
   }
 },
+{
+  desc: "Check that search engine logo has alt text",
+  setup: function ()
+  {
+  },
+  run: function ()
+  {
+    let doc = gBrowser.selectedTab.linkedBrowser.contentDocument;
+
+    let searchEngineLogoElt = doc.getElementById("searchEngineLogo");
+    ok(searchEngineLogoElt, "Found search engine logo");
+
+    let altText = searchEngineLogoElt.alt;
+    ok(typeof altText == "string" && altText.length > 0,
+       "Search engine logo's alt text is a nonempty string");
+
+    isnot(altText, "undefined",
+          "Search engine logo's alt text shouldn't be the string 'undefined'");
+
+    executeSoon(runNextTest);
+  }
+},
 ];
 
 function test()
 {
   waitForExplicitFinish();
 
   // Ensure that by default we don't try to check for remote snippets since that
   // could be tricky due to network bustages or slowness.
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -745,16 +745,19 @@ const DownloadsView = {
     let localFile = controller.dataItem.localFile;
     if (!localFile.exists()) {
       return;
     }
 
     let dataTransfer = aEvent.dataTransfer;
     dataTransfer.mozSetDataAt("application/x-moz-file", localFile, 0);
     dataTransfer.effectAllowed = "copyMove";
+    var url = Services.io.newFileURI(localFile).spec;
+    dataTransfer.setData("text/uri-list", url);
+    dataTransfer.setData("text/plain", url);
     dataTransfer.addElement(element);
 
     aEvent.stopPropagation();
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsViewItem
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -517,16 +517,22 @@ const DownloadsIndicatorView = {
   {
     browserDragAndDrop.dragOver(aEvent);
   },
 
   onDragExit: function () { },
 
   onDrop: function DIV_onDrop(aEvent)
   {
+    let dt = aEvent.dataTransfer;
+    // If dragged item is from our source, do not try to
+    // redownload already downloaded file.
+    if (dt.mozGetDataAt("application/x-moz-file", 0))
+      return;
+
     let name = {};
     let url = browserDragAndDrop.drop(aEvent, name);
     if (url) {
       saveURL(url, name.value, null, true, true);
       aEvent.preventDefault();
     }
   },
 
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/downloads.css
@@ -1,29 +1,14 @@
 /* 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/. */
 
 /*** Panel and outer controls ***/
 
-%ifndef WINSTRIPE_AERO
-#downloadsHistory,
-#downloadsHistory:-moz-focusring > .button-box {
-  outline: 1px -moz-dialogtext dotted;
-  border-bottom-left-radius: 6px;
-  border-bottom-right-radius: 6px;
-}
-
-#downloadsPanel:not([hasdownloads]) > #downloadsHistory,
-#downloadsPanel:not([hasdownloads]) > #downloadsHistory:-moz-focusring > .button-box  {
-  border-top-left-radius: 6px;
-  border-top-right-radius: 6px;
-}
-%endif
-
 #downloadsPanel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 #downloadsListBox {
   background-color: transparent;
   padding: 4px;
   color: inherit;
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -402,17 +402,17 @@ user_pref("dom.min_background_timeout_va
 user_pref("test.mousescroll", true);
 user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
 user_pref("network.http.prompt-temp-redirect", false);
 user_pref("media.cache_size", 100);
 user_pref("security.warn_viewing_mixed", false);
 user_pref("app.update.enabled", false);
 user_pref("app.update.staging.enabled", false);
 user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
-user_pref("dom.w3c_touch_events.enabled", true);
+user_pref("dom.w3c_touch_events.enabled", 1);
 user_pref("toolkit.telemetry.prompted", 2);
 // Existing tests assume there is no font size inflation.
 user_pref("font.size.inflation.emPerLine", 0);
 user_pref("font.size.inflation.minTwips", 0);
 
 // Only load extensions from the application and user profile
 // AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION
 user_pref("extensions.enabledScopes", 5);
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -6922,18 +6922,17 @@ nsContentUtils::ReleaseWrapper(void* aSc
                                nsWrapperCache* aCache)
 {
   if (aCache->PreservingWrapper()) {
     // PreserveWrapper puts new DOM bindings in the JS holders hash, but they
     // can also be in the DOM expando hash, so we need to try to remove them
     // from both here.
     JSObject* obj = aCache->GetWrapperPreserveColor();
     if (aCache->IsDOMBinding() && obj) {
-      xpc::CompartmentPrivate *priv = xpc::GetCompartmentPrivate(obj);
-      priv->RemoveDOMExpandoObject(obj);
+      xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj);
     }
     DropJSObjects(aScriptObjectHolder);
 
     aCache->SetPreservingWrapper(false);
   }
 }
 
 // static
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -1291,16 +1291,24 @@ nsObjectLoadingContent::UpdateObjectPara
                                                    newBaseURI);
     if (NS_SUCCEEDED(rv)) {
       NS_TryToSetImmutable(newURI);
     } else {
       stateInvalid = true;
     }
   }
 
+  // For eAllowPluginSkipChannel tags, if we have a non-plugin type, but can get
+  // a plugin type from the extension, prefer that to falling back to a channel.
+  if (GetTypeOfContent(newMime) != eType_Plugin && newURI &&
+      (caps & eAllowPluginSkipChannel) &&
+      IsPluginEnabledByExtension(newURI, newMime)) {
+    LOG(("OBJLC [%p]: Using extension as type hint (%s)", this, newMime.get()));
+  }
+
   ///
   /// Check if the original (pre-channel) content-type or URI changed, and
   /// record mOriginal{ContentType,URI}
   ///
 
   if ((mOriginalContentType != newMime) || !URIEquals(mOriginalURI, newURI)) {
     // These parameters changing requires re-opening the channel, so don't
     // consider the currently-open channel below
@@ -2111,17 +2119,17 @@ nsObjectLoadingContent::GetTypeOfContent
   uint32_t caps = GetCapabilities();
 
   if ((caps & eSupportImages) && IsSupportedImage(aMIMEType)) {
     return eType_Image;
   }
 
   // SVGs load as documents, but are their own capability
   bool isSVG = aMIMEType.LowerCaseEqualsLiteral("image/svg+xml");
-  bool supportType = isSVG ? eSupportSVG : eSupportDocuments;
+  Capabilities supportType = isSVG ? eSupportSVG : eSupportDocuments;
   if ((caps & supportType) && IsSupportedDocument(aMIMEType)) {
     return eType_Document;
   }
 
   if ((caps & eSupportPlugins) && NS_SUCCEEDED(IsPluginEnabledForType(aMIMEType))) {
     return eType_Plugin;
   }
 
--- a/content/events/src/nsDOMTouchEvent.cpp
+++ b/content/events/src/nsDOMTouchEvent.cpp
@@ -375,24 +375,45 @@ nsDOMTouchEvent::GetCtrlKey(bool* aCtrlK
 
 NS_IMETHODIMP
 nsDOMTouchEvent::GetShiftKey(bool* aShiftKey)
 {
   *aShiftKey = static_cast<nsInputEvent*>(mEvent)->IsShift();
   return NS_OK;
 }
 
+#ifdef XP_WIN
+namespace mozilla {
+namespace widget {
+extern int32_t IsTouchDeviceSupportPresent();
+} }
+#endif
+
 bool
 nsDOMTouchEvent::PrefEnabled()
 {
   static bool sDidCheckPref = false;
   static bool sPrefValue = false;
   if (!sDidCheckPref) {
     sDidCheckPref = true;
-    sPrefValue = Preferences::GetBool("dom.w3c_touch_events.enabled", false);
+    int32_t flag = 0;
+    if (NS_SUCCEEDED(Preferences::GetInt("dom.w3c_touch_events.enabled",
+                                         &flag))) {
+      if (flag == 2) {
+#ifdef XP_WIN
+        // On Windows we auto-detect based on device support.
+        sPrefValue = mozilla::widget::IsTouchDeviceSupportPresent();
+#else
+        NS_WARNING("dom.w3c_touch_events.enabled=2 not implemented!");
+        sPrefValue = false;
+#endif
+      } else {
+        sPrefValue = !!flag;
+      }
+    }
     if (sPrefValue) {
       nsContentUtils::InitializeTouchEventTable();
     }
   }
   return sPrefValue;
 }
 
 nsresult
--- a/content/xbl/src/nsBindingManager.h
+++ b/content/xbl/src/nsBindingManager.h
@@ -25,17 +25,17 @@ class nsIURI;
 class nsXBLDocumentInfo;
 class nsIStreamListener;
 class nsStyleSet;
 class nsXBLBinding;
 template<class E> class nsRefPtr;
 typedef nsTArray<nsRefPtr<nsXBLBinding> > nsBindingList;
 class nsIPrincipal;
 
-class nsBindingManager : public nsStubMutationObserver
+class nsBindingManager MOZ_FINAL : public nsStubMutationObserver
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
   NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
 
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -14,31 +14,30 @@
 #include "nsIScriptRuntime.h"
 #include "nsIDOMScriptObjectFactory.h"
 #include "jsapi.h"
 #include "nsIURI.h"
 #include "nsIConsoleService.h"
 #include "nsIScriptError.h"
 #include "nsIChromeRegistry.h"
 #include "nsIPrincipal.h"
+#include "nsJSPrincipals.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "mozilla/Services.h"
 #include "xpcpublic.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla::scache;
 using namespace mozilla;
 
-using mozilla::dom::DestroyProtoOrIfaceCache;
-
 static const char kXBLCachePrefix[] = "xblcache";
 
 static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 // An XBLDocumentInfo object has a special context associated with it which we can use to pre-compile 
 // properties and methods of XBL bindings against.
 class nsXBLDocGlobalObject : public nsIScriptGlobalObject,
                              public nsIScriptObjectPrincipal
@@ -150,37 +149,36 @@ nsXBLDocGlobalObject_finalize(JSFreeOp *
 
   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
 
   if (sgo)
     sgo->OnFinalize(obj);
 
   // The addref was part of JSObject construction
   NS_RELEASE(nativeThis);
-
-  DestroyProtoOrIfaceCache(obj);
 }
 
 static JSBool
 nsXBLDocGlobalObject_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id)
 {
   JSBool did_resolve = JS_FALSE;
   return JS_ResolveStandardClass(cx, obj, id, &did_resolve);
 }
 
 
 JSClass nsXBLDocGlobalObject::gSharedGlobalClass = {
     "nsXBLPrototypeScript compilation scope",
-    XPCONNECT_GLOBAL_FLAGS,
+    JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
+    JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0),
     JS_PropertyStub,  JS_PropertyStub,
     nsXBLDocGlobalObject_getProperty, nsXBLDocGlobalObject_setProperty,
     JS_EnumerateStub, nsXBLDocGlobalObject_resolve,
     JS_ConvertStub, nsXBLDocGlobalObject_finalize,
     nsXBLDocGlobalObject_checkAccess, NULL, NULL, NULL,
-    TraceXPCGlobal
+    NULL
 };
 
 //----------------------------------------------------------------------
 //
 // nsXBLDocGlobalObject
 //
 
 nsXBLDocGlobalObject::nsXBLDocGlobalObject(nsXBLDocumentInfo *aGlobalObjectOwner)
@@ -276,22 +274,20 @@ nsXBLDocGlobalObject::EnsureScriptEnviro
   JSContext *cx = mScriptContext->GetNativeContext();
   JSAutoRequest ar(cx);
 
   // nsJSEnvironment set the error reporter to NS_ScriptErrorReporter so
   // we must apparently override that with our own (although it isn't clear 
   // why - see bug 339647)
   JS_SetErrorReporter(cx, XBL_ProtoErrorReporter);
 
-  nsIPrincipal *principal = GetPrincipal();
-  JSCompartment *compartment;
-
-  rv = xpc::CreateGlobalObject(cx, &gSharedGlobalClass, principal, false,
-                               &mJSObject, &compartment);
-  NS_ENSURE_SUCCESS(rv, NS_OK);
+  mJSObject = JS_NewGlobalObject(cx, &gSharedGlobalClass,
+                                 nsJSPrincipals::get(GetPrincipal()));
+  if (!mJSObject)
+      return NS_OK;
 
   // Set the location information for the new global, so that tools like
   // about:memory may use that information
   nsIURI *ownerURI = mGlobalObjectOwner->DocumentURI();
   xpc::SetLocationForGlobal(mJSObject, ownerURI);
 
   ::JS_SetGlobalObject(cx, mJSObject);
 
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -6,16 +6,17 @@
 
 #include "nsXULPrototypeDocument.h"
 #include "nsXULDocument.h"
 
 #include "nsAString.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsIPrincipal.h"
+#include "nsJSPrincipals.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptRuntime.h"
 #include "nsIServiceManager.h"
 #include "nsIArray.h"
 #include "nsIURI.h"
 #include "jsapi.h"
@@ -89,37 +90,36 @@ nsXULPDGlobalObject_finalize(JSFreeOp *f
     nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeThis));
 
     if (sgo) {
         sgo->OnFinalize(obj);
     }
 
     // The addref was part of JSObject construction
     NS_RELEASE(nativeThis);
-
-    DestroyProtoOrIfaceCache(obj);
 }
 
 
 JSBool
 nsXULPDGlobalObject_resolve(JSContext *cx, JSHandleObject obj, JSHandleId id)
 {
     JSBool did_resolve = JS_FALSE;
 
     return JS_ResolveStandardClass(cx, obj, id, &did_resolve);
 }
 
 
 JSClass nsXULPDGlobalObject::gSharedGlobalClass = {
     "nsXULPrototypeScript compilation scope",
-    XPCONNECT_GLOBAL_FLAGS,
+    JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS |
+    JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0),
     JS_PropertyStub,  JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, nsXULPDGlobalObject_resolve,  JS_ConvertStub,
     nsXULPDGlobalObject_finalize, NULL, NULL, NULL, NULL,
-    TraceXPCGlobal
+    NULL
 };
 
 
 
 //----------------------------------------------------------------------
 //
 // ctors, dtors, n' stuff
 //
@@ -747,23 +747,20 @@ nsXULPDGlobalObject::EnsureScriptEnviron
 
   // We have to setup a special global object.  We do this then
   // attach it as the global for this context.  Then, we
   // will re-fetch the global and set it up in our language globals array.
   {
     JSContext *cx = ctxNew->GetNativeContext();
     JSAutoRequest ar(cx);
 
-    nsIPrincipal *principal = GetPrincipal();
-    JSObject *newGlob;
-    JSCompartment *compartment;
-
-    rv = xpc::CreateGlobalObject(cx, &gSharedGlobalClass, principal, false,
-                                 &newGlob, &compartment);
-    NS_ENSURE_SUCCESS(rv, NS_OK);
+    JSObject *newGlob = JS_NewGlobalObject(cx, &gSharedGlobalClass,
+                                           nsJSPrincipals::get(GetPrincipal()));
+    if (!newGlob)
+        return NS_OK;
 
     ::JS_SetGlobalObject(cx, newGlob);
 
     // Add an owning reference from JS back to us. This'll be
     // released when the JSObject is finalized.
     ::JS_SetPrivate(newGlob, this);
     NS_ADDREF(this);
   }
--- a/dom/activities/src/ActivityProxy.js
+++ b/dom/activities/src/ActivityProxy.js
@@ -49,17 +49,20 @@ ActivityProxy.prototype = {
     // later notify when the activity handler called postResult or postError
     let principal = aWindow.document.nodePrincipal;
     let appId = principal.appId;
     let manifestURL = (appId != Ci.nsIScriptSecurityManager.NO_APP_ID &&
                        appId != Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID)
                         ? DOMApplicationRegistry.getManifestURLByLocalId(appId)
                         : null;
     cpmm.sendAsyncMessage("Activity:Start", { id: this.id,
-                                              options: aOptions,
+                                              options: {
+                                                name: aOptions.name,
+                                                data: aOptions.data
+                                              },
                                               manifestURL: manifestURL,
                                               pageURL: aWindow.document.location.href });
 
     cpmm.addMessageListener("Activity:FireSuccess", this);
     cpmm.addMessageListener("Activity:FireError", this);
   },
 
   receiveMessage: function actProxy_receiveMessage(aMessage) {
--- a/dom/base/ObjectWrapper.jsm
+++ b/dom/base/ObjectWrapper.jsm
@@ -1,42 +1,76 @@
 /* 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"
 
-const Cu = Components.utils; 
+const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 const EXPORTED_SYMBOLS = ["ObjectWrapper"];
 
 // Makes sure that we expose correctly chrome JS objects to content.
 
 let ObjectWrapper = {
+  getObjectKind: function objWrapper_getobjectkind(aObject) {
+    if (!aObject) {
+      return "null";
+    }
+
+    if (Array.isArray(aObject)) {
+      return "array";
+    } else if (aObject.mozSlice && (typeof aObject.mozSlice == "function")) {
+      return "blob";
+    } else if (typeof aObject == "object") {
+      return "object";
+    } else {
+      return "primitive";
+    }
+  },
+
   wrap: function objWrapper_wrap(aObject, aCtxt) {
+    if (!aObject) {
+      return null;
+    }
+
+    // First check wich kind of object we have.
+    let kind = this.getObjectKind(aObject);
+    if (kind == "array") {
+      let res = Cu.createArrayIn(aCtxt);
+      aObject.forEach(function(aObj) {
+        res.push(this.wrap(aObj, aCtxt));
+      }, this);
+      return res;
+    } else if (kind == "blob") {
+      return new aCtxt.Blob([aObject]);
+    } else if (kind == "primitive") {
+      return aObject;
+    }
+
+    //  Fall-through, we now have a dictionnary object.
     let res = Cu.createObjectIn(aCtxt);
     let propList = { };
     for (let prop in aObject) {
       let value;
-      if (Array.isArray(aObject[prop])) {
+      let objProp = aObject[prop];
+      let propKind = this.getObjectKind(objProp);
+      if (propKind == "array") {
         value = Cu.createArrayIn(aCtxt);
-        aObject[prop].forEach(function(aObj) {
-          // Only wrap objects.
-          if (typeof aObj == "object") {
-            value.push(objWrapper_wrap(aObj, aCtxt));
-          } else {
-            value.push(aObj);
-          }
-        });
-      } else if (typeof(aObject[prop]) == "object") {
-        value = objWrapper_wrap(aObject[prop], aCtxt);
+        objProp.forEach(function(aObj) {
+          value.push(this.wrap(aObj, aCtxt));
+        }, this);
+      } else if (propKind == "blob") {
+        value = new aCtxt.Blob([objProp]);
+      } else if (propKind == "object") {
+        value = this.wrap(objProp, aCtxt);
       } else {
-        value = aObject[prop];
+        value = objProp;
       }
       propList[prop] = {
         enumerable: true,
         configurable: true,
         writable: true,
         value: value
       }
     }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2038,21 +2038,21 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       {
         JSAutoCompartment ac(cx, mJSObject);
 
         JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
 
         rv = SetOuterObject(cx, mJSObject);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        xpc::CompartmentPrivate *priv = xpc::GetCompartmentPrivate(mJSObject);
-        if (priv && priv->waiverWrapperMap) {
-          NS_ASSERTION(!JS_IsExceptionPending(cx),
-                       "We might overwrite a pending exception!");
-          priv->waiverWrapperMap->Reparent(cx, newInnerWindow->mJSObject);
+        NS_ASSERTION(!JS_IsExceptionPending(cx),
+                     "We might overwrite a pending exception!");
+        XPCWrappedNativeScope* scope = xpc::GetObjectScope(mJSObject);
+        if (scope->mWaiverWrapperMap) {
+          scope->mWaiverWrapperMap->Reparent(cx, newInnerWindow->mJSObject);
         }
       }
     }
 
     // Enter the new global's compartment.
     JSAutoCompartment ac(cx, mJSObject);
 
     // If we created a new inner window above, we need to do the last little bit
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1419,18 +1419,17 @@ def CheckPref(descriptor, globalName, va
        wrapperCache = "      %s->ClearIsDOMBinding();\n" % (wrapperCache)
     else:
         wrapperCache = ""
 
     failureCode = ("      %s = false;\n" +
                    "      return %s;") % (varName, retval)
     return """
   {
-    XPCWrappedNativeScope* scope =
-      XPCWrappedNativeScope::FindInJSObjectScope(aCx, %s);
+    XPCWrappedNativeScope* scope = xpc::GetObjectScope(%s);
     if (!scope) {
 %s
     }
 
     if (!scope->ExperimentalBindingsEnabled()) {
 %s%s
     }
   }
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -17,20 +17,18 @@ class nsCycleCollectionParticipant;
 // globals and non-globals.
 #define DOM_OBJECT_SLOT 0
 
 // We use slot 1 for holding the expando object. This is not safe for globals
 // until bug 760095 is fixed, so that bug blocks converting Window to new
 // bindings.
 #define DOM_XRAY_EXPANDO_SLOT 1
 
-// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to
-// start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses
-// that one.
-#define DOM_PROTOTYPE_SLOT (JSCLASS_GLOBAL_SLOT_COUNT + 1)
+// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
+#define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT
 
 // We use these flag bits for the new bindings.
 #define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1
 
 // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
 // LSetDOMProperty. Those constants need to be changed accordingly if this value
 // changes.
 #define DOM_PROTO_INSTANCE_CLASS_SLOT 0
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -56,18 +56,18 @@ DOMProxyHandler::EnsureExpandoObject(JSC
   JSObject* expando = GetExpandoObject(obj);
   if (!expando) {
     expando = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
                                          js::GetObjectParent(obj));
     if (!expando) {
       return NULL;
     }
 
-    xpc::CompartmentPrivate* priv = xpc::GetCompartmentPrivate(obj);
-    if (!priv->RegisterDOMExpandoObject(obj)) {
+    XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj);
+    if (!scope->RegisterDOMExpandoObject(obj)) {
       return NULL;
     }
 
     nsWrapperCache* cache;
     CallQueryInterface(UnwrapDOMObject<nsISupports>(obj, eProxyDOMObject), &cache);
     cache->SetPreservingWrapper(true);
 
     js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -214,19 +214,19 @@ CloseScoSocket()
   if (!sco) {
     NS_WARNING("BluetoothScoManager is not available!");
     return;
   }
   sco->Disconnect();
 }
 
 BluetoothHfpManager::BluetoothHfpManager()
-  : mCurrentVgs(-1)
-  , mCurrentCallIndex(0)
+  : mCurrentCallIndex(0)
   , mCurrentCallState(nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED)
+  , mReceiveVgsFlag(false)
 {
   sCINDItems[CINDType::CALL].value = CallState::NO_CALL;
   sCINDItems[CINDType::CALLSETUP].value = CallSetupState::NO_CALLSETUP;
   sCINDItems[CINDType::CALLHELD].value = CallHeldState::NO_CALLHELD;
 }
 
 bool
 BluetoothHfpManager::Init()
@@ -244,16 +244,28 @@ BluetoothHfpManager::Init()
 
   if (!sHfpCommandThread) {
     if (NS_FAILED(NS_NewThread(getter_AddRefs(sHfpCommandThread)))) {
       NS_ERROR("Failed to new thread for sHfpCommandThread");
       return false;
     }
   }
 
+  float volume;
+  nsCOMPtr<nsIAudioManager> am = do_GetService("@mozilla.org/telephony/audiomanager;1");
+  if (!am) {
+    NS_WARNING("Failed to get AudioManager Service!");
+    return false;
+  }
+  am->GetMasterVolume(&volume);
+
+  // AG volume range: [0.0, 1.0]
+  // HS volume range: [0, 15]
+  mCurrentVgs = floor(volume * 15);
+
   return true;
 }
 
 BluetoothHfpManager::~BluetoothHfpManager()
 {
   Cleanup();
 }
 
@@ -349,20 +361,16 @@ BluetoothHfpManager::NotifyDialer(const 
   }
 }
 
 nsresult
 BluetoothHfpManager::HandleVolumeChanged(const nsAString& aData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (GetConnectionStatus() != SocketConnectionStatus::SOCKET_CONNECTED) {
-    return NS_OK;
-  }
-
   // The string that we're interested in will be a JSON string that looks like:
   //  {"key":"volumeup", "value":1.0}
   //  {"key":"volumedown", "value":0.2}
 
   JSContext* cx = nsContentUtils::GetSafeJSContext();
   if (!cx) {
     return NS_OK;
   }
@@ -406,17 +414,26 @@ BluetoothHfpManager::HandleVolumeChanged
 
   if (!value.isNumber()) {
     return NS_ERROR_UNEXPECTED;
   }
 
   // AG volume range: [0.0, 1.0]
   // HS volume range: [0, 15]
   float volume = value.toNumber();
-  mCurrentVgs = ceil(volume * 15);
+  mCurrentVgs = floor(volume * 15);
+
+  if (mReceiveVgsFlag) {
+    mReceiveVgsFlag = false;
+    return NS_OK;
+  }
+
+  if (GetConnectionStatus() != SocketConnectionStatus::SOCKET_CONNECTED) {
+    return NS_OK;
+  }
 
   SendCommand("+VGS: ", mCurrentVgs);
 
   return NS_OK;
 }
 
 nsresult
 BluetoothHfpManager::HandleShutdown()
@@ -453,40 +470,44 @@ BluetoothHfpManager::ReceiveSocketData(U
     // SLC establishment
     SendLine("OK");
   } else if (!strncmp(msg, "AT+CHLD=?", 9)) {
     SendLine("+CHLD: (0,1,2,3)");
     SendLine("OK");
   } else if (!strncmp(msg, "AT+CHLD=", 8)) {
     SendLine("OK");
   } else if (!strncmp(msg, "AT+VGS=", 7)) {
-    // HS volume range: [0, 15]
-    int newVgs = msg[7] - '0';
+    mReceiveVgsFlag = true;
+
+    int length = strlen(msg) - 8;
+    nsAutoCString vgsString(nsDependentCSubstring(msg+7, length));
 
-    if (strlen(msg) > 8) {
-      newVgs *= 10;
-      newVgs += (msg[8] - '0');
+    nsresult rv;
+    int newVgs = vgsString.ToInteger(&rv);
+    if (NS_FAILED(rv)) {
+      NS_WARNING("Failed to extract volume value from bluetooth headset!");
+    }
+
+    if (newVgs == mCurrentVgs) {
+      SendLine("OK");
+      return;
     }
 
 #ifdef DEBUG
     NS_ASSERTION(newVgs >= 0 && newVgs <= 15, "Received invalid VGS value");
 #endif
 
-    // Currently, we send volume up/down commands to represent that
-    // volume has been changed by Bluetooth headset, and that will affect
-    // the main stream volume of our device. In the future, we may want to
-    // be able to set volume by stream.
+    // HS volume range: [0, 15]
+    // sound_manager volume range: [0, 10]
+    nsString data;
+    int volume;
     nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-    if (newVgs > mCurrentVgs) {
-      os->NotifyObservers(nullptr, "bluetooth-volume-change", NS_LITERAL_STRING("up").get());
-    } else if (newVgs < mCurrentVgs) {
-      os->NotifyObservers(nullptr, "bluetooth-volume-change", NS_LITERAL_STRING("down").get());
-    }
-
-    mCurrentVgs = newVgs;
+    volume = ceil((float)newVgs / 15.0 * 10.0);
+    data.AppendInt(volume);
+    os->NotifyObservers(nullptr, "bluetooth-volume-change", data.get());
 
     SendLine("OK");
   } else if (!strncmp(msg, "AT+BLDN", 7)) {
     NotifyDialer(NS_LITERAL_STRING("BLDN"));
     SendLine("OK");
   } else if (!strncmp(msg, "ATA", 3)) {
     NotifyDialer(NS_LITERAL_STRING("ATA"));
     SendLine("OK");
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -48,14 +48,15 @@ private:
   void NotifySettings();
   virtual void OnConnectSuccess() MOZ_OVERRIDE;
   virtual void OnConnectError() MOZ_OVERRIDE;
   virtual void OnDisconnect() MOZ_OVERRIDE;
 
   int mCurrentVgs;
   int mCurrentCallIndex;
   int mCurrentCallState;
+  bool mReceiveVgsFlag;
   nsAutoPtr<BluetoothRilListener> mListener;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -448,39 +448,64 @@ BrowserElementChild.prototype = {
 
     debug("scroll event " + win);
     sendAsyncMsg("scroll", { top: win.scrollY, left: win.scrollX });
   },
 
   _recvGetScreenshot: function(data) {
     debug("Received getScreenshot message: (" + data.json.id + ")");
 
+    let self = this;
+    let maxWidth = data.json.args.width;
+    let maxHeight = data.json.args.height;
+    let domRequestID = data.json.id;
+
+    let takeScreenshotClosure = function() {
+      self._takeScreenshot(maxWidth, maxHeight, domRequestID);
+    };
+
+    let maxDelayMS = 2000;
+    try {
+      maxDelayMS = Services.prefs.getIntPref('dom.browserElement.maxScreenshotDelayMS');
+    }
+    catch(e) {}
+
+    // Try to wait for the event loop to go idle before we take the screenshot,
+    // but once we've waited maxDelayMS milliseconds, go ahead and take it
+    // anyway.
+    Cc['@mozilla.org/message-loop;1'].getService(Ci.nsIMessageLoop).postIdleTask(
+      takeScreenshotClosure, maxDelayMS);
+  },
+
+  /**
+   * Actually take a screenshot and foward the result up to our parent, given
+   * the desired maxWidth and maxHeight, and given the DOMRequest ID associated
+   * with the request from the parent.
+   */
+  _takeScreenshot: function(maxWidth, maxHeight, domRequestID) {
     // You can think of the screenshotting algorithm as carrying out the
     // following steps:
     //
-    // - Let max-width be data.json.args.width, and let max-height be
-    //   data.json.args.height.
-    //
-    // - Let scale-width be the factor by which we'd need to downscale the
-    //   viewport so it would fit within max-width.  (If the viewport's width
-    //   is less than max-width, let scale-width be 1.) Compute scale-height
+    // - Let scaleWidth be the factor by which we'd need to downscale the
+    //   viewport so it would fit within maxWidth.  (If the viewport's width
+    //   is less than maxWidth, let scaleWidth be 1.) Compute scaleHeight
     //   the same way.
     //
-    // - Scale the viewport by max(scale-width, scale-height).  Now either the
-    //   viewport's width is no larger than max-width, the viewport's height is
-    //   no larger than max-height, or both.
+    // - Scale the viewport by max(scaleWidth, scaleHeight).  Now either the
+    //   viewport's width is no larger than maxWidth, the viewport's height is
+    //   no larger than maxHeight, or both.
     //
-    // - Crop the viewport so its width is no larger than max-width and its
-    //   height is no larger than max-height.
+    // - Crop the viewport so its width is no larger than maxWidth and its
+    //   height is no larger than maxHeight.
     //
     // - Return a screenshot of the page's viewport scaled and cropped per
     //   above.
-
-    let maxWidth = data.json.args.width;
-    let maxHeight = data.json.args.height;
+    debug("Taking a screenshot: maxWidth=" + maxWidth +
+          ", maxHeight=" + maxHeight +
+          ", domRequestID=" + domRequestID + ".");
 
     let scaleWidth = Math.min(1, maxWidth / content.innerWidth);
     let scaleHeight = Math.min(1, maxHeight / content.innerHeight);
 
     let scale = Math.max(scaleWidth, scaleHeight);
 
     let canvasWidth = Math.min(maxWidth, Math.round(content.innerWidth * scale));
     let canvasHeight = Math.min(maxHeight, Math.round(content.innerHeight * scale));
@@ -492,20 +517,21 @@ BrowserElementChild.prototype = {
     canvas.height = canvasHeight;
 
     var ctx = canvas.getContext("2d");
     ctx.scale(scale, scale);
     ctx.drawWindow(content, 0, 0, content.innerWidth, content.innerHeight,
                    "rgb(255,255,255)");
 
     sendAsyncMsg('got-screenshot', {
-      id: data.json.id,
-      // Hack around the fact that we can't specify opaque PNG, this requires
-      // us to unpremultiply the alpha channel which is expensive on ARM
-      // processors because they lack a hardware integer division instruction.
+      id: domRequestID,
+      // Use JPEG to hack around the fact that we can't specify opaque PNG.
+      // This requires us to unpremultiply the alpha channel, which is
+      // expensive on ARM processors because they lack a hardware integer
+      // division instruction.
       successRv: canvas.toDataURL("image/jpeg")
     });
   },
 
   _recvFireCtxCallback: function(data) {
     debug("Received fireCtxCallback message: (" + data.json.menuitem + ")");
     // We silently ignore if the embedder uses an incorrect id in the callback
     if (data.json.menuitem in this._ctxHandlers) {
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -30,16 +30,25 @@ function getBoolPref(prefName, def) {
   try {
     return Services.prefs.getBoolPref(prefName);
   }
   catch(err) {
     return def;
   }
 }
 
+function getIntPref(prefName, def) {
+  try {
+    return Services.prefs.getIntPref(prefName);
+  }
+  catch(err) {
+    return def;
+  }
+}
+
 function exposeAll(obj) {
   // Filter for Objects and Arrays.
   if (typeof obj !== "object" || !obj)
     return;
 
   // Recursively expose our children.
   Object.keys(obj).forEach(function(key) {
     exposeAll(obj[key]);
@@ -231,17 +240,19 @@ function BrowserElementParent(frameLoade
         return self._sendDOMRequest(msgName);
       }
     };
   }
 
   // Define methods on the frame element.
   defineMethod('setVisible', this._setVisible);
   defineMethod('sendMouseEvent', this._sendMouseEvent);
-  if (getBoolPref(TOUCH_EVENTS_ENABLED_PREF, false)) {
+
+  // 0 = disabled, 1 = enabled, 2 - auto detect
+  if (getIntPref(TOUCH_EVENTS_ENABLED_PREF, 0) != 0) {
     defineMethod('sendTouchEvent', this._sendTouchEvent);
   }
   defineMethod('goBack', this._goBack);
   defineMethod('goForward', this._goForward);
   defineMethod('reload', this._reload);
   defineMethod('stop', this._stop);
   defineMethod('getScreenshot', this._getScreenshot);
   defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
--- a/dom/browser-element/mochitest/browserElement_SendEvent.js
+++ b/dom/browser-element/mochitest/browserElement_SendEvent.js
@@ -31,17 +31,17 @@ function runTest() {
         ok(true, "Receive a mousemove event.");
         iframe.sendMouseEvent("mouseup", 10, 10, 0, 1, 0);
         break;
       case "#mouseup":
         ok(true, "Receive a mouseup event.");
         break;
       case "#click":
         ok(true, "Receive a click event.");
-        if (SpecialPowers.getBoolPref("dom.w3c_touch_events.enabled")) {
+        if (SpecialPowers.getIntPref("dom.w3c_touch_events.enabled") != 0) {
           iframe.sendTouchEvent("touchstart", [1], [10], [10], [2], [2],
                                 [20], [0.5], 1, 0);
         } else {
           SimpleTest.finish();
         }
         break;
       case "#touchstart":
         ok(true, "Receive a touchstart event.");
--- a/dom/icc/src/IccManager.cpp
+++ b/dom/icc/src/IccManager.cpp
@@ -31,16 +31,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IccManager,
                                                 nsDOMEventTargetHelper)
   tmp->mProvider = nullptr;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IccManager)
   NS_INTERFACE_MAP_ENTRY(nsIDOMMozIccManager)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMMozIccManager)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozIccManager)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(IccManager, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(IccManager, nsDOMEventTargetHelper)
 
 IccManager::IccManager()
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -12,32 +12,50 @@
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsIRemoteBlob.h"
 #include "nsISeekableStream.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/unused.h"
+#include "mozilla/Util.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "nsDOMFile.h"
 #include "nsThreadUtils.h"
 
 #include "ContentChild.h"
 #include "ContentParent.h"
 
+#define PRIVATE_REMOTE_INPUT_STREAM_IID \
+  {0x30c7699f, 0x51d2, 0x48c8, {0xad, 0x56, 0xc0, 0x16, 0xd7, 0x6f, 0x71, 0x27}}
+
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::ipc;
 
 namespace {
 
+class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(PRIVATE_REMOTE_INPUT_STREAM_IID)
+
+  // This will return the underlying stream.
+  virtual nsIInputStream*
+  BlockAndGetInternalStream() = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRemoteInputStream,
+                              PRIVATE_REMOTE_INPUT_STREAM_IID)
+
 class RemoteInputStream : public nsIInputStream,
                           public nsISeekableStream,
-                          public nsIIPCSerializableInputStream
+                          public nsIIPCSerializableInputStream,
+                          public IPrivateRemoteInputStream
 {
   mozilla::Monitor mMonitor;
   nsCOMPtr<nsIDOMBlob> mSourceBlob;
   nsCOMPtr<nsIInputStream> mStream;
   nsCOMPtr<nsISeekableStream> mSeekableStream;
   ActorFlavorEnum mOrigin;
 
 public:
@@ -178,16 +196,24 @@ public:
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
   NS_IMETHOD
   Tell(int64_t* aResult)
   {
+    // We can cheat here and assume that we're going to start at 0 if we don't
+    // yet have our stream. Though, really, this should abort since most input
+    // streams could block here.
+    if (NS_IsMainThread() && !mStream) {
+      *aResult = 0;
+      return NS_OK;
+    }
+
     nsresult rv = BlockAndWaitForStream();
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!mSeekableStream) {
       NS_WARNING("Underlying blob stream is not seekable!");
       return NS_ERROR_NO_INTERFACE;
     }
 
@@ -209,38 +235,68 @@ public:
     }
 
     rv = mSeekableStream->SetEOF();
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
+  virtual nsIInputStream*
+  BlockAndGetInternalStream()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    nsresult rv = BlockAndWaitForStream();
+    NS_ENSURE_SUCCESS(rv, nullptr);
+
+    return mStream;
+  }
+
 private:
   virtual ~RemoteInputStream()
   { }
 
   void
   ReallyBlockAndWaitForStream()
   {
-    mozilla::MonitorAutoLock lock(mMonitor);
-    while (!mStream) {
-      mMonitor.Wait();
+    mozilla::DebugOnly<bool> waited;
+
+    {
+      mozilla::MonitorAutoLock lock(mMonitor);
+
+      waited = !mStream;
+
+      while (!mStream) {
+        mMonitor.Wait();
+      }
     }
+
+    MOZ_ASSERT(mStream);
+
+#ifdef DEBUG
+    if (waited && mSeekableStream) {
+      int64_t position;
+      MOZ_ASSERT(NS_SUCCEEDED(mSeekableStream->Tell(&position)),
+                 "Failed to determine initial stream position!");
+      MOZ_ASSERT(!position, "Stream not starting at 0!");
+    }
+#endif
   }
 
   nsresult
   BlockAndWaitForStream()
   {
     if (NS_IsMainThread()) {
       NS_WARNING("Blocking the main thread is not supported!");
       return NS_ERROR_FAILURE;
     }
 
     ReallyBlockAndWaitForStream();
+
     return NS_OK;
   }
 
   bool
   IsSeekableStream()
   {
     if (NS_IsMainThread()) {
       if (!mStream) {
@@ -259,16 +315,17 @@ private:
 NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream)
 NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream)
 
 NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
+  NS_INTERFACE_MAP_ENTRY(IPrivateRemoteInputStream)
 NS_INTERFACE_MAP_END
 
 template <ActorFlavorEnum ActorFlavor>
 class InputStreamActor : public BlobTraits<ActorFlavor>::StreamType
 {
   nsRefPtr<RemoteInputStream> mRemoteStream;
 
 public:
@@ -356,16 +413,226 @@ ToConcreteBlob(nsIDOMBlob* aBlob)
 }
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace dom {
 namespace ipc {
 
+// Each instance of this class will be dispatched to the network stream thread
+// pool to run the first time where it will open the file input stream. It will
+// then dispatch itself back to the main thread to send the child process its
+// response (assuming that the child has not crashed). The runnable will then
+// dispatch itself to the thread pool again in order to close the file input
+// stream.
+class BlobTraits<Parent>::BaseType::OpenStreamRunnable : public nsRunnable
+{
+  friend class nsRevocableEventPtr<OpenStreamRunnable>;
+
+  typedef BlobTraits<Parent> TraitsType;
+  typedef TraitsType::BaseType BlobActorType;
+  typedef TraitsType::StreamType BlobStreamProtocolType;
+
+  // Only safe to access these pointers if mRevoked is false!
+  BlobActorType* mBlobActor;
+  BlobStreamProtocolType* mStreamActor;
+
+  nsCOMPtr<nsIInputStream> mStream;
+  nsCOMPtr<nsIIPCSerializableInputStream> mSerializable;
+  nsCOMPtr<nsIEventTarget> mTarget;
+
+  bool mRevoked;
+  bool mClosing;
+
+public:
+  OpenStreamRunnable(BlobActorType* aBlobActor,
+                     BlobStreamProtocolType* aStreamActor,
+                     nsIInputStream* aStream,
+                     nsIIPCSerializableInputStream* aSerializable,
+                     nsIEventTarget* aTarget)
+  : mBlobActor(aBlobActor), mStreamActor(aStreamActor), mStream(aStream),
+    mSerializable(aSerializable), mTarget(aTarget), mRevoked(false),
+    mClosing(false)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(aBlobActor);
+    MOZ_ASSERT(aStreamActor);
+    MOZ_ASSERT(aStream);
+    // aSerializable may be null.
+    MOZ_ASSERT(aTarget);
+  }
+
+  NS_IMETHOD
+  Run()
+  {
+    if (NS_IsMainThread()) {
+      return SendResponse();
+    }
+
+    if (!mClosing) {
+      return OpenStream();
+    }
+
+    return CloseStream();
+  }
+
+  nsresult
+  Dispatch()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(mTarget);
+
+    nsresult rv = mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+private:
+  void
+  Revoke()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+#ifdef DEBUG
+    mBlobActor = nullptr;
+    mStreamActor = nullptr;
+#endif
+    mRevoked = true;
+  }
+
+  nsresult
+  OpenStream()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+    MOZ_ASSERT(mStream);
+
+    if (!mSerializable) {
+      nsCOMPtr<IPrivateRemoteInputStream> remoteStream =
+        do_QueryInterface(mStream);
+      MOZ_ASSERT(remoteStream, "Must QI to IPrivateRemoteInputStream here!");
+
+      nsCOMPtr<nsIInputStream> realStream =
+        remoteStream->BlockAndGetInternalStream();
+      NS_ENSURE_TRUE(realStream, NS_ERROR_FAILURE);
+
+      mSerializable = do_QueryInterface(realStream);
+      if (!mSerializable) {
+        MOZ_ASSERT(false, "Must be serializable!");
+        return NS_ERROR_FAILURE;
+      }
+
+      mStream.swap(realStream);
+    }
+
+    // To force the stream open we call Available(). We don't actually care
+    // how much data is available.
+    uint64_t available;
+    if (NS_FAILED(mStream->Available(&available))) {
+      NS_WARNING("Available failed on this stream!");
+    }
+
+    nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  nsresult
+  CloseStream()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+    MOZ_ASSERT(mStream);
+
+    // Going to always release here.
+    nsCOMPtr<nsIInputStream> stream;
+    mStream.swap(stream);
+
+    nsresult rv = stream->Close();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  nsresult
+  SendResponse()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    MOZ_ASSERT(mStream);
+    MOZ_ASSERT(mSerializable);
+    MOZ_ASSERT(mTarget);
+    MOZ_ASSERT(!mClosing);
+
+    nsCOMPtr<nsIIPCSerializableInputStream> serializable;
+    mSerializable.swap(serializable);
+
+    if (mRevoked) {
+      MOZ_ASSERT(!mBlobActor);
+      MOZ_ASSERT(!mStreamActor);
+    }
+    else {
+      MOZ_ASSERT(mBlobActor);
+      MOZ_ASSERT(mStreamActor);
+
+      InputStreamParams params;
+      serializable->Serialize(params);
+
+      MOZ_ASSERT(params.type() != InputStreamParams::T__None);
+
+      unused << mStreamActor->Send__delete__(mStreamActor, params);
+
+      mBlobActor->NoteRunnableCompleted(this);
+
+#ifdef DEBUG
+      mBlobActor = nullptr;
+      mStreamActor = nullptr;
+#endif
+    }
+
+    mClosing = true;
+
+    nsCOMPtr<nsIEventTarget> target;
+    mTarget.swap(target);
+
+    nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+};
+
+BlobTraits<Parent>::BaseType::BaseType()
+{
+}
+
+BlobTraits<Parent>::BaseType::~BaseType()
+{
+}
+
+void
+BlobTraits<Parent>::BaseType::NoteRunnableCompleted(
+                    BlobTraits<Parent>::BaseType::OpenStreamRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) {
+    nsRevocableEventPtr<BaseType::OpenStreamRunnable>& runnable =
+      mOpenStreamRunnables[index];
+
+    if (runnable.get() == aRunnable) {
+      runnable.Forget();
+      mOpenStreamRunnables.RemoveElementAt(index);
+      return;
+    }
+  }
+
+  MOZ_NOT_REACHED("Runnable not in our array!");
+}
+
 template <ActorFlavorEnum ActorFlavor>
 class RemoteBlob : public nsDOMFile,
                    public nsIRemoteBlob
 {
 public:
   typedef RemoteBlob<ActorFlavor> SelfType;
   typedef Blob<ActorFlavor> ActorType;
   typedef InputStreamActor<ActorFlavor> StreamActorType;
@@ -945,32 +1212,51 @@ Blob<Parent>::RecvPBlobStreamConstructor
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(!mRemoteBlob);
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, false);
 
-  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
-    do_QueryInterface(stream);
-  if (!serializable) {
-    MOZ_ASSERT(false, "Must be serializable!");
-    return false;
+  nsCOMPtr<nsIIPCSerializableInputStream> serializableStream;
+
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob);
+  if (remoteBlob) {
+    // Sanity check that the remote blob returned a remote stream.
+    nsCOMPtr<IPrivateRemoteInputStream> remoteStream =
+      do_QueryInterface(stream);
+    if (!remoteStream) {
+      MOZ_ASSERT(false, "Remote blob didn't return a remote stream!");
+      return false;
+    }
+  }
+
+  // If the underlying blob is not a remote blob or it is a remote blob
+  // representing this actor then we can use the internal stream that it
+  // provides. Otherwise we need to be on a background thread before we can
+  // get to the real stream.
+  if (!remoteBlob ||
+      static_cast<ProtocolType*>(remoteBlob->GetPBlob()) == this) {
+    serializableStream = do_QueryInterface(stream);
+    if (!serializableStream) {
+      MOZ_ASSERT(false, "Must be serializable!");
+      return false;
+    }
   }
 
   nsCOMPtr<nsIEventTarget> target =
     do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
   NS_ENSURE_TRUE(target, false);
 
   nsRefPtr<BaseType::OpenStreamRunnable> runnable =
-    new BaseType::OpenStreamRunnable(this, aActor, stream, serializable,
-                                      target);
+    new BaseType::OpenStreamRunnable(this, aActor, stream, serializableStream,
+                                     target);
 
-  rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
+  rv = runnable->Dispatch();
   NS_ENSURE_SUCCESS(rv, false);
 
   nsRevocableEventPtr<BaseType::OpenStreamRunnable>* arrayMember =
     mOpenStreamRunnables.AppendElement();
   *arrayMember = runnable;
   return true;
 }
 
@@ -1023,137 +1309,15 @@ NS_IMPL_ADDREF_INHERITED(RemoteBlob<Acto
 
 template <ActorFlavorEnum ActorFlavor>
 NS_IMPL_RELEASE_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
 
 template <ActorFlavorEnum ActorFlavor>
 NS_IMPL_QUERY_INTERFACE_INHERITED1(RemoteBlob<ActorFlavor>, nsDOMFile,
                                                             nsIRemoteBlob)
 
-void
-BlobTraits<Parent>::BaseType::NoteRunnableCompleted(
-                    BlobTraits<Parent>::BaseType::OpenStreamRunnable* aRunnable)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) {
-    nsRevocableEventPtr<BaseType::OpenStreamRunnable>& runnable =
-      mOpenStreamRunnables[index];
-
-    if (runnable.get() == aRunnable) {
-      runnable.Forget();
-      mOpenStreamRunnables.RemoveElementAt(index);
-      return;
-    }
-  }
-
-  MOZ_NOT_REACHED("Runnable not in our array!");
-}
-
-BlobTraits<Parent>::BaseType::
-OpenStreamRunnable::OpenStreamRunnable(
-                                   BlobTraits<Parent>::BaseType* aOwner,
-                                   BlobTraits<Parent>::StreamType* aActor,
-                                   nsIInputStream* aStream,
-                                   nsIIPCSerializableInputStream* aSerializable,
-                                   nsIEventTarget* aTarget)
-: mOwner(aOwner), mActor(aActor), mStream(aStream),
-  mSerializable(aSerializable), mTarget(aTarget), mRevoked(false),
-  mClosing(false)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  MOZ_ASSERT(aOwner);
-  MOZ_ASSERT(aActor);
-  MOZ_ASSERT(aStream);
-  MOZ_ASSERT(aSerializable);
-  MOZ_ASSERT(aTarget);
-}
-
-NS_IMETHODIMP
-BlobTraits<Parent>::BaseType::OpenStreamRunnable::Run()
-{
-  MOZ_ASSERT(mStream);
-
-  nsresult rv;
-
-  if (NS_IsMainThread()) {
-    MOZ_ASSERT(mTarget);
-    MOZ_ASSERT(!mClosing);
-
-    if (mRevoked) {
-      MOZ_ASSERT(!mOwner);
-      MOZ_ASSERT(!mActor);
-    }
-    else {
-      MOZ_ASSERT(mOwner);
-      MOZ_ASSERT(mActor);
-
-      nsCOMPtr<nsIIPCSerializableInputStream> serializable;
-      mSerializable.swap(serializable);
-
-      InputStreamParams params;
-      serializable->Serialize(params);
-
-      MOZ_ASSERT(params.type() != InputStreamParams::T__None);
-
-      unused << mActor->Send__delete__(mActor, params);
-
-      mOwner->NoteRunnableCompleted(this);
-
-#ifdef DEBUG
-      mOwner = nullptr;
-      mActor = nullptr;
-#endif
-    }
-
-    mClosing = true;
-
-    nsCOMPtr<nsIEventTarget> target;
-    mTarget.swap(target);
-
-    rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    return NS_OK;
-  }
-
-  if (!mClosing) {
-    // To force the stream open we call Available(). We don't actually care how
-    // much data is available.
-    uint64_t available;
-    if (NS_FAILED(mStream->Available(&available))) {
-      NS_WARNING("Available failed on this stream!");
-    }
-
-    rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    return NS_OK;
-  }
-
-  // Going to always release here.
-  nsCOMPtr<nsIInputStream> stream;
-  mStream.swap(stream);
-
-  rv = stream->Close();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-#ifdef DEBUG
-void
-BlobTraits<Parent>::BaseType::OpenStreamRunnable::Revoke()
-{
-  MOZ_ASSERT(NS_IsMainThread());
-  mOwner = nullptr;
-  mActor = nullptr;
-  mRevoked = true;
-}
-#endif
-
 // Explicit instantiation of both classes.
 template class Blob<Parent>;
 template class Blob<Child>;
 
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/Blob.h
+++ b/dom/ipc/Blob.h
@@ -50,63 +50,20 @@ struct BlobTraits<Parent>
   // crash during this process so we need to make sure we cancel the intended
   // response in such a case. We do that by holding an array of
   // nsRevocableEventPtr. If the child crashes then this actor will be destroyed
   // and the nsRevocableEventPtr destructor will cancel any stream events that
   // are currently in flight.
   class BaseType : public ProtocolType
   {
   protected:
-    BaseType()
-    { }
-
-    virtual ~BaseType()
-    { }
-
-    // Each instance of this class will be dispatched to the network stream
-    // thread pool to run the first time where it will open the file input
-    // stream. It will then dispatch itself back to the main thread to send the
-    // child process its response (assuming that the child has not crashed). The
-    // runnable will then dispatch itself to the thread pool again in order to
-    // close the file input stream.
-    class OpenStreamRunnable : public nsRunnable
-    {
-      friend class nsRevocableEventPtr<OpenStreamRunnable>;
-    public:
-      NS_DECL_NSIRUNNABLE
-
-      OpenStreamRunnable(BaseType* aOwner, StreamType* aActor,
-                         nsIInputStream* aStream,
-                         nsIIPCSerializableInputStream* aSerializable,
-                         nsIEventTarget* aTarget);
+    BaseType();
+    virtual ~BaseType();
 
-    private:
-#ifdef DEBUG
-      void
-      Revoke();
-#else
-      void
-      Revoke()
-      {
-        mRevoked = true;
-      }
-#endif
-
-      // Only safe to access these two pointers if mRevoked is false!
-      BaseType* mOwner;
-      StreamType* mActor;
-
-      nsCOMPtr<nsIInputStream> mStream;
-      nsCOMPtr<nsIIPCSerializableInputStream> mSerializable;
-      nsCOMPtr<nsIEventTarget> mTarget;
-
-      bool mRevoked;
-      bool mClosing;
-    };
-
+    class OpenStreamRunnable;
     friend class OpenStreamRunnable;
 
     void
     NoteRunnableCompleted(OpenStreamRunnable* aRunnable);
 
     nsTArray<nsRevocableEventPtr<OpenStreamRunnable> > mOpenStreamRunnables;
   };
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -1223,17 +1223,19 @@ ContentParent::GetOrCreateActorForBlob(n
 
   nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
   if (remoteBlob) {
     BlobParent* actor =
       static_cast<BlobParent*>(
         static_cast<PBlobParent*>(remoteBlob->GetPBlob()));
     NS_ASSERTION(actor, "Null actor?!");
 
-    return actor;
+    if (static_cast<ContentParent*>(actor->Manager()) == this) {
+      return actor;
+    }
   }
 
   // XXX This is only safe so long as all blob implementations in our tree
   //     inherit nsDOMFileBase. If that ever changes then this will need to grow
   //     a real interface or something.
   const nsDOMFileBase* blob = static_cast<nsDOMFileBase*>(aBlob);
 
   BlobConstructorParams params;
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -225,153 +225,150 @@ PeerConnection.prototype = {
       if (!obj.wait) {
         this._executeNext();
       }
     } else {
       this._pending = false;
     }
   },
 
+  /**
+   * Constraints look like this:
+   *
+   * {
+   *   mandatory: {"foo": true, "bar": 10, "baz": "boo"},
+   *   optional: [{"foo": true}, {"bar": 10}]
+   * }
+   *
+   * We check for basic structure but not the validity of the constraints
+   * themselves before passing them along to C++.
+   */
+  _validateConstraints: function(constraints) {
+    function isObject(obj) {
+      return obj && (typeof obj === "object");
+    }
+    function isArray(obj) {
+      return isObject(obj) &&
+        (Object.prototype.toString.call(obj) === "[object Array]");
+    }
+
+    if (!isObject(constraints)) {
+      return false;
+    }
+    if (constraints.mandatory && !isObject(constraints.mandatory)) {
+      return false;
+    }
+    if (constraints.optional && !isArray(constraints.optional)) {
+      return false;
+    }
+
+    return true;
+  },
+
   createOffer: function(onSuccess, onError, constraints) {
     if (this._onCreateOfferSuccess) {
-      if (onError) {
-        onError.onCallback("createOffer already called");
-      }
-      return;
+      throw new Error("createOffer already called");
+    }
+
+    if (!this._validateConstraints(constraints)) {
+      throw new Error("createOffer passed invalid constraints");
     }
 
     this._onCreateOfferSuccess = onSuccess;
     this._onCreateOfferFailure = onError;
 
-    // TODO: Implement constraints/hints.
-    if (!constraints) {
-      constraints = "";
-    }
-
     this._queueOrRun({
       func: this._pc.createOffer,
       args: [constraints],
       wait: true
     });
   },
 
   createAnswer: function(onSuccess, onError, constraints, provisional) {
     if (this._onCreateAnswerSuccess) {
-      if (onError) {
-        try {
-          onError.onCallback("createAnswer already called");
-        } catch(e) {}
-      }
-      return;
+      throw new Error("createAnswer already called");
     }
 
     if (!this.remoteDescription) {
-      if (onError) {
-        try {
-          onError.onCallback("setRemoteDescription not called");
-        } catch(e) {}
-      }
+      throw new Error("setRemoteDescription not called");
     }
 
     if (this.remoteDescription.type != "offer") {
-      if (onError) {
-        try {
-          onError.onCallback("No outstanding offer");
-        } catch(e) {}
-      }
+      throw new Error("No outstanding offer");
+    }
+
+    if (!this._validateConstraints(constraints)) {
+      throw new Error("createAnswer passed invalid constraints");
     }
 
     this._onCreateAnswerSuccess = onSuccess;
     this._onCreateAnswerFailure = onError;
 
-    if (!constraints) {
-      constraints = "";
-    }
     if (!provisional) {
       provisional = false;
     }
 
-    // TODO: Implement provisional answer & constraints.
+    // TODO: Implement provisional answer.
     this._queueOrRun({
       func: this._pc.createAnswer,
-      args: ["", this.remoteDescription.sdp],
+      args: [constraints],
       wait: true
     });
   },
 
   setLocalDescription: function(desc, onSuccess, onError) {
     if (this._onSetLocalDescriptionSuccess) {
-      if (onError) {
-        try {
-          onError.onCallback("setLocalDescription already called");
-        } catch(e) {}
-      }
-      return;
+      throw new Error("setLocalDescription already called");
     }
 
     this._onSetLocalDescriptionSuccess = onSuccess;
     this._onSetLocalDescriptionFailure = onError;
 
     let type;
     switch (desc.type) {
       case "offer":
         type = Ci.IPeerConnection.kActionOffer;
         break;
       case "answer":
         type = Ci.IPeerConnection.kActionAnswer;
         break;
       default:
-        if (onError) {
-          try {
-            onError.onCallback(
-              "Invalid type " + desc.type + " provided to setLocalDescription"
-            );
-          } catch(e) {}
-          return;
-        }
+        throw new Error(
+          "Invalid type " + desc.type + " provided to setLocalDescription"
+        );
         break;
     }
 
     this._queueOrRun({
       func: this._pc.setLocalDescription,
       args: [type, desc.sdp],
       wait: true
     });
   },
 
   setRemoteDescription: function(desc, onSuccess, onError) {
     if (this._onSetRemoteDescriptionSuccess) {
-      if (onError) {
-        try {
-          onError.onCallback("setRemoteDescription already called");
-        } catch(e) {}
-      }
-      return;
+      throw new Error("setRemoteDescription already called");
     }
 
     this._onSetRemoteDescriptionSuccess = onSuccess;
     this._onSetRemoteDescriptionFailure = onError;
 
     let type;
     switch (desc.type) {
       case "offer":
         type = Ci.IPeerConnection.kActionOffer;
         break;
       case "answer":
         type = Ci.IPeerConnection.kActionAnswer;
         break;
       default:
-        if (onError) {
-          try {
-            onError.onCallback(
-              "Invalid type " + desc.type + " provided to setRemoteDescription"
-            );
-          } catch(e) {}
-          return;
-        }
+        throw new Error(
+          "Invalid type " + desc.type + " provided to setRemoteDescription"
+        );
         break;
     }
 
     this.remoteDescription = {
       type: desc.type, sdp: desc.sdp,
       __exposedProps__: { type: "rw", sdp: "rw" }
     };
 
--- a/dom/media/bridge/IPeerConnection.idl
+++ b/dom/media/bridge/IPeerConnection.idl
@@ -1,10 +1,11 @@
 #include "nsIThread.idl"
 #include "nsIDOMWindow.idl"
+#include "nsIPropertyBag2.idl"
 
 interface nsIDOMMediaStream;
 interface nsIDOMDataChannel;
 
 /* Do not confuse with nsIDOMRTCPeerConnection. This interface is purely for
  * communication between the PeerConnection JS DOM binding and the C++
  * implementation in SIPCC.
  *
@@ -46,17 +47,17 @@ interface IPeerConnectionObserver : nsIS
   /* When SDP is parsed and a candidate line is found this method is called.
    * It should hook back into the media transport to notify it of ICE candidates
    * listed in the SDP PeerConnectionImpl does not parse ICE candidates, just
    * pulls them out of the SDP.
    */
   void foundIceCandidate(in string candidate);
 };
 
-[scriptable, uuid(cb3f0048-1009-11e2-b822-87ee49eface7)]
+[scriptable, uuid(f6819246-f5af-40f2-ab82-e166d5da7ba0)]
 interface IPeerConnection : nsISupports
 {
   const unsigned long kHintAudio = 0x00000001;
   const unsigned long kHintVideo = 0x00000002;
 
   const long kActionNone = -1;
   const long kActionOffer = 0;
   const long kActionAnswer = 1;
@@ -68,18 +69,18 @@ interface IPeerConnection : nsISupports
   const long kIceConnected = 3;
   const long kIceFailed = 4;
 
   /* Must be called first. Observer events will be dispatched on the thread provided */
   void initialize(in IPeerConnectionObserver observer, in nsIDOMWindow window,
                   [optional] in nsIThread thread);
 
   /* JSEP calls */
-  void createOffer(in string hints);
-  void createAnswer(in string hints, in string offer);
+  [implicit_jscontext] void createOffer(in jsval constraints);
+  [implicit_jscontext] void createAnswer(in jsval constraints);
   void setLocalDescription(in long action, in string sdp);
   void setRemoteDescription(in long action, in string sdp);
 
   /* Adds the stream created by GetUserMedia */
   void addStream(in nsIDOMMediaStream stream);
   void removeStream(in nsIDOMMediaStream stream);
   void closeStreams();
 
--- a/dom/messages/SystemMessageInternal.js
+++ b/dom/messages/SystemMessageInternal.js
@@ -25,16 +25,17 @@ let kMaxPendingMessages;
 try {
   kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages");
 } catch(e) {
   // getIntPref throws when the pref is not set.
   kMaxPendingMessages = 5;
 }
 
 const kMessages =["SystemMessageManager:GetPendingMessages",
+                  "SystemMessageManager:HasPendingMessages",
                   "SystemMessageManager:Register",
                   "SystemMessageManager:Message:Return:OK",
                   "SystemMessageManager:AskReadyToRegister",
                   "child-process-shutdown"]
 
 function debug(aMsg) {
   //dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n");
 }
@@ -204,30 +205,56 @@ SystemMessageInternal.prototype = {
         let page = null;
         this._pages.some(function(aPage) {
           if (this._isPageMatched(aPage, msg.type, msg.uri, msg.manifest)) {
             page = aPage;
           }
           return page !== null;
         }, this);
         if (!page) {
-          return null;
+          return;
         }
 
         // Return the |msg| of each pending message (drop the |msgID|).
         let pendingMessages = [];
         page.pendingMessages.forEach(function(aMessage) {
           pendingMessages.push(aMessage.msg);
         });
 
         // Clear the pending queue for this page. This is OK since we'll store
         // pending messages in the content process (|SystemMessageManager|).
         page.pendingMessages.length = 0;
 
-        return pendingMessages;
+        // Send the array of pending messages.
+        aMessage.target.sendAsyncMessage("SystemMessageManager:GetPendingMessages:Return",
+                                         { type: msg.type,
+                                           manifest: msg.manifest,
+                                           uri: msg.uri,
+                                           msgQueue: pendingMessages });
+        break;
+      }
+      case "SystemMessageManager:HasPendingMessages":
+      {
+        debug("received SystemMessageManager:HasPendingMessages " + msg.type +
+          " for " + msg.uri + " @ " + msg.manifest);
+
+        // This is a sync call used to return if a page has pending messages.
+        // Find the right page to get its corresponding pending messages.
+        let page = null;
+        this._pages.some(function(aPage) {
+          if (this._isPageMatched(aPage, msg.type, msg.uri, msg.manifest)) {
+            page = aPage;
+          }
+          return page !== null;
+        }, this);
+        if (!page) {
+          return false;
+        }
+
+        return page.pendingMessages.length != 0;
         break;
       }
       case "SystemMessageManager:Message:Return:OK":
       {
         debug("received SystemMessageManager:Message:Return:OK " + msg.type +
           " for " + msg.uri + " @ " + msg.manifest);
 
         // We need to clean up the pending message since the app has already
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -14,25 +14,16 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/ObjectWrapper.jsm");
 
 const kSystemMessageInternalReady = "system-message-internal-ready";
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsISyncMessageSender");
 
-// Limit the number of pending messages for a given type.
-let kMaxPendingMessages;
-try {
-  kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages");
-} catch(e) {
-  // getIntPref throws when the pref is not set.
-  kMaxPendingMessages = 5;
-}
-
 function debug(aMsg) {
   //dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n");
 }
 
 // Implementation of the DOM API for system messages
 
 function SystemMessageManager() {
   // Message handlers for this page.
@@ -97,114 +88,85 @@ SystemMessageManager.prototype = {
       // of this type anymore.
       delete handlers[aType];
       return;
     }
 
     // Last registered handler wins.
     handlers[aType] = aHandler;
 
-    // If we have pending messages, send them asynchronously.
-    if (this._getPendingMessages(aType, true)) {
-      let thread = Services.tm.mainThread;
-      let pending = this._pendings[aType];
-      this._pendings[aType] = [];
-      let self = this;
-      pending.forEach(function dispatch_pending(aPending) {
-        thread.dispatch({
-          run: function run() {
-            self._dispatchMessage(aType, aHandler, aPending);
-          }
-        }, Ci.nsIEventTarget.DISPATCH_NORMAL);
-      });
-    }
+    // Ask for the list of currently pending messages.
+    cpmm.sendAsyncMessage("SystemMessageManager:GetPendingMessages",
+                          { type: aType,
+                            uri: this._uri,
+                            manifest: this._manifest });
   },
 
-  _getPendingMessages: function sysMessMgr_getPendingMessages(aType, aForceUpdate) {
-    debug("hasPendingMessage " + aType);
-    let pendings = this._pendings;
-
+  mozHasPendingMessage: function sysMessMgr_hasPendingMessage(aType) {
     // If we have a handler for this type, we can't have any pending message.
-    // If called from setMessageHandler, we still want to update the pending
-    // queue to deliver existing messages.
-    if (aType in this._handlers && !aForceUpdate) {
+    if (aType in this._handlers) {
       return false;
     }
 
-    // Send a sync message to the parent to check if we have a pending message
-    // for this type.
-    let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPendingMessages",
-                                        { type: aType,
-                                          uri: this._uri,
-                                          manifest: this._manifest })[0];
-    if (!messages) {
-      // No new pending messages, but the queue may not be empty yet.
-      return pendings[aType] && pendings[aType].length != 0;
-    }
-
-    if (!pendings[aType]) {
-      pendings[aType] = [];
-    }
-
-    // Doing that instead of pending.concat() to avoid array copy.
-    messages.forEach(function hpm_addPendings(aMessage) {
-      pendings[aType].push(aMessage);
-      if (pendings[aType].length > kMaxPendingMessages) {
-        pendings[aType].splice(0, 1);
-      }
-    });
-
-    return pendings[aType].length != 0;
-  },
-
-  mozHasPendingMessage: function sysMessMgr_hasPendingMessage(aType) {
-    return this._getPendingMessages(aType, false);
+    return cpmm.sendSyncMessage("SystemMessageManager:HasPendingMessages",
+                                { type: aType,
+                                  uri: this._uri,
+                                  manifest: this._manifest })[0];
   },
 
   uninit: function sysMessMgr_uninit()  {
     this._handlers = null;
     this._pendings = null;
 
     if (this._isParentProcess) {
       Services.obs.removeObserver(this, kSystemMessageInternalReady);
     }
   },
 
   receiveMessage: function sysMessMgr_receiveMessage(aMessage) {
     debug("receiveMessage " + aMessage.name + " - " +
-          aMessage.json.type + " for " + aMessage.json.manifest +
+          aMessage.data.type + " for " + aMessage.data.manifest +
           " (" + this._manifest + ")");
 
-    let msg = aMessage.json;
+    let msg = aMessage.data;
     if (msg.manifest != this._manifest || msg.uri != this._uri) {
       return;
     }
 
-    // Send an acknowledgement to parent to clean up the pending message,
-    // so a re-launched app won't handle it again, which is redundant.
-    cpmm.sendAsyncMessage(
-      "SystemMessageManager:Message:Return:OK",
-      { type: msg.type,
-        manifest: msg.manifest,
-        uri: msg.uri,
-        msgID: msg.msgID });
+    if (aMessage.name == "SystemMessageManager:Message") {
+      // Send an acknowledgement to parent to clean up the pending message,
+      // so a re-launched app won't handle it again, which is redundant.
+      cpmm.sendAsyncMessage(
+        "SystemMessageManager:Message:Return:OK",
+        { type: msg.type,
+          manifest: msg.manifest,
+          uri: msg.uri,
+          msgID: msg.msgID });
+    }
 
     // Bail out if we have no handlers registered for this type.
     if (!(msg.type in this._handlers)) {
       debug("No handler for this type");
       return;
     }
 
-    this._dispatchMessage(msg.type, this._handlers[msg.type], msg.msg);
+    let messages = (aMessage.name == "SystemMessageManager:Message")
+                   ? [msg.msg]
+                   : msg.msgQueue;
+
+    messages.forEach(function(aMsg) {
+      this._dispatchMessage(msg.type, this._handlers[msg.type], aMsg);
+    }, this);
   },
 
   // nsIDOMGlobalPropertyInitializer implementation.
   init: function sysMessMgr_init(aWindow) {
     debug("init");
-    this.initHelper(aWindow, ["SystemMessageManager:Message"]);
+    this.initHelper(aWindow, ["SystemMessageManager:Message",
+                              "SystemMessageManager:GetPendingMessages:Return"]);
 
     let principal = aWindow.document.nodePrincipal;
     this._uri = principal.URI.spec;
 
     let appsService = Cc["@mozilla.org/AppsService;1"]
                         .getService(Ci.nsIAppsService);
     this._manifest = appsService.getManifestURLByLocalId(principal.appId);
     this._window = aWindow;
--- a/dom/settings/SettingsManager.js
+++ b/dom/settings/SettingsManager.js
@@ -104,17 +104,17 @@ SettingsLock.prototype = {
 
             for (var i in event.target.result) {
               let result = event.target.result[i];
               var name = result.settingName;
               var value = result.settingValue;
               results[name] = value;
               results.__exposedProps__[name] = "r";
               // If the value itself is an object, expose the properties.
-              if (typeof value == "object") {
+              if (typeof value == "object" && value != null) {
                 var exposed = {};
                 Object.keys(value).forEach(function(key) { exposed[key] = 'r'; });
                 results[name].__exposedProps__ = exposed;
               }
             }
 
             this._open = true;
             Services.DOMRequest.fireSuccess(request, results);
--- a/editor/txtsvc/src/nsTextServicesDocument.cpp
+++ b/editor/txtsvc/src/nsTextServicesDocument.cpp
@@ -1378,23 +1378,24 @@ nsTextServicesDocument::DeleteSelection(
 
     if (origStartNode != curStartNode || origEndNode != curEndNode)
     {
       // The range has changed, so we need to create a new content
       // iterator based on the new range.
 
       nsCOMPtr<nsIContent> curContent;
 
-      if (mIteratorStatus != nsTextServicesDocument::eIsDone &&
-          mIterator->GetCurrentNode()->IsContent()) {
+      if (mIteratorStatus != nsTextServicesDocument::eIsDone) {
         // The old iterator is still pointing to something valid,
         // so get its current node so we can restore it after we
         // create the new iterator!
 
-        curContent = mIterator->GetCurrentNode()->AsContent();
+        curContent = mIterator->GetCurrentNode()
+                     ? mIterator->GetCurrentNode()->AsContent()
+                     : nullptr;
       }
 
       // Create the new iterator.
 
       result = CreateContentIterator(mExtent, getter_AddRefs(mIterator));
 
       if (NS_FAILED(result))
       {
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -6,17 +6,16 @@
 #pragma once
 
 #include "skia/SkCanvas.h"
 #include "2D.h"
 #include "Rect.h"
 #include "PathSkia.h"
 #include <sstream>
 #include <vector>
-using namespace std;
 
 namespace mozilla {
 namespace gfx {
 
 class SourceSurfaceSkia;
 
 class DrawTargetSkia : public DrawTarget
 {
@@ -100,13 +99,13 @@ private:
   void RemoveSnapshot(SourceSurfaceSkia* aSnapshot);
 
   void MarkChanged();
 
   IntSize mSize;
   SkBitmap mBitmap;
   SkRefPtr<SkCanvas> mCanvas;
   SkRefPtr<SkDevice> mDevice;
-  vector<SourceSurfaceSkia*> mSnapshots;
+  std::vector<SourceSurfaceSkia*> mSnapshots;
 };
 
 }
 }
--- a/gfx/2d/Tools.h
+++ b/gfx/2d/Tools.h
@@ -37,17 +37,17 @@ struct ClassStorage
 
   const T *addr() const { return (const T *)bytes; }
   T *addr() { return (T *)(void *)bytes; }
 };
 
 static inline bool
 FuzzyEqual(Float aA, Float aB, Float aErr)
 {
-  if ((aA + aErr > aB) && (aA - aErr < aB)) {
+  if ((aA + aErr >= aB) && (aA - aErr <= aB)) {
     return true;
   }
   return false;
 }
 
 static inline void
 NudgeToInteger(float *aVal)
 {
--- a/gfx/layers/basic/BasicCanvasLayer.cpp
+++ b/gfx/layers/basic/BasicCanvasLayer.cpp
@@ -9,16 +9,17 @@
 #include "gfxUtils.h"
 #include "gfxPlatform.h"
 #include "mozilla/Preferences.h"
 
 #include "BasicLayersImpl.h"
 #include "nsXULAppAPI.h"
 
 using namespace mozilla::gfx;
+using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 class BasicCanvasLayer : public CanvasLayer,
                          public BasicImplData
 {
 public:
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -149,16 +149,17 @@ public:
                                                  bool* aNeedsClipToVisibleRegion);
   already_AddRefed<gfxContext> PushGroupWithCachedSurface(gfxContext *aTarget,
                                                           gfxASurface::gfxContentType aContent);
   void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
 
   virtual bool IsCompositingCheap() { return false; }
   virtual int32_t GetMaxTextureSize() const { return INT32_MAX; }
   bool CompositorMightResample() { return mCompositorMightResample; }
+  bool HasShadowTarget() { return !!mShadowTarget; }
 
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 
   // This is the main body of the PaintLayer routine which will if it has
--- a/gfx/layers/basic/BasicTiledThebesLayer.cpp
+++ b/gfx/layers/basic/BasicTiledThebesLayer.cpp
@@ -392,16 +392,17 @@ BasicTiledThebesLayer::PaintThebes(gfxCo
   for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
     const FrameMetrics& metrics = parent->GetFrameMetrics();
     resolution.width *= metrics.mResolution.width;
     resolution.height *= metrics.mResolution.height;
   }
 
   // Only draw progressively when the resolution is unchanged.
   if (gfxPlatform::UseProgressiveTilePainting() &&
+      !BasicManager()->HasShadowTarget() &&
       mTiledBuffer.GetResolution() == resolution) {
     // Calculate the transform required to convert screen space into layer space
     gfx3DMatrix transform = GetEffectiveTransform();
     // XXX Not sure if this code for intermediate surfaces is correct.
     //     It rarely gets hit though, and shouldn't have terrible consequences
     //     even if it is wrong.
     for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
       if (parent->UseIntermediateSurface()) {
--- a/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsD3D10.cpp
@@ -6,16 +6,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <d3d10_1.h>
 #include <dxgi.h>
 
 #include "mozilla/layers/PLayers.h"
 #include "ShadowLayers.h"
 
+using namespace mozilla::gl;
+
 namespace mozilla {
 namespace layers {
 
 // Platform-specific shadow-layers interfaces.  See ShadowLayers.h.
 // D3D10 doesn't need all these yet.
 bool
 ShadowLayerForwarder::PlatformAllocBuffer(const gfxIntSize&,
                                           gfxASurface::gfxContentType,
--- a/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsGralloc.cpp
@@ -17,16 +17,17 @@
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 
 #include "sampler.h"
 
 using namespace android;
 using namespace base;
 using namespace mozilla::layers;
+using namespace mozilla::gl;
 
 namespace IPC {
 
 void
 ParamTraits<MagicGrallocBufferHandle>::Write(Message* aMsg,
                                              const paramType& aParam)
 {
   Flattenable *flattenable = aParam.mGraphicBuffer.get();
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -9,16 +9,18 @@
 #include "mozilla/layers/ShadowLayers.h"
  
 #include "gfxPlatform.h"
 
 #include "gfxXlibSurface.h"
 #include "mozilla/X11Util.h"
 #include "cairo-xlib.h"
 
+using namespace mozilla::gl;
+
 namespace mozilla {
 namespace layers {
 
 // Return true if we're likely compositing using X and so should use
 // Xlib surfaces in shadow layers.
 static bool
 UsingXCompositing()
 {
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -19,16 +19,17 @@
 #include "ShadowLayers.h"
 #include "ShadowLayerChild.h"
 #include "gfxipc/ShadowLayerUtils.h"
 #include "RenderTrace.h"
 #include "sampler.h"
 #include "nsXULAppAPI.h"
 
 using namespace mozilla::ipc;
+using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 typedef nsTArray<SurfaceDescriptor> BufferArray; 
 typedef std::vector<Edit> EditVector;
 typedef std::set<ShadowableLayer*> ShadowableLayerSet;
 
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -18,17 +18,16 @@
 class gfxSharedImageSurface;
 
 namespace mozilla {
 
 namespace gl {
 class GLContext;
 class TextureImage;
 }
-using namespace gl;
 
 namespace layers {
 
 class Edit;
 class EditReply;
 class OptionalThebesBuffer;
 class PLayerChild;
 class PLayersChild;
@@ -411,18 +410,18 @@ public:
 
   virtual void NotifyShadowTreeTransaction() {}
 
   /**
    * Try to open |aDescriptor| for direct texturing.  If the
    * underlying surface supports direct texturing, a non-null
    * TextureImage is returned.  Otherwise null is returned.
    */
-  static already_AddRefed<TextureImage>
-  OpenDescriptorForDirectTexturing(GLContext* aContext,
+  static already_AddRefed<gl::TextureImage>
+  OpenDescriptorForDirectTexturing(gl::GLContext* aContext,
                                    const SurfaceDescriptor& aDescriptor,
                                    GLenum aWrapMode);
 
   static void PlatformSyncBeforeReplyUpdate();
 
   void SetCompositorID(uint32_t aID)
   {
     NS_ASSERTION(mCompositorID==0, "The compositor ID must be set only once.");
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -1448,10 +1448,92 @@ LayerManagerOGL::CreateDrawTarget(const 
   if (useAcceleration) {
     return Factory::CreateDrawTarget(BACKEND_COREGRAPHICS_ACCELERATED,
                                      aSize, aFormat);
   }
 #endif
   return LayerManager::CreateDrawTarget(aSize, aFormat);
 }
 
+/* static */ void
+LayerManagerOGL::ComputeRenderIntegrityInternal(Layer* aLayer,
+                                                nsIntRegion& aScreenRegion,
+                                                const gfx3DMatrix& aTransform)
+{
+  if (aScreenRegion.IsEmpty() || aLayer->GetOpacity() <= 0.f) {
+    return;
+  }
+
+  // If the layer's a container, recurse into all of its children
+  ContainerLayer* container = aLayer->AsContainerLayer();
+  if (container) {
+    // Accumulate the transform of intermediate surfaces
+    gfx3DMatrix transform = aTransform;
+    if (container->UseIntermediateSurface()) {
+      transform = aLayer->GetEffectiveTransform();
+      transform.PreMultiply(aTransform);
+    }
+    for (Layer* child = aLayer->GetFirstChild(); child;
+         child = child->GetNextSibling()) {
+      ComputeRenderIntegrityInternal(child, aScreenRegion, transform);
+    }
+    return;
+  }
+
+  // Only thebes layers can be incomplete
+  ThebesLayer* thebesLayer = aLayer->AsThebesLayer();
+  if (!thebesLayer) {
+    return;
+  }
+
+  // See if there's any incomplete rendering
+  nsIntRegion incompleteRegion = aLayer->GetEffectiveVisibleRegion();
+  incompleteRegion.Sub(incompleteRegion, thebesLayer->GetValidRegion());
+
+  if (!incompleteRegion.IsEmpty()) {
+    // Calculate the transform to get between screen and layer space
+    gfx3DMatrix transformToScreen = aLayer->GetEffectiveTransform();
+    transformToScreen.PreMultiply(aTransform);
+
+    // For each rect in the region, find out its bounds in screen space and
+    // subtract it from the screen region.
+    nsIntRegionRectIterator it(incompleteRegion);
+    while (const nsIntRect* rect = it.Next()) {
+      gfxRect incompleteRect = transformToScreen.TransformBounds(gfxRect(*rect));
+      aScreenRegion.Sub(aScreenRegion, nsIntRect(incompleteRect.x,
+                                                 incompleteRect.y,
+                                                 incompleteRect.width,
+                                                 incompleteRect.height));
+    }
+  }
+}
+
+float
+LayerManagerOGL::ComputeRenderIntegrity()
+{
+  // We only ever have incomplete rendering when progressive tiles are enabled.
+  if (!gfxPlatform::UseProgressiveTilePainting() || !GetRoot()) {
+    return 1.f;
+  }
+
+  // XXX We assume that mWidgetSize represents the 'screen' area.
+  gfx3DMatrix transform;
+  nsIntRect screenRect(0, 0, mWidgetSize.width, mWidgetSize.height);
+  nsIntRegion screenRegion(screenRect);
+  ComputeRenderIntegrityInternal(GetRoot(), screenRegion, transform);
+
+  if (!screenRegion.IsEqual(screenRect)) {
+    // Calculate the area of the region. All rects in an nsRegion are
+    // non-overlapping.
+    int area = 0;
+    nsIntRegionRectIterator it(screenRegion);
+    while (const nsIntRect* rect = it.Next()) {
+      area += rect->width * rect->height;
+    }
+
+    return area / (float)(screenRect.width * screenRect.height);
+  }
+
+  return 1.f;
+}
+
 } /* layers */
 } /* mozilla */
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -356,16 +356,25 @@ public:
   /**
    * Creates a DrawTarget which is optimized for inter-operating with this
    * layermanager.
    */
   virtual TemporaryRef<mozilla::gfx::DrawTarget>
     CreateDrawTarget(const mozilla::gfx::IntSize &aSize,
                      mozilla::gfx::SurfaceFormat aFormat);
 
+  /**
+   * Calculates the 'completeness' of the rendering that intersected with the
+   * screen on the last render. This is only useful when progressive tile
+   * drawing is enabled, otherwise this will always return 1.0.
+   * This function's expense scales with the size of the layer tree and the
+   * complexity of individual layers' valid regions.
+   */
+  float ComputeRenderIntegrity();
+
 private:
   /** Widget associated with this layer manager */
   nsIWidget *mWidget;
   nsIntSize mWidgetSize;
 
   /** The size of the surface we are rendering to */
   nsIntSize mSurfaceSize;
 
@@ -435,16 +444,25 @@ private:
   void SetLayerProgramProjectionMatrix(const gfx3DMatrix& aMatrix);
 
   /**
    * Helper method for Initialize, creates all valid variations of a program
    * and adds them to mPrograms
    */
   void AddPrograms(gl::ShaderProgramType aType);
 
+  /**
+   * Recursive helper method for use by ComputeRenderIntegrity. Subtracts
+   * any incomplete rendering on aLayer from aScreenRegion. aTransform is the
+   * accumulated transform of intermediate surfaces beneath aLayer.
+   */
+  static void ComputeRenderIntegrityInternal(Layer* aLayer,
+                                             nsIntRegion& aScreenRegion,
+                                             const gfx3DMatrix& aTransform);
+
   /* Thebes layer callbacks; valid at the end of a transaciton,
    * while rendering */
   DrawThebesLayerCallback mThebesLayerCallback;
   void *mThebesLayerCallbackData;
   gfxMatrix mWorldMatrix;
   nsAutoPtr<FPSState> mFPS;
 
   static bool sDrawFPS;
--- a/intl/lwbrk/src/nsJISx4501LineBreaker.cpp
+++ b/intl/lwbrk/src/nsJISx4501LineBreaker.cpp
@@ -540,17 +540,17 @@ public:
     mLength = aLength;
     Init();
   }
 
   uint32_t Length() { return mLength; }
   uint32_t Index() { return mIndex; }
 
   PRUnichar GetCharAt(uint32_t aIndex) {
-    NS_ASSERTION(0 <= aIndex && aIndex < mLength, "Out of range!");
+    NS_ASSERTION(aIndex < mLength, "Out of range!");
     return mUniText ? mUniText[aIndex] : PRUnichar(mText[aIndex]);
   }
 
   void AdvanceIndex() {
     ++mIndex;
   }
 
   void NotifyBreakBefore() { mLastBreakIndex = mIndex; }
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -493,16 +493,44 @@ struct RootKind<T *> { static ThingRootK
 template <typename T>
 struct RootMethods<T *>
 {
     static T *initial() { return NULL; }
     static ThingRootKind kind() { return RootKind<T *>::rootKind(); }
     static bool poisoned(T *v) { return IsPoisonedPtr(v); }
 };
 
+#if !defined(JSGC_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING)
+template <typename T>
+struct RootSink {
+    static inline void dispose(const T &) {}
+};
+
+/*
+ * The *alleged* killer whale hack (see JS::Anchor<T> in jsapi.h) duplicated
+ * here because using JS::Anchor causes clang to emit bad instructions.
+ *
+ * In exact-gc builds, Rooted<T> always keeps the T reachable. In non-exact-gc
+ * builds, it does not, but conservative scanning usually picks up the slack.
+ * However in the case where the Rooted pointer is no longer used, but some
+ * subobject or malloc'd memory with the same lifetime may be used,
+ * conservative scanning can fail. JSStableString's chars() method makes it
+ * particularly attractive to use that way, so we use some voodoo to convince
+ * the compiler to keep the string pointer on the stack for the full lifetime
+ * of the Rooted<JSStableString *>.
+ */
+template <>
+struct RootSink<JSStableString *> {
+    static void dispose(JSStableString *ptr) {
+        JSStableString * volatile sink;
+        sink = ptr;
+    }
+};
+#endif
+
 template <typename T>
 class RootedBase {};
 
 /*
  * Local variable of type T whose value is always rooted. This is typically
  * used for local variables, or for non-rooted values being passed to a
  * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
  *
@@ -582,16 +610,18 @@ class Rooted : public RootedBase<T>
         init(cx);
     }
 
     ~Rooted()
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         JS_ASSERT(*stack == this);
         *stack = prev;
+#else
+        RootSink<T>::dispose(ptr);
 #endif
     }
 
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
     Rooted<T> *previous() { return prev; }
 #endif
 
     operator T () const { return ptr; }
--- a/js/src/ion/AliasAnalysis.cpp
+++ b/js/src/ion/AliasAnalysis.cpp
@@ -6,16 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdio.h>
 
 #include "MIR.h"
 #include "AliasAnalysis.h"
 #include "MIRGraph.h"
 #include "Ion.h"
+#include "IonBuilder.h"
 #include "IonSpewer.h"
 
 using namespace js;
 using namespace js::ion;
 
 // Iterates over the flags in an AliasSet.
 class AliasSetIterator
 {
@@ -42,18 +43,19 @@ class AliasSetIterator
     operator bool() const {
         return !!flags;
     }
     unsigned operator *() const {
         return pos;
     }
 };
 
-AliasAnalysis::AliasAnalysis(MIRGraph &graph)
-  : graph_(graph),
+AliasAnalysis::AliasAnalysis(MIRGenerator *mir, MIRGraph &graph)
+  : mir(mir),
+    graph_(graph),
     loop_(NULL)
 {
 }
 
 // This pass annotates every load instruction with the last store instruction
 // on which it depends. The algorithm is optimistic in that it ignores explicit
 // dependencies and only considers loads and stores.
 //
@@ -80,16 +82,19 @@ AliasAnalysis::analyze()
     }
 
     // Type analysis may have inserted new instructions. Since this pass depends
     // on the instruction number ordering, all instructions are renumbered.
     // We start with 1 because some passes use 0 to denote failure.
     uint32 newId = 1;
 
     for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
+        if (mir->shouldCancel("Alias Analysis (main loop)"))
+            return false;
+
         if (block->isLoopHeader()) {
             IonSpew(IonSpew_Alias, "Processing loop header %d", block->id());
             loop_ = new LoopAliasInfo(loop_, *block);
         }
 
         for (MDefinitionIterator def(*block); def; def++) {
             def->setId(newId++);
 
--- a/js/src/ion/AliasAnalysis.h
+++ b/js/src/ion/AliasAnalysis.h
@@ -50,20 +50,21 @@ class LoopAliasInfo : public TempObject 
     }
     MDefinition *firstInstruction() const {
         return *loopHeader_->begin();
     }
 };
 
 class AliasAnalysis
 {
+    MIRGenerator *mir;
     MIRGraph &graph_;
     LoopAliasInfo *loop_;
 
   public:
-    AliasAnalysis(MIRGraph &graph);
+    AliasAnalysis(MIRGenerator *mir, MIRGraph &graph);
     bool analyze();
 };
 
 } // namespace js
 } // namespace ion
 
 #endif // jsion_alias_analysis_h__
--- a/js/src/ion/EdgeCaseAnalysis.cpp
+++ b/js/src/ion/EdgeCaseAnalysis.cpp
@@ -3,50 +3,57 @@
  *
  * 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 <stdio.h>
 
 #include "Ion.h"
+#include "IonBuilder.h"
 #include "IonSpewer.h"
 #include "EdgeCaseAnalysis.h"
 #include "MIR.h"
 #include "MIRGraph.h"
 
 using namespace js;
 using namespace js::ion;
 
-EdgeCaseAnalysis::EdgeCaseAnalysis(MIRGraph &graph)
-  : graph(graph)
+EdgeCaseAnalysis::EdgeCaseAnalysis(MIRGenerator *mir, MIRGraph &graph)
+  : mir(mir), graph(graph)
 {
 }
 
 bool
 EdgeCaseAnalysis::analyzeLate()
 {
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
+        if (mir->shouldCancel("Analyze Late (first loop)"))
+            return false;
         for (MDefinitionIterator iter(*block); iter; iter++)
             iter->analyzeEdgeCasesForward();
     }
 
     for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); block++) {
+        if (mir->shouldCancel("Analyze Late (second loop)"))
+            return false;
         for (MInstructionReverseIterator riter(block->rbegin()); riter != block->rend(); riter++)
             riter->analyzeEdgeCasesBackward();
     }
 
     return true;
 }
 
 bool
 EdgeCaseAnalysis::analyzeEarly()
 {
 
     for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); block++) {
+        if (mir->shouldCancel("Analyze Early (main loop)"))
+            return false;
         for (MInstructionReverseIterator riter(block->rbegin()); riter != block->rend(); riter++)
             riter->analyzeTruncateBackward();
     }
 
     return true;
 }
 
 bool
--- a/js/src/ion/EdgeCaseAnalysis.h
+++ b/js/src/ion/EdgeCaseAnalysis.h
@@ -10,20 +10,21 @@
 
 namespace js {
 namespace ion {
 
 class MIRGraph;
 
 class EdgeCaseAnalysis
 {
+    MIRGenerator *mir;
     MIRGraph &graph;
 
   public:
-    EdgeCaseAnalysis(MIRGraph &graph);
+    EdgeCaseAnalysis(MIRGenerator *mir, MIRGraph &graph);
     bool analyzeEarly();
     bool analyzeLate();
     static bool AllUsesTruncate(MInstruction *m);
 };
 
 
 } // namespace ion
 } // namespace js
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -760,134 +760,191 @@ LIRGraph *
 CompileBackEnd(MIRGenerator *mir)
 {
     IonSpewPass("BuildSSA");
     // Note: don't call AssertGraphCoherency before SplitCriticalEdges,
     // the graph is not in RPO at this point.
 
     MIRGraph &graph = mir->graph();
 
+    if (mir->shouldCancel("Start"))
+        return NULL;
+
     if (!SplitCriticalEdges(graph))
         return NULL;
     IonSpewPass("Split Critical Edges");
     AssertGraphCoherency(graph);
 
+    if (mir->shouldCancel("Split Critical Edges"))
+        return NULL;
+
     if (!RenumberBlocks(graph))
         return NULL;
     IonSpewPass("Renumber Blocks");
     AssertGraphCoherency(graph);
 
+    if (mir->shouldCancel("Renumber Blocks"))
+        return NULL;
+
     if (!BuildDominatorTree(graph))
         return NULL;
     // No spew: graph not changed.
 
+    if (mir->shouldCancel("Dominator Tree"))
+        return NULL;
+
     // This must occur before any code elimination.
-    if (!EliminatePhis(graph))
+    if (!EliminatePhis(mir, graph))
         return NULL;
     IonSpewPass("Eliminate phis");
     AssertGraphCoherency(graph);
 
+    if (mir->shouldCancel("Eliminate phis"))
+        return NULL;
+
     if (!BuildPhiReverseMapping(graph))
         return NULL;
     // No spew: graph not changed.
 
+    if (mir->shouldCancel("Phi reverse mapping"))
+        return NULL;
+
     // This pass also removes copies.
-    if (!ApplyTypeInformation(graph))
+    if (!ApplyTypeInformation(mir, graph))
         return NULL;
     IonSpewPass("Apply types");
     AssertGraphCoherency(graph);
 
+    if (mir->shouldCancel("Apply types"))
+        return NULL;
+
     // Alias analysis is required for LICM and GVN so that we don't move
     // loads across stores.
     if (js_IonOptions.licm || js_IonOptions.gvn) {
-        AliasAnalysis analysis(graph);
+        AliasAnalysis analysis(mir, graph);
         if (!analysis.analyze())
             return NULL;
         IonSpewPass("Alias analysis");
         AssertGraphCoherency(graph);
+
+        if (mir->shouldCancel("Alias analysis"))
+            return NULL;
     }
 
     if (js_IonOptions.edgeCaseAnalysis) {
-        EdgeCaseAnalysis edgeCaseAnalysis(graph);
+        EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
         if (!edgeCaseAnalysis.analyzeEarly())
             return NULL;
         IonSpewPass("Edge Case Analysis (Early)");
         AssertGraphCoherency(graph);
+
+        if (mir->shouldCancel("Edge Case Analysis (Early)"))
+            return NULL;
     }
 
     if (js_IonOptions.gvn) {
-        ValueNumberer gvn(graph, js_IonOptions.gvnIsOptimistic);
+        ValueNumberer gvn(mir, graph, js_IonOptions.gvnIsOptimistic);
         if (!gvn.analyze())
             return NULL;
         IonSpewPass("GVN");
         AssertGraphCoherency(graph);
+
+        if (mir->shouldCancel("GVN"))
+            return NULL;
     }
 
     if (js_IonOptions.rangeAnalysis) {
         RangeAnalysis r(graph);
         if (!r.addBetaNobes())
             return NULL;
         IonSpewPass("Beta");
         AssertGraphCoherency(graph);
 
+        if (mir->shouldCancel("RA Beta"))
+            return NULL;
+
         if (!r.analyze())
             return NULL;
         IonSpewPass("Range Analysis");
         AssertGraphCoherency(graph);
 
+        if (mir->shouldCancel("Range Analysis"))
+            return NULL;
+
         if (!r.removeBetaNobes())
             return NULL;
         IonSpewPass("De-Beta");
         AssertGraphCoherency(graph);
+
+        if (mir->shouldCancel("RA De-Beta"))
+            return NULL;
     }
 
-    if (!EliminateDeadCode(graph))
+    if (!EliminateDeadCode(mir, graph))
         return NULL;
     IonSpewPass("DCE");
     AssertGraphCoherency(graph);
 
+    if (mir->shouldCancel("DCE"))
+        return NULL;
+
     if (js_IonOptions.licm) {
-        LICM licm(graph);
+        LICM licm(mir, graph);
         if (!licm.analyze())
             return NULL;
         IonSpewPass("LICM");
         AssertGraphCoherency(graph);
+
+        if (mir->shouldCancel("LICM"))
+            return NULL;
     }
 
     if (js_IonOptions.edgeCaseAnalysis) {
-        EdgeCaseAnalysis edgeCaseAnalysis(graph);
+        EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
         if (!edgeCaseAnalysis.analyzeLate())
             return NULL;
         IonSpewPass("Edge Case Analysis (Late)");
         AssertGraphCoherency(graph);
+
+        if (mir->shouldCancel("Edge Case Analysis (Late)"))
+            return NULL;
     }
 
     // Note: bounds check elimination has to run after all other passes that
     // move instructions. Since bounds check uses are replaced with the actual
     // index, code motion after this pass could incorrectly move a load or
     // store before its bounds check.
     if (!EliminateRedundantBoundsChecks(graph))
         return NULL;
     IonSpewPass("Bounds Check Elimination");
     AssertGraphCoherency(graph);
 
+    if (mir->shouldCancel("Bounds Check Elimination"))
+        return NULL;
+
     LIRGraph *lir = mir->temp().lifoAlloc()->new_<LIRGraph>(&graph);
     if (!lir)
         return NULL;
 
     LIRGenerator lirgen(mir, graph, *lir);
     if (!lirgen.generate())
         return NULL;
     IonSpewPass("Generate LIR");
 
+    if (mir->shouldCancel("Generate LIR"))
+        return NULL;
+
     if (js_IonOptions.lsra) {
-        LinearScanAllocator regalloc(&lirgen, *lir);
+        LinearScanAllocator regalloc(mir, &lirgen, *lir);
         if (!regalloc.go())
             return NULL;
         IonSpewPass("Allocate Registers", &regalloc);
+
+        if (mir->shouldCancel("Allocate Registers"))
+            return NULL;
     }
 
     return lir;
 }
 
 class AutoDestroyAllocator
 {
     LifoAlloc *alloc;
--- a/js/src/ion/IonAnalysis.cpp
+++ b/js/src/ion/IonAnalysis.cpp
@@ -39,21 +39,24 @@ ion::SplitCriticalEdges(MIRGraph &graph)
     }
     return true;
 }
 
 // Instructions are useless if they are unused and have no side effects.
 // This pass eliminates useless instructions.
 // The graph itself is unchanged.
 bool
-ion::EliminateDeadCode(MIRGraph &graph)
+ion::EliminateDeadCode(MIRGenerator *mir, MIRGraph &graph)
 {
     // Traverse in postorder so that we hit uses before definitions.
     // Traverse instruction list backwards for the same reason.
     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
+        if (mir->shouldCancel("Eliminate Dead Code (main loop)"))
+            return false;
+
         // Remove unused instructions.
         for (MInstructionReverseIterator inst = block->rbegin(); inst != block->rend(); ) {
             if (!inst->isEffectful() && !inst->hasUses() && !inst->isGuard() &&
                 !inst->isControlInstruction()) {
                 inst = block->discardAt(inst);
             } else {
                 inst++;
             }
@@ -102,23 +105,26 @@ IsPhiRedundant(MPhi *phi)
     // another phi.
     if (phi->hasBytecodeUses() && first->isPhi())
         first->toPhi()->setHasBytecodeUses();
 
     return first;
 }
 
 bool
-ion::EliminatePhis(MIRGraph &graph)
+ion::EliminatePhis(MIRGenerator *mir, MIRGraph &graph)
 {
     Vector<MPhi *, 16, SystemAllocPolicy> worklist;
 
     // Add all observable phis to a worklist. We use the "in worklist" bit to
     // mean "this phi is live".
     for (PostorderIterator block = graph.poBegin(); block != graph.poEnd(); block++) {
+        if (mir->shouldCancel("Eliminate Phis (populate loop)"))
+            return false;
+
         MPhiIterator iter = block->phisBegin();
         while (iter != block->phisEnd()) {
             // Flag all as unused, only observable phis would be marked as used
             // when processed by the work list.
             iter->setUnused();
 
             // If the phi is redundant, remove it here.
             if (MDefinition *redundant = IsPhiRedundant(*iter)) {
@@ -134,16 +140,19 @@ ion::EliminatePhis(MIRGraph &graph)
                     return false;
             }
             iter++;
         }
     }
 
     // Iteratively mark all phis reachable from live phis.
     while (!worklist.empty()) {
+        if (mir->shouldCancel("Eliminate Phis (worklist)"))
+            return false;
+
         MPhi *phi = worklist.popCopy();
         JS_ASSERT(phi->isUnused());
         phi->setNotInWorklist();
 
         // The removal of Phis can produce newly redundant phis.
         if (MDefinition *redundant = IsPhiRedundant(phi)) {
             // Add to the worklist the used phis which are impacted.
             for (MUseDefIterator it(phi); it; it++) {
@@ -195,16 +204,17 @@ ion::EliminatePhis(MIRGraph &graph)
 // specialized to return that type.
 //
 // Input adjustment: Each input is asked to apply conversion operations to its
 // inputs. This may include Box, Unbox, or other instruction-specific type
 // conversion operations.
 //
 class TypeAnalyzer
 {
+    MIRGenerator *mir;
     MIRGraph &graph;
     Vector<MPhi *, 0, SystemAllocPolicy> phiWorklist_;
 
     bool addPhiToWorklist(MPhi *phi) {
         if (phi->isInWorklist())
             return true;
         if (!phiWorklist_.append(phi))
             return false;
@@ -221,18 +231,18 @@ class TypeAnalyzer
     bool propagateSpecialization(MPhi *phi);
     bool specializePhis();
     void replaceRedundantPhi(MPhi *phi);
     void adjustPhiInputs(MPhi *phi);
     bool adjustInputs(MDefinition *def);
     bool insertConversions();
 
   public:
-    TypeAnalyzer(MIRGraph &graph)
-      : graph(graph)
+    TypeAnalyzer(MIRGenerator *mir, MIRGraph &graph)
+      : mir(mir), graph(graph)
     { }
 
     bool analyze();
 };
 
 // Try to specialize this phi based on its non-cyclic inputs.
 static MIRType
 GuessPhiType(MPhi *phi)
@@ -310,32 +320,38 @@ TypeAnalyzer::propagateSpecialization(MP
 
     return true;
 }
 
 bool
 TypeAnalyzer::specializePhis()
 {
     for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); block++) {
+        if (mir->shouldCancel("Specialize Phis (main loop)"))
+            return false;
+
         for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
             MIRType type = GuessPhiType(*phi);
             phi->specialize(type);
             if (type == MIRType_None) {
                 // We tried to guess the type but failed because all operands are
                 // phis we still have to visit. Set the triedToSpecialize flag but
                 // don't propagate the type to other phis, propagateSpecialization
                 // will do that once we know the type of one of the operands.
                 continue;
             }
             if (!propagateSpecialization(*phi))
                 return false;
         }
     }
 
     while (!phiWorklist_.empty()) {
+        if (mir->shouldCancel("Specialize Phis (worklist)"))
+            return false;
+
         MPhi *phi = popPhi();
         if (!propagateSpecialization(phi))
             return false;
     }
 
     return true;
 }
 
@@ -417,16 +433,19 @@ TypeAnalyzer::replaceRedundantPhi(MPhi *
 
 bool
 TypeAnalyzer::insertConversions()
 {
     // Instructions are processed in reverse postorder: all uses are defs are
     // seen before uses. This ensures that output adjustment (which may rewrite
     // inputs of uses) does not conflict with input adjustment.
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
+        if (mir->shouldCancel("Insert Conversions"))
+            return false;
+
         for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd();) {
             if (phi->type() <= MIRType_Null || phi->type() == MIRType_Magic) {
                 replaceRedundantPhi(*phi);
                 phi = block->discardPhiAt(phi);
             } else {
                 adjustPhiInputs(*phi);
                 phi++;
             }
@@ -445,19 +464,19 @@ TypeAnalyzer::analyze()
     if (!specializePhis())
         return false;
     if (!insertConversions())
         return false;
     return true;
 }
 
 bool
-ion::ApplyTypeInformation(MIRGraph &graph)
+ion::ApplyTypeInformation(MIRGenerator *mir, MIRGraph &graph)
 {
-    TypeAnalyzer analyzer(graph);
+    TypeAnalyzer analyzer(mir, graph);
 
     if (!analyzer.analyze())
         return false;
 
     return true;
 }
 
 bool
--- a/js/src/ion/IonAnalysis.h
+++ b/js/src/ion/IonAnalysis.h
@@ -17,23 +17,23 @@ namespace ion {
 
 class MIRGenerator;
 class MIRGraph;
 
 bool
 SplitCriticalEdges(MIRGraph &graph);
 
 bool
-EliminatePhis(MIRGraph &graph);
+EliminatePhis(MIRGenerator *mir, MIRGraph &graph);
 
 bool
-EliminateDeadCode(MIRGraph &graph);
+EliminateDeadCode(MIRGenerator *mir, MIRGraph &graph);
 
 bool
-ApplyTypeInformation(MIRGraph &graph);
+ApplyTypeInformation(MIRGenerator *mir, MIRGraph &graph);
 
 bool
 RenumberBlocks(MIRGraph &graph);
 
 bool
 BuildDominatorTree(MIRGraph &graph);
 
 bool
--- a/js/src/ion/LICM.cpp
+++ b/js/src/ion/LICM.cpp
@@ -3,16 +3,17 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdio.h>
 
 #include "Ion.h"
+#include "IonBuilder.h"
 #include "IonSpewer.h"
 #include "LICM.h"
 #include "MIR.h"
 #include "MIRGraph.h"
 
 using namespace js;
 using namespace js::ion;
 
@@ -69,18 +70,18 @@ ion::ExtractLinearInequality(MTest *test
     }
 
     *plhs = lsum;
     *prhs = rsum.term;
 
     return true;
 }
 
-LICM::LICM(MIRGraph &graph)
-  : graph(graph)
+LICM::LICM(MIRGenerator *mir, MIRGraph &graph)
+  : mir(mir), graph(graph)
 {
 }
 
 bool
 LICM::analyze()
 {
     IonSpew(IonSpew_LICM, "Beginning LICM pass.");
 
@@ -88,33 +89,34 @@ LICM::analyze()
     for (ReversePostorderIterator i(graph.rpoBegin()); i != graph.rpoEnd(); i++) {
         MBasicBlock *header = *i;
 
         // Skip non-headers and self-loops.
         if (!header->isLoopHeader() || header->numPredecessors() < 2)
             continue;
 
         // Attempt to optimize loop.
-        Loop loop(header->backedge(), header, graph);
+        Loop loop(mir, header->backedge(), header, graph);
 
         Loop::LoopReturn lr = loop.init();
         if (lr == Loop::LoopReturn_Error)
             return false;
         if (lr == Loop::LoopReturn_Skip)
             continue;
 
         if (!loop.optimize())
             return false;
     }
 
     return true;
 }
 
-Loop::Loop(MBasicBlock *footer, MBasicBlock *header, MIRGraph &graph)
-  : graph(graph),
+Loop::Loop(MIRGenerator *mir, MBasicBlock *footer, MBasicBlock *header, MIRGraph &graph)
+  : mir(mir),
+    graph(graph),
     footer_(footer),
     header_(header)
 {
     preLoop_ = header_->getPredecessor(0);
 }
 
 Loop::LoopReturn
 Loop::init()
@@ -176,16 +178,19 @@ bool
 Loop::optimize()
 {
     InstructionQueue invariantInstructions;
     InstructionQueue boundsChecks;
 
     IonSpew(IonSpew_LICM, "These instructions are in the loop: ");
 
     while (!worklist_.empty()) {
+        if (mir->shouldCancel("LICM (worklist)"))
+            return false;
+
         MInstruction *ins = popFromWorklist();
 
         IonSpewHeader(IonSpew_LICM);
 
         if (IonSpewEnabled(IonSpew_LICM)) {
             ins->printName(IonSpewFile);
             fprintf(IonSpewFile, " <- ");
             ins->printOpcode(IonSpewFile);
--- a/js/src/ion/LICM.h
+++ b/js/src/ion/LICM.h
@@ -20,44 +20,46 @@ namespace ion {
 class MIRGraph;
 class MBasicBlock;
 
 typedef Vector<MBasicBlock*, 1, IonAllocPolicy> BlockQueue;
 typedef Vector<MInstruction*, 1, IonAllocPolicy> InstructionQueue;
 
 class LICM
 {
+    MIRGenerator *mir;
     MIRGraph &graph;
 
   public:
-    LICM(MIRGraph &graph);
+    LICM(MIRGenerator *mir, MIRGraph &graph);
     bool analyze();
 };
 
 // Extract a linear inequality holding when a boolean test goes in the
 // specified direction, of the form 'lhs + lhsN <= rhs' (or >=).
 bool
 ExtractLinearInequality(MTest *test, BranchDirection direction,
                         LinearSum *plhs, MDefinition **prhs, bool *plessEqual);
 
 class Loop
 {
+    MIRGenerator *mir;
     MIRGraph &graph;
 
   public:
     // Loop code may return three values:
     enum LoopReturn {
         LoopReturn_Success,
         LoopReturn_Error, // Compilation failure.
         LoopReturn_Skip   // The loop is not suitable for LICM, but there is no error.
     };
 
   public:
     // A loop is constructed on a backedge found in the control flow graph.
-    Loop(MBasicBlock *header, MBasicBlock *footer, MIRGraph &graph);
+    Loop(MIRGenerator *mir, MBasicBlock *header, MBasicBlock *footer, MIRGraph &graph);
 
     // Initializes the loop, finds all blocks and instructions contained in the loop.
     LoopReturn init();
 
     // Identifies hoistable loop invariant instructions and moves them out of the loop.
     bool optimize();
 
   private:
--- a/js/src/ion/LinearScan.cpp
+++ b/js/src/ion/LinearScan.cpp
@@ -3,16 +3,17 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <limits.h>
 #include "BitSet.h"
 #include "LinearScan.h"
+#include "IonBuilder.h"
 #include "IonSpewer.h"
 #include "LIR-inl.h"
 
 using namespace js;
 using namespace js::ion;
 
 static bool
 UseCompatibleWith(const LUse *use, LAllocation alloc)
@@ -384,16 +385,19 @@ LinearScanAllocator::createDataStructure
     if (!vregs.init(lir->mir(), graph.numVirtualRegisters()))
         return false;
 
     if (!insData.init(lir->mir(), graph.numInstructions()))
         return false;
 
     // Build virtual register objects
     for (size_t i = 0; i < graph.numBlocks(); i++) {
+        if (mir->shouldCancel("LSRA create data structures (main loop)"))
+            return false;
+
         LBlock *block = graph.getBlock(i);
         for (LInstructionIterator ins = block->begin(); ins != block->end(); ins++) {
             for (size_t j = 0; j < ins->numDefs(); j++) {
                 LDefinition *def = ins->getDef(j);
                 if (def->policy() != LDefinition::PASSTHROUGH) {
                     uint32 reg = def->virtualRegister();
                     if (!vregs[reg].init(reg, block, *ins, def, /* isTemp */ false))
                         return false;
@@ -476,16 +480,19 @@ bool
 LinearScanAllocator::buildLivenessInfo()
 {
     Vector<MBasicBlock *, 1, SystemAllocPolicy> loopWorkList;
     BitSet *loopDone = BitSet::New(graph.numBlockIds());
     if (!loopDone)
         return false;
 
     for (size_t i = graph.numBlocks(); i > 0; i--) {
+        if (mir->shouldCancel("LSRA Build Liveness Info (main loop)"))
+            return false;
+
         LBlock *block = graph.getBlock(i - 1);
         MBasicBlock *mblock = block->mir();
 
         BitSet *live = BitSet::New(graph.numVirtualRegisters());
         if (!live)
             return false;
         liveIn[mblock->id()] = live;
 
@@ -788,16 +795,19 @@ LinearScanAllocator::allocateRegisters()
     }
 
     // Iterate through all intervals in ascending start order.
     CodePosition prevPosition = CodePosition::MIN;
     while ((current = unhandled.dequeue()) != NULL) {
         JS_ASSERT(current->getAllocation()->isUse());
         JS_ASSERT(current->numRanges() > 0);
 
+        if (mir->shouldCancel("LSRA Allocate Registers (main loop)"))
+            return false;
+
         CodePosition position = current->start();
         Requirement *req = current->requirement();
         Requirement *hint = current->hint();
 
         IonSpew(IonSpew_RegAlloc, "Processing %d = [%u, %u] (pri=%d)",
                 current->reg() ? current->reg()->reg() : 0, current->start().pos(),
                 current->end().pos(), current->requirement()->priority());
 
@@ -919,16 +929,19 @@ LinearScanAllocator::allocateRegisters()
  * The algorithm is based on the one published in "Linear Scan Register
  * Allocation on SSA Form" by C. Wimmer et al., for which the full citation
  * appears above.
  */
 bool
 LinearScanAllocator::resolveControlFlow()
 {
     for (size_t i = 0; i < graph.numBlocks(); i++) {
+        if (mir->shouldCancel("LSRA Resolve Control Flow (main loop)"))
+            return false;
+
         LBlock *successor = graph.getBlock(i);
         MBasicBlock *mSuccessor = successor->mir();
         if (mSuccessor->numPredecessors() < 1)
             continue;
 
         // Resolve phis to moves
         for (size_t j = 0; j < successor->numPhis(); j++) {
             LPhi *phi = successor->getPhi(j);
@@ -1002,16 +1015,19 @@ LinearScanAllocator::moveInputAlloc(Code
  * corresponding to the appropriate interval.
  */
 bool
 LinearScanAllocator::reifyAllocations()
 {
     // Iterate over each interval, ensuring that definitions are visited before uses.
     for (size_t j = 1; j < graph.numVirtualRegisters(); j++) {
         VirtualRegister *reg = &vregs[j];
+        if (mir->shouldCancel("LSRA Reification (main loop)"))
+            return false;
+
     for (size_t k = 0; k < reg->numIntervals(); k++) {
         LiveInterval *interval = reg->getInterval(k);
         JS_ASSERT(reg == interval->reg());
         if (!interval->numRanges())
             continue;
 
         UsePositionIterator usePos(interval->usesBegin());
         for (; usePos != interval->usesEnd(); usePos++) {
@@ -1967,41 +1983,59 @@ LinearScanAllocator::go()
 {
     IonSpew(IonSpew_RegAlloc, "Beginning register allocation");
 
     IonSpew(IonSpew_RegAlloc, "Beginning creation of initial data structures");
     if (!createDataStructures())
         return false;
     IonSpew(IonSpew_RegAlloc, "Creation of initial data structures completed");
 
+    if (mir->shouldCancel("LSRA Create Data Structures"))
+        return false;
+
     IonSpew(IonSpew_RegAlloc, "Beginning liveness analysis");
     if (!buildLivenessInfo())
         return false;
     IonSpew(IonSpew_RegAlloc, "Liveness analysis complete");
 
+    if (mir->shouldCancel("LSRA Liveness"))
+        return false;
+
     IonSpew(IonSpew_RegAlloc, "Beginning preliminary register allocation");
     if (!allocateRegisters())
         return false;
     IonSpew(IonSpew_RegAlloc, "Preliminary register allocation complete");
 
+    if (mir->shouldCancel("LSRA Preliminary Regalloc"))
+        return false;
+
     IonSpew(IonSpew_RegAlloc, "Beginning control flow resolution");
     if (!resolveControlFlow())
         return false;
     IonSpew(IonSpew_RegAlloc, "Control flow resolution complete");
 
+    if (mir->shouldCancel("LSRA Control Flow"))
+        return false;
+
     IonSpew(IonSpew_RegAlloc, "Beginning register allocation reification");
     if (!reifyAllocations())
         return false;
     IonSpew(IonSpew_RegAlloc, "Register allocation reification complete");
 
+    if (mir->shouldCancel("LSRA Reification"))
+        return false;
+
     IonSpew(IonSpew_RegAlloc, "Beginning safepoint population.");
     if (!populateSafepoints())
         return false;
     IonSpew(IonSpew_RegAlloc, "Safepoint population complete.");
 
+    if (mir->shouldCancel("LSRA Safepoints"))
+        return false;
+
     IonSpew(IonSpew_RegAlloc, "Register allocation complete");
 
     return true;
 }
 
 void
 LinearScanAllocator::setIntervalRequirement(LiveInterval *interval)
 {
--- a/js/src/ion/LinearScan.h
+++ b/js/src/ion/LinearScan.h
@@ -586,16 +586,17 @@ class LinearScanAllocator
         void enqueueAtHead(LiveInterval *interval);
 
         void assertSorted();
 
         LiveInterval *dequeue();
     };
 
     // Context
+    MIRGenerator *mir;
     LIRGenerator *lir;
     LIRGraph &graph;
 
     // Computed inforamtion
     BitSet **liveIn;
     VirtualRegisterMap vregs;
     InstructionDataMap insData;
     FixedArityList<LiveInterval *, AnyRegister::Total> fixedIntervals;
@@ -680,18 +681,19 @@ class LinearScanAllocator
     CodePosition inputOf(LInstruction *ins) {
         return CodePosition(ins->id(), CodePosition::INPUT);
     }
 #ifdef JS_NUNBOX32
     VirtualRegister *otherHalfOfNunbox(VirtualRegister *vreg);
 #endif
 
   public:
-    LinearScanAllocator(LIRGenerator *lir, LIRGraph &graph)
-      : lir(lir),
+    LinearScanAllocator(MIRGenerator *mir, LIRGenerator *lir, LIRGraph &graph)
+      : mir(mir),
+        lir(lir),
         graph(graph),
         allRegisters_(RegisterSet::All())
     {
         if (FramePointer != InvalidReg && lir->mir()->instrumentedProfiling())
             allRegisters_.take(AnyRegister(FramePointer));
     }
 
     bool go();
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -2118,16 +2118,19 @@ LIRGenerator::precreatePhi(LBlock *block
     return true;
 }
 
 bool
 LIRGenerator::generate()
 {
     // Create all blocks and prep all phis beforehand.
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
+        if (gen->shouldCancel("Lowering (preparation loop)"))
+            return false;
+
         current = LBlock::New(*block);
         if (!current)
             return false;
         if (!lirGraph_.addBlock(current))
             return false;
         block->assignLir(current);
 
         // For each MIR phi, add LIR phis as appropriate. We'll fill in their
@@ -2138,16 +2141,19 @@ LIRGenerator::generate()
             for (int i = 0; i < numPhis; i++) {
                 if (!precreatePhi(block->lir(), *phi))
                     return false;
             }
         }
     }
 
     for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
+        if (gen->shouldCancel("Lowering (main loop)"))
+            return false;
+
         if (!visitBlock(*block))
             return false;
     }
 
     if (graph.osrBlock())
         lirGraph_.setOsrBlock(graph.osrBlock()->lir());
 
     lirGraph_.setArgumentSlotCount(maxargslots_);
--- a/js/src/ion/MIRGenerator.h
+++ b/js/src/ion/MIRGenerator.h
@@ -59,25 +59,34 @@ class MIRGenerator
     bool errored() const {
         return error_;
     }
 
     bool instrumentedProfiling() {
         return compartment->rt->spsProfiler.enabled();
     }
 
+    // Whether the main thread is trying to cancel this build.
+    bool shouldCancel(const char *why) {
+        return cancelBuild_;
+    }
+    void cancel() {
+        cancelBuild_ = 1;
+    }
+
   public:
     JSCompartment *compartment;
 
   protected:
     CompileInfo *info_;
     TempAllocator *temp_;
     JSFunction *fun_;
     uint32 nslots_;
     MIRGraph *graph_;
     bool error_;
+    size_t cancelBuild_;
 };
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_mirgen_h__
 
--- a/js/src/ion/MIRGraph.cpp
+++ b/js/src/ion/MIRGraph.cpp
@@ -17,17 +17,18 @@ using namespace js;
 using namespace js::ion;
 
 MIRGenerator::MIRGenerator(JSCompartment *compartment,
                            TempAllocator *temp, MIRGraph *graph, CompileInfo *info)
   : compartment(compartment),
     info_(info),
     temp_(temp),
     graph_(graph),
-    error_(false)
+    error_(false),
+    cancelBuild_(0)
 { }
 
 bool
 MIRGenerator::abortFmt(const char *message, va_list ap)
 {
     IonSpewVA(IonSpew_Abort, message, ap);
     error_ = true;
     return false;
--- a/js/src/ion/ValueNumbering.cpp
+++ b/js/src/ion/ValueNumbering.cpp
@@ -1,25 +1,27 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=4 sw=4 et tw=99:
  *
  * 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 "Ion.h"
+#include "IonBuilder.h"
 #include "IonSpewer.h"
 #include "CompileInfo.h"
 #include "ValueNumbering.h"
 
 using namespace js;
 using namespace js::ion;
 
-ValueNumberer::ValueNumberer(MIRGraph &graph, bool optimistic)
-  : graph_(graph),
+ValueNumberer::ValueNumberer(MIRGenerator *mir, MIRGraph &graph, bool optimistic)
+  : mir(mir),
+    graph_(graph),
     pessimisticPass_(!optimistic),
     count_(0)
 { }
 
 uint32
 ValueNumberer::lookupValue(MDefinition *ins)
 {
 
@@ -140,16 +142,18 @@ ValueNumberer::computeValueNumbers()
     // any graph with back-edges, but is much faster to perform.
 
     IonSpew(IonSpew_GVN, "Numbering instructions");
 
     if (!values.init())
         return false;
     // Stick a VN object onto every mdefinition
     for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
+        if (mir->shouldCancel("Value Numbering (preparation loop"))
+            return false;
         for (MDefinitionIterator iter(*block); iter; iter++)
             iter->setValueNumberData(new ValueNumberData);
         MControlInstruction *jump = block->lastIns();
         jump->setValueNumberData(new ValueNumberData);
     }
 
     // Assign unique value numbers if pessimistic.
     // It might be productive to do this in the MDefinition constructor or
@@ -184,16 +188,18 @@ ValueNumberer::computeValueNumbers()
                 }
             }
             if (!debugCount)
                 IonSpew(IonSpew_GVN, "\tNone");
             JS_ASSERT(debugCount == count_);
         }
 #endif
         for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) {
+            if (mir->shouldCancel("Value Numbering (main loop)"))
+                return false;
             for (MDefinitionIterator iter(*block); iter; ) {
 
                 if (!isMarked(*iter)) {
                     iter++;
                     continue;
                 }
 
                 JS_ASSERT_IF(!pessimisticPass_, count_ > 0);
@@ -320,16 +326,18 @@ ValueNumberer::eliminateRedundancies()
         if (block->immediateDominator() == block) {
             if (!worklist.append(block))
                 return false;
         }
     }
 
     // Starting from each self-dominating block, traverse the CFG in pre-order.
     while (!worklist.empty()) {
+        if (mir->shouldCancel("Value Numbering (eliminate loop)"))
+            return false;
         MBasicBlock *block = worklist.popCopy();
 
         IonSpew(IonSpew_GVN, "Looking at block %d", block->id());
 
         // Add all immediate dominators to the front of the worklist.
         for (size_t i = 0; i < block->numImmediatelyDominatedBlocks(); i++) {
             if (!worklist.append(block->getImmediatelyDominatedBlock(i)))
                 return false;
--- a/js/src/ion/ValueNumbering.h
+++ b/js/src/ion/ValueNumbering.h
@@ -72,23 +72,24 @@ class ValueNumberer
     void markBlock(MBasicBlock *block);
     void setClass(MDefinition *toSet, MDefinition *representative);
 
   public:
     static MDefinition *findSplit(MDefinition *);
     void breakClass(MDefinition*);
 
   protected:
+    MIRGenerator *mir;
     MIRGraph &graph_;
     ValueMap values;
     bool pessimisticPass_;
     size_t count_;
 
   public:
-    ValueNumberer(MIRGraph &graph, bool optimistic);
+    ValueNumberer(MIRGenerator *mir, MIRGraph &graph, bool optimistic);
     bool analyze();
 };
 
 class ValueNumberData : public TempObject {
 
     friend void ValueNumberer::breakClass(MDefinition*);
     friend MDefinition *ValueNumberer::findSplit(MDefinition*);
     uint32 number;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-787703.js
@@ -0,0 +1,5 @@
+eval(" function x() {}" + Array(241).join(" "));
+for (var i = 0; i < 100; i++) {
+    gczeal(4, 2);
+    String(x);
+}
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2211,16 +2211,22 @@ JS_GetFunctionPrototype(JSContext *cx, J
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForObject(JSContext *cx, JSRawObject obj)
 {
     AssertHeapIsIdle(cx);
     assertSameCompartment(cx, obj);
     return &obj->global();
 }
 
+extern JS_PUBLIC_API(JSBool)
+JS_IsGlobalObject(JSRawObject obj)
+{
+    return obj->isGlobal();
+}
+
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c)
 {
     AssertHeapIsIdleOrIterating(cx);
     assertSameCompartment(cx, c);
     return c->maybeGlobal();
 }
 
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3355,16 +3355,19 @@ JS_GetFunctionPrototype(JSContext *cx, J
  * which |forObj| was created.
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_GetObjectPrototype(JSContext *cx, JSRawObject forObj);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForObject(JSContext *cx, JSRawObject obj);
 
+extern JS_PUBLIC_API(JSBool)
+JS_IsGlobalObject(JSRawObject obj);
+
 /*
  * May return NULL, if |c| never had a global (e.g. the atoms compartment), or
  * if |c|'s global has been collected.
  */
 extern JS_PUBLIC_API(JSObject *)
 JS_GetGlobalForCompartmentOrNull(JSContext *cx, JSCompartment *c);
 
 extern JS_PUBLIC_API(JSObject *)
@@ -4118,21 +4121,19 @@ struct JSClass {
 #define JSCLASS_IS_GLOBAL               (1<<(JSCLASS_HIGH_FLAGS_SHIFT+1))
 #define JSCLASS_INTERNAL_FLAG2          (1<<(JSCLASS_HIGH_FLAGS_SHIFT+2))
 #define JSCLASS_INTERNAL_FLAG3          (1<<(JSCLASS_HIGH_FLAGS_SHIFT+3))
 
 /* Indicate whether the proto or ctor should be frozen. */
 #define JSCLASS_FREEZE_PROTO            (1<<(JSCLASS_HIGH_FLAGS_SHIFT+4))
 #define JSCLASS_FREEZE_CTOR             (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5))
 
-#define JSCLASS_XPCONNECT_GLOBAL        (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6))
-
 /* Reserved for embeddings. */
-#define JSCLASS_USERBIT2                (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7))
-#define JSCLASS_USERBIT3                (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8))
+#define JSCLASS_USERBIT2                (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6))
+#define JSCLASS_USERBIT3                (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7))
 
 /*
  * Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see
  * below.
  */
 
 /* Global flags. */
 #define JSGLOBAL_FLAGS_CLEARED          0x1
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -198,16 +198,17 @@ typedef struct JSStackFrame             
 typedef struct JSScript          JSScript;
 typedef struct JSStructuredCloneCallbacks   JSStructuredCloneCallbacks;
 typedef struct JSStructuredCloneReader      JSStructuredCloneReader;
 typedef struct JSStructuredCloneWriter      JSStructuredCloneWriter;
 typedef struct JSTracer                     JSTracer;
 
 #ifdef __cplusplus
 class                                       JSFlatString;
+class                                       JSStableString;  // long story
 class                                       JSString;
 #else
 typedef struct JSFlatString                 JSFlatString;
 typedef struct JSString                     JSString;
 #endif /* !__cplusplus */
 
 #ifdef JS_THREADSAFE
 typedef struct PRCallOnceType    JSCallOnceType;
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -93,18 +93,22 @@ js::CancelOffThreadIonCompile(JSCompartm
             state.ionWorklist[i--] = state.ionWorklist.back();
             state.ionWorklist.popBack();
         }
     }
 
     /* Wait for in progress entries to finish up. */
     for (size_t i = 0; i < state.numThreads; i++) {
         const WorkerThread &helper = state.threads[i];
-        while (helper.ionScript && CompiledScriptMatches(compartment, script, helper.ionScript))
+        while (helper.ionBuilder &&
+               CompiledScriptMatches(compartment, script, helper.ionBuilder->script()))
+        {
+            helper.ionBuilder->cancel();
             state.wait(WorkerThreadState::MAIN);
+        }
     }
 
     ion::OffThreadCompilationVector &compilations = ion->finishedOffThreadCompilations();
 
     /* Cancel code generation for any completed entries. */
     for (size_t i = 0; i < compilations.length(); i++) {
         ion::IonBuilder *builder = compilations[i];
         if (CompiledScriptMatches(compartment, script, builder->script())) {
@@ -271,42 +275,41 @@ WorkerThread::ThreadMain(void *arg)
 
 void
 WorkerThread::threadLoop()
 {
     WorkerThreadState &state = *runtime->workerThreadState;
     state.lock();
 
     while (true) {
-        JS_ASSERT(!ionScript);
+        JS_ASSERT(!ionBuilder);
 
         while (state.ionWorklist.empty()) {
             if (terminate) {
                 state.unlock();
                 return;
             }
             state.wait(WorkerThreadState::WORKER);
         }
 
-        ion::IonBuilder *builder = state.ionWorklist.popCopy();
-        ionScript = builder->script();
+        ionBuilder = state.ionWorklist.popCopy();
 
-        JS_ASSERT(ionScript->ion == ION_COMPILING_SCRIPT);
+        JS_ASSERT(ionBuilder->script()->ion == ION_COMPILING_SCRIPT);
 
         state.unlock();
 
         {
-            ion::IonContext ictx(NULL, ionScript->compartment(), &builder->temp());
-            builder->backgroundCompiledLir = ion::CompileBackEnd(builder);
+            ion::IonContext ictx(NULL, ionBuilder->script()->compartment(), &ionBuilder->temp());
+            ionBuilder->backgroundCompiledLir = ion::CompileBackEnd(ionBuilder);
         }
 
         state.lock();
 
-        ionScript = NULL;
-        FinishOffThreadIonCompile(builder);
+        FinishOffThreadIonCompile(ionBuilder);
+        ionBuilder = NULL;
 
         /*
          * Notify the main thread in case it is waiting for the compilation to
          * finish.
          */
         state.notify(WorkerThreadState::MAIN);
 
         /*
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -82,18 +82,18 @@ class WorkerThreadState
 struct WorkerThread
 {
     JSRuntime *runtime;
     PRThread *thread;
 
     /* Indicate to an idle thread that it should finish executing. */
     bool terminate;
 
-    /* Any script currently being compiled for Ion on this thread. */
-    JSScript *ionScript;
+    /* Any builder currently being compiled by Ion on this thread. */
+    ion::IonBuilder *ionBuilder;
 
     void destroy();
 
     static void ThreadMain(void *arg);
     void threadLoop();
 };
 
 #endif /* JS_THREADSAFE && JS_ION */
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2466,18 +2466,17 @@ nsXPCComponents_Constructor::CallOrConst
     // get the various other object pointers we need
 
     XPCCallContext ccx(JS_CALLER, cx);
     if (!ccx.IsValid())
         return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
 
     nsXPConnect* xpc = ccx.GetXPConnect();
     XPCContext* xpcc = ccx.GetXPCContext();
-    XPCWrappedNativeScope* scope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, obj);
+    XPCWrappedNativeScope* scope = GetObjectScope(obj);
     nsXPCComponents* comp;
 
     if (!xpc || !xpcc || !scope || !(comp = scope->GetComponents()))
         return ThrowAndFail(NS_ERROR_XPC_UNEXPECTED, cx, _retval);
 
     // Do the security check if necessary
 
     nsIXPCSecurityManager* sm =
@@ -3251,22 +3250,22 @@ xpc_CreateSandboxObject(JSContext *cx, j
 
         sop = new PrincipalHolder(principal);
         if (!sop)
             return NS_ERROR_OUT_OF_MEMORY;
     }
 
     nsIPrincipal *principal = sop->GetPrincipal();
 
-    JSCompartment *compartment;
     JSObject *sandbox;
 
-    rv = xpc::CreateGlobalObject(cx, &SandboxClass, principal,
-                                 options.wantXrays, &sandbox, &compartment);
-    NS_ENSURE_SUCCESS(rv, rv);
+    sandbox = xpc::CreateGlobalObject(cx, &SandboxClass, principal);
+    if (!sandbox)
+        return NS_ERROR_FAILURE;
+    xpc::GetCompartmentPrivate(sandbox)->wantXrays = options.wantXrays;
 
     JS::AutoObjectRooter tvr(cx, sandbox);
 
     {
         JSAutoCompartment ac(cx, sandbox);
 
         if (options.proto) {
             bool ok = JS_WrapObject(cx, &options.proto);
@@ -3303,24 +3302,18 @@ xpc_CreateSandboxObject(JSContext *cx, j
         JS_SetPrivate(sandbox, sop.forget().get());
 
         XPCCallContext ccx(NATIVE_CALLER, cx);
         if (!ccx.IsValid())
             return NS_ERROR_XPC_UNEXPECTED;
 
         {
           JSAutoCompartment ac(ccx, sandbox);
-          XPCWrappedNativeScope* scope =
-              XPCWrappedNativeScope::GetNewOrUsed(ccx, sandbox);
-
-          if (!scope)
-              return NS_ERROR_XPC_UNEXPECTED;
-
           if (options.wantComponents &&
-              !nsXPCComponents::AttachComponentsObject(ccx, scope))
+              !nsXPCComponents::AttachComponentsObject(ccx, GetObjectScope(sandbox)))
               return NS_ERROR_XPC_UNEXPECTED;
 
           if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, sandbox))
               return NS_ERROR_XPC_UNEXPECTED;
         }
 
         if (!JS_DefineFunctions(cx, sandbox, SandboxFunctions))
             return NS_ERROR_XPC_UNEXPECTED;
@@ -4303,20 +4296,17 @@ nsXPCComponents_Utils::RecomputeWrappers
 /* jsval getComponentsForScope(jsval vscope); */
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetComponentsForScope(const jsval &vscope, JSContext *cx,
                                              jsval *rval)
 {
     if (!vscope.isObject())
         return NS_ERROR_INVALID_ARG;
     JSObject *scopeObj = js::UnwrapObject(&vscope.toObject());
-    XPCWrappedNativeScope *scope =
-      XPCWrappedNativeScope::FindInJSObjectScope(cx, scopeObj);
-    if (!scope)
-        return NS_ERROR_FAILURE;
+    XPCWrappedNativeScope *scope = GetObjectScope(scopeObj);
     XPCCallContext ccx(NATIVE_CALLER, cx);
     JSObject *components = scope->GetComponentsJSObject(ccx);
     if (!components)
         return NS_ERROR_FAILURE;
     *rval = ObjectValue(*components);
     if (!JS_WrapValue(cx, rval))
         return NS_ERROR_FAILURE;
     return NS_OK;
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -807,18 +807,17 @@ XPCConvert::NativeInterface2JSObject(XPC
     // (that means an XPCWrappedNative around an nsXPCWrappedJS). This isn't
     // optimal -- we could detect this and roll the functionality into a
     // single wrapper, but the current solution is good enough for now.
     JSContext* cx = lccx.GetJSContext();
     NS_ABORT_IF_FALSE(js::IsObjectInContextCompartment(lccx.GetScopeForNewJSObjects(), cx),
                       "bad scope for new JSObjects");
 
     JSObject *jsscope = lccx.GetScopeForNewJSObjects();
-    XPCWrappedNativeScope* xpcscope =
-        XPCWrappedNativeScope::FindInJSObjectScope(cx, jsscope);
+    XPCWrappedNativeScope* xpcscope = GetObjectScope(jsscope);
     if (!xpcscope)
         return false;
 
     // First, see if this object supports the wrapper cache.
     // Note: If |cache->IsProxy()| is true, then it means that the object
     // implementing it doesn't want a wrapped native as its JS Object, but
     // instead it provides its own proxy object. In that case, the object
     // to use is found as cache->GetWrapper(). If that is null, then the
--- a/js/xpconnect/src/XPCInlines.h
+++ b/js/xpconnect/src/XPCInlines.h
@@ -593,32 +593,16 @@ xpc_ForcePropertyResolve(JSContext* cx, 
 {
     jsval prop;
 
     if (!JS_LookupPropertyById(cx, obj, id, &prop))
         return false;
     return true;
 }
 
-inline JSObject*
-xpc_NewSystemInheritingJSObject(JSContext *cx, JSClass *clasp, JSObject *proto,
-                                bool uniqueType, JSObject *parent)
-{
-    // Global creation should go through XPCWrappedNative::WrapNewGlobal().
-    MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
-
-    JSObject *obj;
-    if (uniqueType) {
-        obj = JS_NewObjectWithUniqueType(cx, clasp, proto, parent);
-    } else {
-        obj = JS_NewObject(cx, clasp, proto, parent);
-    }
-    return obj;
-}
-
 inline jsid
 GetRTIdByIndex(JSContext *cx, unsigned index)
 {
   XPCJSRuntime *rt = nsXPConnect::FastGetXPConnect()->GetRuntime();
   return rt->GetStringID(index);
 }
 
 inline
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -176,22 +176,17 @@ XPCJSContextStack::GetSafeJSContext()
 
     JSObject *glob;
     {
         // scoped JS Request
         JSAutoRequest req(mSafeJSContext);
 
         JS_SetErrorReporter(mSafeJSContext, mozJSLoaderErrorReporter);
 
-        JSCompartment *compartment;
-        nsresult rv = xpc::CreateGlobalObject(mSafeJSContext, &global_class,
-                                              principal, false, &glob,
-                                              &compartment);
-        if (NS_FAILED(rv))
-            glob = nullptr;
+        glob = xpc::CreateGlobalObject(mSafeJSContext, &global_class, principal);
 
         if (glob) {
             // Make sure the context is associated with a proper compartment
             // and not the default compartment.
             JS_SetGlobalObject(mSafeJSContext, glob);
 
             // Note: make sure to set the private before calling
             // InitClasses
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -208,47 +208,48 @@ ContextCallback(JSContext *cx, unsigned 
                 return false;
         } else if (operation == JSCONTEXT_DESTROY) {
             delete XPCContext::GetXPCContext(cx);
         }
     }
     return true;
 }
 
-xpc::CompartmentPrivate::~CompartmentPrivate()
+namespace xpc {
+
+CompartmentPrivate::~CompartmentPrivate()
 {
     MOZ_COUNT_DTOR(xpc::CompartmentPrivate);
 }
 
+CompartmentPrivate*
+EnsureCompartmentPrivate(JSObject *obj)
+{
+    JSCompartment *c = js::GetObjectCompartment(obj);
+    CompartmentPrivate *priv = GetCompartmentPrivate(c);
+    if (priv)
+        return priv;
+    priv = new CompartmentPrivate();
+    JS_SetCompartmentPrivate(c, priv);
+    return priv;
+}
+
+}
+
 static void
 CompartmentDestroyedCallback(JSFreeOp *fop, JSCompartment *compartment)
 {
     XPCJSRuntime* self = nsXPConnect::GetRuntimeInstance();
     if (!self)
         return;
-    XPCCompartmentSet &set = self->GetCompartmentSet();
 
     // Get the current compartment private into an AutoPtr (which will do the
     // cleanup for us), and null out the private (which may already be null).
     nsAutoPtr<CompartmentPrivate> priv(GetCompartmentPrivate(compartment));
     JS_SetCompartmentPrivate(compartment, nullptr);
-
-    // JSD creates compartments in our runtime without going through our creation
-    // code. This means that those compartments aren't in our set, and don't have
-    // compartment privates. JSD is on the way out, so let's just handle that
-    // case for now.
-    if (!priv) {
-        MOZ_ASSERT(!set.has(compartment));
-        return;
-    }
-
-    // Remove the compartment from the set.
-    MOZ_ASSERT(set.has(compartment));
-    set.remove(compartment);
-    return;
 }
 
 nsresult
 XPCJSRuntime::AddJSHolder(void* aHolder, nsScriptObjectTracer* aTracer)
 {
     MOZ_ASSERT(aTracer->Trace, "AddJSHolder needs a non-null Trace function");
     mJSHolders.Put(aHolder, aTracer);
 
@@ -317,24 +318,16 @@ TraceJSObject(void *aScriptThing, const 
 static PLDHashOperator
 TraceJSHolder(void *holder, nsScriptObjectTracer *&tracer, void *arg)
 {
     tracer->Trace(holder, TraceJSObject, arg);
 
     return PL_DHASH_NEXT;
 }
 
-static PLDHashOperator
-TraceDOMExpandos(nsPtrHashKey<JSObject> *expando, void *aClosure)
-{
-    JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando->GetKey(),
-                          "DOM expando object");
-    return PL_DHASH_NEXT;
-}
-
 void XPCJSRuntime::TraceXPConnectRoots(JSTracer *trc)
 {
     JSContext *iter = nullptr;
     while (JSContext *acx = JS_ContextIterator(GetJSRuntime(), &iter)) {
         MOZ_ASSERT(js::HasUnrootedGlobal(acx));
         if (JSObject *global = JS_GetGlobalObject(acx))
             JS_CALL_OBJECT_TRACER(trc, global, "XPC global object");
     }
@@ -345,24 +338,16 @@ void XPCJSRuntime::TraceXPConnectRoots(J
 
     for (XPCRootSetElem *e = mVariantRoots; e ; e = e->GetNextRoot())
         static_cast<XPCTraceableVariant*>(e)->TraceJS(trc);
 
     for (XPCRootSetElem *e = mWrappedJSRoots; e ; e = e->GetNextRoot())
         static_cast<nsXPCWrappedJS*>(e)->TraceJS(trc);
 
     mJSHolders.Enumerate(TraceJSHolder, trc);
-
-    // Trace compartments.
-    XPCCompartmentSet &set = GetCompartmentSet();
-    for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
-        CompartmentPrivate *priv = GetCompartmentPrivate(r.front());
-        if (priv->domExpandoMap)
-            priv->domExpandoMap->EnumerateEntries(TraceDOMExpandos, trc);
-    }
 }
 
 struct Closure
 {
     bool cycleCollectionEnabled;
     nsCycleCollectionTraversalCallback *cb;
 };
 
@@ -408,29 +393,16 @@ XPCJSRuntime::SuspectWrappedNative(XPCWr
 
     // Only record objects that might be part of a cycle as roots, unless
     // the callback wants all traces (a debug feature).
     JSObject* obj = wrapper->GetFlatJSObjectPreserveColor();
     if (xpc_IsGrayGCThing(obj) || cb.WantAllTraces())
         cb.NoteJSRoot(obj);
 }
 
-static PLDHashOperator
-SuspectDOMExpandos(nsPtrHashKey<JSObject> *key, void *arg)
-{
-    Closure *closure = static_cast<Closure*>(arg);
-    JSObject* obj = key->GetKey();
-    const dom::DOMClass* clasp;
-    dom::DOMObjectSlot slot = GetDOMClass(obj, clasp);
-    MOZ_ASSERT(slot != dom::eNonDOMObject && clasp->mDOMObjectIsISupports);
-    nsISupports* native = dom::UnwrapDOMObject<nsISupports>(obj, slot);
-    closure->cb->NoteXPCOMRoot(native);
-    return PL_DHASH_NEXT;
-}
-
 bool
 CanSkipWrappedJS(nsXPCWrappedJS *wrappedJS)
 {
     JSObject *obj = wrappedJS->GetJSObjectPreserveColor();
     // If traversing wrappedJS wouldn't release it, nor
     // cause any other objects to be added to the graph, no
     // need to add it to the graph at all.
     if (nsCCUncollectableMarker::sGeneration &&
@@ -492,24 +464,16 @@ XPCJSRuntime::AddXPConnectRoots(nsCycleC
             continue;
         }
 
         cb.NoteXPCOMRoot(static_cast<nsIXPConnectWrappedJS *>(wrappedJS));
     }
 
     Closure closure = { true, &cb };
     mJSHolders.Enumerate(NoteJSHolder, &closure);
-
-    // Suspect objects with expando objects.
-    XPCCompartmentSet &set = GetCompartmentSet();
-    for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
-        CompartmentPrivate *priv = GetCompartmentPrivate(r.front());
-        if (priv->domExpandoMap)
-            priv->domExpandoMap->EnumerateEntries(SuspectDOMExpandos, &closure);
-    }
 }
 
 static PLDHashOperator
 UnmarkJSHolder(void *holder, nsScriptObjectTracer *&tracer, void *arg)
 {
     tracer->CanSkip(holder, true);
     return PL_DHASH_NEXT;
 }
@@ -793,24 +757,16 @@ XPCJSRuntime::FinalizeCallback(JSFreeOp 
             // We add them to the array now and Release the array members
             // later to avoid the posibility of doing any JS GCThing
             // allocations during the gc cycle.
             self->mWrappedJSMap->FindDyingJSObjects(dyingWrappedJSArray);
 
             // Find dying scopes.
             XPCWrappedNativeScope::StartFinalizationPhaseOfGC(fop, self);
 
-            // Sweep compartments.
-            XPCCompartmentSet &set = self->GetCompartmentSet();
-            for (XPCCompartmentRange r = set.all(); !r.empty(); r.popFront()) {
-                CompartmentPrivate *priv = GetCompartmentPrivate(r.front());
-                if (priv->waiverWrapperMap)
-                    priv->waiverWrapperMap->Sweep();
-            }
-
             self->mDoingFinalization = true;
             break;
         }
         case JSFINALIZE_END:
         {
             NS_ASSERTION(self->mDoingFinalization, "bad state");
             self->mDoingFinalization = false;
 
@@ -2455,18 +2411,16 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
 
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
     NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
     NS_RegisterMemoryMultiReporter(new JSCompartmentsMultiReporter);
 
     mJSHolders.Init(512);
 
-    mCompartmentSet.init();
-
     // Install a JavaScript 'debugger' keyword handler in debug builds only
 #ifdef DEBUG
     if (!JS_GetGlobalDebugHooks(mJSRuntime)->debuggerHandler)
         xpc_InstallJSDebuggerKeywordHandler(mJSRuntime);
 #endif
 
     mWatchdogLock = PR_NewLock();
     if (!mWatchdogLock)
@@ -2500,17 +2454,16 @@ XPCJSRuntime::newXPCJSRuntime(nsXPConnec
         self->GetWrappedJSClassMap()            &&
         self->GetIID2NativeInterfaceMap()       &&
         self->GetClassInfo2NativeSetMap()       &&
         self->GetNativeSetMap()                 &&
         self->GetThisTranslatorMap()            &&
         self->GetNativeScriptableSharedMap()    &&
         self->GetDyingWrappedNativeProtoMap()   &&
         self->GetMapLock()                      &&
-        self->GetCompartmentSet().initialized() &&
         self->mWatchdogThread) {
         return self;
     }
 
     NS_RUNTIMEABORT("new XPCJSRuntime failed to initialize.");
 
     delete self;
     return nullptr;
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -12,16 +12,17 @@
 #include "nsWrapperCache.h"
 #include "XPCWrapper.h"
 #include "AccessCheck.h"
 #include "nsJSUtils.h"
 #include "mozilla/Attributes.h"
 
 #include "jsapi.h"
 
+using namespace xpc;
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
 
 // the value of this variable is never used - we use its address as a sentinel
 static uint32_t zero_methods_descriptor;
 
 bool AutoScriptEvaluate::StartEvaluating(JSObject *scope, JSErrorReporter errorReporter)
 {
     NS_PRECONDITION(!mEvaluated, "AutoScriptEvaluate::Evaluate should only be called once");
@@ -501,18 +502,17 @@ GetContextFromObject(JSObject *obj)
         return nullptr;
 
     // In order to get a context, we need a context.
     XPCCallContext ccx(NATIVE_CALLER);
     if (!ccx.IsValid())
         return nullptr;
 
     JSAutoCompartment ac(ccx, obj);
-    XPCWrappedNativeScope* scope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, obj);
+    XPCWrappedNativeScope* scope = GetObjectScope(obj);
     XPCContext *xpcc = scope->GetContext();
 
     if (xpcc) {
         JSContext *cx = xpcc->GetJSContext();
         JS_AbortIfWrongThread(JS_GetRuntime(cx));
         return cx;
     }
 
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -307,42 +307,34 @@ XPCWrappedNative::WrapNewGlobal(XPCCallC
         si(ccx, XPCNativeScriptableInfo::Construct(ccx, &sciWrapper));
     MOZ_ASSERT(si.get());
 
     // Finally, we get to the JSClass.
     JSClass *clasp = si->GetJSClass();
     MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
 
     // Create the global.
-    JSObject *global;
-    JSCompartment *compartment;
-    nsresult rv = xpc::CreateGlobalObject(ccx, clasp, principal, false, &global,
-                                          &compartment);
-    NS_ENSURE_SUCCESS(rv, rv);
+    JSObject *global = xpc::CreateGlobalObject(ccx, clasp, principal);
+    if (!global)
+        return NS_ERROR_FAILURE;
+    XPCWrappedNativeScope *scope = GetCompartmentPrivate(global)->scope;
 
     // Immediately enter the global's compartment, so that everything else we
     // create ends up there.
     JSAutoCompartment ac(ccx, global);
 
-    // If requested, immediately initialize the standard classes on the global.
-    // We need to do this before creating a scope, because
-    // XPCWrappedNativeScope::SetGlobal resolves |Object| via
-    // JS_ResolveStandardClass. JS_InitStandardClasses asserts if any of the
-    // standard classes are already initialized, so this is a problem.
+    // If requested, initialize the standard classes on the global.
     if (initStandardClasses && ! JS_InitStandardClasses(ccx, global))
         return NS_ERROR_FAILURE;
 
-    // Create a scope, but don't do any extra stuff like initializing |Components|.
-    // All of that stuff happens in the caller.
-    XPCWrappedNativeScope *scope = XPCWrappedNativeScope::GetNewOrUsed(ccx, global, identity);
-    MOZ_ASSERT(scope);
-
     // Make a proto.
     XPCWrappedNativeProto *proto =
-        XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, nativeHelper.GetClassInfo(), &sciProto,
+        XPCWrappedNativeProto::GetNewOrUsed(ccx,
+                                            scope,
+                                            nativeHelper.GetClassInfo(), &sciProto,
                                             UNKNOWN_OFFSETS, /* callPostCreatePrototype = */ false);
     if (!proto)
         return NS_ERROR_FAILURE;
     proto->CacheOffsets(identity);
 
     // Set up the prototype on the global.
     MOZ_ASSERT(proto->GetJSProtoObject());
     bool success = JS_SplicePrototype(ccx, global, proto->GetJSProtoObject());
@@ -528,18 +520,17 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
         rv = NS_OK;
 
         NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(parent),
                      "Xray wrapper being used to parent XPCWrappedNative?");
 
         ac.construct(ccx, parent);
 
         if (parent != plannedParent) {
-            XPCWrappedNativeScope* betterScope =
-                XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
+            XPCWrappedNativeScope* betterScope = GetObjectScope(parent);
             if (betterScope != Scope)
                 return GetNewOrUsed(ccx, 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
@@ -1141,17 +1132,17 @@ XPCWrappedNative::Init(XPCCallContext& c
     JSObject* protoJSObject = HasProto() ?
                                 GetProto()->GetJSProtoObject() :
                                 GetScope()->GetPrototypeNoHelper(ccx);
 
     if (!protoJSObject) {
         return false;
     }
 
-    mFlatJSObject = xpc_NewSystemInheritingJSObject(ccx, jsclazz, protoJSObject, false, parent);
+    mFlatJSObject = JS_NewObject(ccx, jsclazz, protoJSObject, parent);
     if (!mFlatJSObject)
         return false;
 
     JS_SetPrivate(mFlatJSObject, this);
 
     return FinishInit(ccx);
 }
 
@@ -1791,21 +1782,18 @@ XPCWrappedNative::RescueOrphans(XPCCallC
     // been orphaned. If not, we have nothing to do.
     if (!IsOrphan())
         return NS_OK;
 
     // We've been orphaned. Find where our parent went, and follow it.
     JSObject *parentGhost = js::GetObjectParent(mFlatJSObject);
     JSObject *realParent = js::UnwrapObject(parentGhost);
     nsRefPtr<XPCWrappedNative> ignored;
-    return ReparentWrapperIfFound(ccx,
-                                  XPCWrappedNativeScope::
-                                    FindInJSObjectScope(ccx, parentGhost),
-                                  XPCWrappedNativeScope::
-                                    FindInJSObjectScope(ccx, realParent),
+    return ReparentWrapperIfFound(ccx, GetObjectScope(parentGhost),
+                                  GetObjectScope(realParent),
                                   realParent, mIdentity, getter_AddRefs(ignored));
 }
 
 #define IS_TEAROFF_CLASS(clazz)                                               \
           ((clazz) == &XPC_WN_Tearoff_JSClass)
 
 // static
 XPCWrappedNative*
@@ -2212,21 +2200,19 @@ XPCWrappedNative::InitTearOff(XPCCallCon
 }
 
 JSBool
 XPCWrappedNative::InitTearOffJSObject(XPCCallContext& ccx,
                                       XPCWrappedNativeTearOff* to)
 {
     // This is only called while locked (during XPCWrappedNative::FindTearOff).
 
-    JSObject* obj =
-        xpc_NewSystemInheritingJSObject(ccx, Jsvalify(&XPC_WN_Tearoff_JSClass),
-                                        GetScope()->GetPrototypeJSObject(),
-                                        false, mFlatJSObject);
-
+    JSObject* obj = JS_NewObject(ccx, Jsvalify(&XPC_WN_Tearoff_JSClass),
+                                 JS_GetObjectPrototype(ccx, mFlatJSObject),
+                                 mFlatJSObject);
     if (!obj)
         return false;
 
     JS_SetPrivate(obj, to);
     to->SetJSObject(obj);
     return true;
 }
 
@@ -3821,18 +3807,17 @@ ConstructSlimWrapper(XPCCallContext &ccx
         SLIM_LOG_NOT_CREATED(ccx, identityObj, "wrong compartment");
 
         return false;
     }
 
     JSAutoCompartment ac(ccx, parent);
 
     if (parent != plannedParent) {
-        XPCWrappedNativeScope *newXpcScope =
-            XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
+        XPCWrappedNativeScope *newXpcScope = GetObjectScope(parent);
         if (newXpcScope != xpcScope) {
             SLIM_LOG_NOT_CREATED(ccx, identityObj, "crossing origins");
 
             return false;
         }
     }
 
     // The PreCreate hook could have forced the creation of a wrapper, need
@@ -3857,19 +3842,17 @@ ConstructSlimWrapper(XPCCallContext &ccx
 
     xpcproto->CacheOffsets(identityObj);
 
     XPCNativeScriptableInfo* si = xpcproto->GetScriptableInfo();
     JSClass* jsclazz = si->GetSlimJSClass();
     if (!jsclazz)
         return false;
 
-    wrapper = xpc_NewSystemInheritingJSObject(ccx, jsclazz,
-                                              xpcproto->GetJSProtoObject(),
-                                              false, parent);
+    wrapper = JS_NewObject(ccx, jsclazz, xpcproto->GetJSProtoObject(), parent);
     if (!wrapper)
         return false;
 
     JS_SetPrivate(wrapper, identityObj);
     SetSlimWrapperProto(wrapper, xpcproto.get());
 
     // Transfer ownership to the wrapper's private.
     aHelper.forgetCanonical();
--- a/js/xpconnect/src/XPCWrappedNativeProto.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp
@@ -85,20 +85,19 @@ XPCWrappedNativeProto::Init(XPCCallConte
                 &XPC_WN_NoMods_NoCall_Proto_JSClass;
         }
     } else {
         jsclazz = &XPC_WN_NoMods_NoCall_Proto_JSClass;
     }
 
     JSObject *parent = mScope->GetGlobalJSObject();
 
-    mJSProtoObject =
-        xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(jsclazz),
-                                        mScope->GetPrototypeJSObject(),
-                                        true, parent);
+    mJSProtoObject = JS_NewObjectWithUniqueType(ccx, js::Jsvalify(jsclazz),
+                                                JS_GetObjectPrototype(ccx, parent),
+                                                parent);
 
     bool success = !!mJSProtoObject;
     if (success) {
         JS_SetPrivate(mJSProtoObject, this);
         if (callPostCreatePrototype)
             success = CallPostCreatePrototype(ccx);
     }
 
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -7,16 +7,17 @@
 
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "jsproxy.h"
 
 #include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
+using namespace xpc;
 
 /***************************************************************************/
 
 #ifdef XPC_TRACK_SCOPE_STATS
 static int DEBUG_TotalScopeCount;
 static int DEBUG_TotalLiveScopeCount;
 static int DEBUG_TotalMaxScopeCount;
 static int DEBUG_TotalScopeTraversalCount;
@@ -76,74 +77,68 @@ static void DEBUG_TrackScopeShutdown()
 
 /***************************************************************************/
 
 XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr;
 XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
 
 // static
 XPCWrappedNativeScope*
-XPCWrappedNativeScope::GetNewOrUsed(XPCCallContext& ccx, JSObject* aGlobal, nsISupports* aNative)
+XPCWrappedNativeScope::GetNewOrUsed(JSContext *cx, JSObject* aGlobal)
 {
-
-    XPCWrappedNativeScope* scope = FindInJSObjectScope(ccx, aGlobal, true);
-    if (!scope)
-        scope = new XPCWrappedNativeScope(ccx, aGlobal, aNative);
-    else {
-        // We need to call SetGlobal in order to refresh our cached
-        // mPrototypeJSObject and to clear mPrototypeNoHelper (so we get a new
-        // new one if requested in the new scope) in the case where the global
-        // object is being reused (JS_SetAllNonReservedSlotsToUndefined has
-        // been called).  NOTE: We are only called by nsXPConnect::InitClasses.
-        scope->SetGlobal(ccx, aGlobal, aNative);
+    XPCWrappedNativeScope* scope = GetObjectScope(aGlobal);
+    if (!scope) {
+        scope = new XPCWrappedNativeScope(cx, aGlobal);
+    } else {
+        // We need to call SetGlobal in order to clear mPrototypeNoHelper (so we
+        // get a new new one if requested in the new scope) in the case where
+        // the global object is being reused (JS_SetAllNonReservedSlotsToUndefined
+        // has been called). NOTE: We are only called by nsXPConnect::InitClasses.
+        scope->SetGlobal(cx, aGlobal);
     }
-    if (js::GetObjectClass(aGlobal)->flags & JSCLASS_XPCONNECT_GLOBAL)
-        JS_SetReservedSlot(aGlobal,
-                           JSCLASS_GLOBAL_SLOT_COUNT,
-                           PRIVATE_TO_JSVAL(scope));
     return scope;
 }
 
-XPCWrappedNativeScope::XPCWrappedNativeScope(XPCCallContext& ccx,
-                                             JSObject* aGlobal,
-                                             nsISupports* aNative)
-    :   mRuntime(ccx.GetRuntime()),
-        mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)),
+XPCWrappedNativeScope::XPCWrappedNativeScope(JSContext *cx,
+                                             JSObject* aGlobal)
+      : mWrappedNativeMap(Native2WrappedNativeMap::newMap(XPC_NATIVE_MAP_SIZE)),
         mWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)),
         mMainThreadWrappedNativeProtoMap(ClassInfo2WrappedNativeProtoMap::newMap(XPC_NATIVE_PROTO_MAP_SIZE)),
         mComponents(nullptr),
         mNext(nullptr),
         mGlobalJSObject(nullptr),
-        mPrototypeJSObject(nullptr),
         mPrototypeNoHelper(nullptr),
-        mScriptObjectPrincipal(nullptr),
-        mExperimentalBindingsEnabled(ccx.GetRuntime()->ExperimentalBindingsEnabled())
+        mExperimentalBindingsEnabled(XPCJSRuntime::Get()->ExperimentalBindingsEnabled())
 {
     // add ourselves to the scopes list
     {   // scoped lock
-        XPCAutoLock lock(mRuntime->GetMapLock());
+        XPCAutoLock lock(XPCJSRuntime::Get()->GetMapLock());
 
 #ifdef DEBUG
         for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext)
             MOZ_ASSERT(aGlobal != cur->GetGlobalJSObjectPreserveColor(), "dup object");
 #endif
 
         mNext = gScopes;
         gScopes = this;
 
         // Grab the XPCContext associated with our context.
-        mContext = XPCContext::GetXPCContext(ccx.GetJSContext());
+        mContext = XPCContext::GetXPCContext(cx);
         mContext->AddScope(this);
     }
 
     if (aGlobal)
-        SetGlobal(ccx, aGlobal, aNative);
+        SetGlobal(cx, aGlobal);
 
     DEBUG_TrackNewScope(this);
     MOZ_COUNT_CTOR(XPCWrappedNativeScope);
+
+    // Attach ourselves to the compartment private.
+    CompartmentPrivate *priv = EnsureCompartmentPrivate(aGlobal);
+    priv->scope = this;
 }
 
 // static
 JSBool
 XPCWrappedNativeScope::IsDyingScope(XPCWrappedNativeScope *scope)
 {
     for (XPCWrappedNativeScope *cur = gDyingScopes; cur; cur = cur->mNext) {
         if (scope == cur)
@@ -209,59 +204,21 @@ js::Class XPC_WN_NoHelper_Proto_JSClass 
     nullptr,                         // trace;
 
     JS_NULL_CLASS_EXT,
     XPC_WN_NoCall_ObjectOps
 };
 
 
 void
-XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal,
-                                 nsISupports* aNative)
+XPCWrappedNativeScope::SetGlobal(JSContext *cx, JSObject* aGlobal)
 {
     // We allow for calling this more than once. This feature is used by
     // nsXPConnect::InitClassesWithNewWrappedGlobal.
-
     mGlobalJSObject = aGlobal;
-    mScriptObjectPrincipal = nullptr;
-
-    // Try to find the native global object. If we didn't receive it explicitly,
-    // we might be able to find it in the private slot.
-    nsISupports *native;
-    if (aNative) {
-        native = aNative;
-    } else {
-        const JSClass *jsClass = js::GetObjectJSClass(aGlobal);
-        if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
-                                 JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
-            // Our global has an nsISupports native pointer.  Let's
-            // see whether it's what we want.
-            nsISupports *priv =
-                static_cast<nsISupports*>(xpc_GetJSPrivate(aGlobal));
-            nsCOMPtr<nsIXPConnectWrappedNative> wn = do_QueryInterface(priv);
-            if (wn)
-                native = static_cast<XPCWrappedNative*>(wn.get())->GetIdentityObject();
-            else
-                native = nullptr;
-        } else if (!mozilla::dom::UnwrapDOMObjectToISupports(aGlobal, native)) {
-            native = nullptr;
-        }
-    }
-
-    // Now init our script object principal, if the new global has one.
-    nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(native);
-    mScriptObjectPrincipal = sop;
-
-    // Lookup 'globalObject.Object.prototype' for our wrapper's proto
-    JSObject *objectPrototype =
-        JS_GetObjectPrototype(ccx.GetJSContext(), aGlobal);
-    if (objectPrototype)
-        mPrototypeJSObject = objectPrototype;
-    else
-        NS_ERROR("Can't get globalObject.Object.prototype");
 
     // Clear the no helper wrapper prototype object so that a new one
     // gets created if needed.
     mPrototypeNoHelper = nullptr;
 }
 
 XPCWrappedNativeScope::~XPCWrappedNativeScope()
 {
@@ -292,33 +249,30 @@ XPCWrappedNativeScope::~XPCWrappedNative
     // with the scope but just in case.
     if (mComponents)
         mComponents->mScope = nullptr;
 
     // XXX we should assert that we are dead or that xpconnect has shutdown
     // XXX might not want to do this at xpconnect shutdown time???
     mComponents = nullptr;
 
-    JSRuntime *rt = mRuntime->GetJSRuntime();
+    JSRuntime *rt = XPCJSRuntime::Get()->GetJSRuntime();
     mGlobalJSObject.finalize(rt);
-    mPrototypeJSObject.finalize(rt);
 }
 
 JSObject *
 XPCWrappedNativeScope::GetPrototypeNoHelper(XPCCallContext& ccx)
 {
     // We could create this prototype in SetGlobal(), but all scopes
     // don't need one, so we save ourselves a bit of space if we
     // create these when they're needed.
     if (!mPrototypeNoHelper) {
-        mPrototypeNoHelper =
-            xpc_NewSystemInheritingJSObject(ccx,
-                                            js::Jsvalify(&XPC_WN_NoHelper_Proto_JSClass),
-                                            mPrototypeJSObject,
-                                            false, mGlobalJSObject);
+        mPrototypeNoHelper = JS_NewObject(ccx, js::Jsvalify(&XPC_WN_NoHelper_Proto_JSClass),
+                                          JS_GetObjectPrototype(ccx, mGlobalJSObject),
+                                          mGlobalJSObject);
 
         NS_ASSERTION(mPrototypeNoHelper,
                      "Failed to create prototype for wrappers w/o a helper");
     } else {
         xpc_UnmarkGrayObject(mPrototypeNoHelper);
     }
 
     return mPrototypeNoHelper;
@@ -330,27 +284,38 @@ WrappedNativeJSGCThingTracer(JSDHashTabl
 {
     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
     if (wrapper->HasExternalReference() && !wrapper->IsWrapperExpired())
         wrapper->TraceSelf((JSTracer *)arg);
 
     return JS_DHASH_NEXT;
 }
 
+static PLDHashOperator
+TraceDOMExpandos(nsPtrHashKey<JSObject> *expando, void *aClosure)
+{
+    JS_CALL_OBJECT_TRACER(static_cast<JSTracer *>(aClosure), expando->GetKey(),
+                          "DOM expando object");
+    return PL_DHASH_NEXT;
+}
+
 // static
 void
 XPCWrappedNativeScope::TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt)
 {
     // FIXME The lock may not be necessary during tracing as that serializes
     // access to JS runtime. See bug 380139.
     XPCAutoLock lock(rt->GetMapLock());
 
-    // Do JS_CallTracer for all wrapped natives with external references.
+    // Do JS_CallTracer for all wrapped natives with external references, as
+    // well as any DOM expando objects.
     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
         cur->mWrappedNativeMap->Enumerate(WrappedNativeJSGCThingTracer, trc);
+        if (cur->mDOMExpandoMap)
+            cur->mDOMExpandoMap->EnumerateEntries(TraceDOMExpandos, trc);
     }
 }
 
 static JSDHashOperator
 WrappedNativeSuspecter(JSDHashTable *table, JSDHashEntryHdr *hdr,
                        uint32_t number, void *arg)
 {
     XPCWrappedNative* wrapper = ((Native2WrappedNativeMap::Entry*)hdr)->value;
@@ -359,25 +324,41 @@ WrappedNativeSuspecter(JSDHashTable *tab
         nsCycleCollectionTraversalCallback *cb =
             static_cast<nsCycleCollectionTraversalCallback *>(arg);
         XPCJSRuntime::SuspectWrappedNative(wrapper, *cb);
     }
 
     return JS_DHASH_NEXT;
 }
 
+static PLDHashOperator
+SuspectDOMExpandos(nsPtrHashKey<JSObject> *key, void *arg)
+{
+    nsCycleCollectionTraversalCallback *cb =
+      static_cast<nsCycleCollectionTraversalCallback *>(arg);
+    JSObject* obj = key->GetKey();
+    const dom::DOMClass* clasp;
+    dom::DOMObjectSlot slot = GetDOMClass(obj, clasp);
+    MOZ_ASSERT(slot != dom::eNonDOMObject && clasp->mDOMObjectIsISupports);
+    nsISupports* native = dom::UnwrapDOMObject<nsISupports>(obj, slot);
+    cb->NoteXPCOMRoot(native);
+    return PL_DHASH_NEXT;
+}
+
 // static
 void
 XPCWrappedNativeScope::SuspectAllWrappers(XPCJSRuntime* rt,
                                           nsCycleCollectionTraversalCallback& cb)
 {
     XPCAutoLock lock(rt->GetMapLock());
 
     for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
         cur->mWrappedNativeMap->Enumerate(WrappedNativeSuspecter, &cb);
+        if (cur->mDOMExpandoMap)
+            cur->mDOMExpandoMap->EnumerateEntries(SuspectDOMExpandos, &cb);
     }
 }
 
 // static
 void
 XPCWrappedNativeScope::StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt)
 {
     // FIXME The lock may not be necessary since we are inside JSGC_MARK_END
@@ -389,37 +370,36 @@ XPCWrappedNativeScope::StartFinalization
     // KillDyingScopes.
     NS_ASSERTION(gDyingScopes == nullptr,
                  "JSGC_MARK_END without JSGC_FINALIZE_END");
 
     XPCWrappedNativeScope* prev = nullptr;
     XPCWrappedNativeScope* cur = gScopes;
 
     while (cur) {
+        // Sweep waivers.
+        if (cur->mWaiverWrapperMap)
+            cur->mWaiverWrapperMap->Sweep();
+
         XPCWrappedNativeScope* next = cur->mNext;
 
         if (cur->mGlobalJSObject &&
             JS_IsAboutToBeFinalized(cur->mGlobalJSObject)) {
             cur->mGlobalJSObject.finalize(fop->runtime());
-            cur->mScriptObjectPrincipal = nullptr;
             if (cur->GetCachedDOMPrototypes().IsInitialized())
                  cur->GetCachedDOMPrototypes().Clear();
             // Move this scope from the live list to the dying list.
             if (prev)
                 prev->mNext = next;
             else
                 gScopes = next;
             cur->mNext = gDyingScopes;
             gDyingScopes = cur;
             cur = nullptr;
         } else {
-            if (cur->mPrototypeJSObject &&
-                JS_IsAboutToBeFinalized(cur->mPrototypeJSObject)) {
-                cur->mPrototypeJSObject.finalize(fop->runtime());
-            }
             if (cur->mPrototypeNoHelper &&
                 JS_IsAboutToBeFinalized(cur->mPrototypeNoHelper)) {
                 cur->mPrototypeNoHelper = nullptr;
             }
         }
         if (cur)
             prev = cur;
         cur = next;
@@ -602,28 +582,16 @@ XPCWrappedNativeScope::SystemIsBeingShut
         // Walk the protos first. Wrapper shutdown can leave dangling
         // proto pointers in the proto map.
         cur->mWrappedNativeProtoMap->
                 Enumerate(WrappedNativeProtoShutdownEnumerator,  &data);
         cur->mMainThreadWrappedNativeProtoMap->
                 Enumerate(WrappedNativeProtoShutdownEnumerator,  &data);
         cur->mWrappedNativeMap->
                 Enumerate(WrappedNativeShutdownEnumerator,  &data);
-
-        // Since we're not gating the scope destruction on the finalization
-        // of the JS global in this case, it might stick around. And if it
-        // gets later on (or otherwise triggers an access to the scope), we'll
-        // crash. Null it out.
-        JSObject *global = cur->mGlobalJSObject;
-        if (global &&
-            js::GetObjectClass(global)->flags & JSCLASS_XPCONNECT_GLOBAL)
-        {
-            JS_SetReservedSlot(global, JSCLASS_GLOBAL_SLOT_COUNT,
-                               PRIVATE_TO_JSVAL(nullptr));
-        }
     }
 
     // Now it is safe to kill all the scopes.
     KillDyingScopes();
 
 #ifdef XPC_DUMP_AT_SHUTDOWN
     if (data.wrapperCount)
         printf("deleting nsXPConnect  with %d live XPCWrappedNatives\n",
@@ -635,106 +603,16 @@ XPCWrappedNativeScope::SystemIsBeingShut
         printf("deleting nsXPConnect  with %d live XPCWrappedNativeScopes\n",
                liveScopeCount);
 #endif
 }
 
 
 /***************************************************************************/
 
-static
-XPCWrappedNativeScope*
-GetScopeOfObject(JSObject* obj)
-{
-    nsISupports* supports;
-    js::Class* clazz = js::GetObjectClass(obj);
-    JSBool isWrapper = IS_WRAPPER_CLASS(clazz);
-
-    if (isWrapper && IS_SLIM_WRAPPER_OBJECT(obj))
-        return GetSlimWrapperProto(obj)->GetScope();
-
-    if (!isWrapper || !(supports = (nsISupports*) xpc_GetJSPrivate(obj)))
-        return nullptr;
-
-#ifdef DEBUG
-    {
-        nsCOMPtr<nsIXPConnectWrappedNative> iface = do_QueryInterface(supports);
-
-        NS_ASSERTION(iface, "Uh, how'd this happen?");
-    }
-#endif
-
-    // obj is one of our nsXPConnectWrappedNative objects.
-    return ((XPCWrappedNative*)supports)->GetScope();
-}
-
-// static
-XPCWrappedNativeScope*
-XPCWrappedNativeScope::FindInJSObjectScope(JSContext* cx, JSObject* obj,
-                                           JSBool OKIfNotInitialized,
-                                           XPCJSRuntime* runtime)
-{
-    XPCWrappedNativeScope* scope;
-
-    if (!obj)
-        return nullptr;
-
-    // If this object is itself a wrapped native then we can get the
-    // scope directly.
-
-    scope = GetScopeOfObject(obj);
-    if (scope)
-        return scope;
-
-    // Else we'll have to look up the parent chain to get the scope
-
-    JSAutoCompartment ac(cx, obj);
-    obj = JS_GetGlobalForObject(cx, obj);
-
-    if (js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL) {
-        scope = XPCWrappedNativeScope::GetNativeScope(obj);
-        if (scope)
-            return scope;
-    }
-
-    if (!runtime) {
-        runtime = nsXPConnect::GetRuntimeInstance();
-        NS_ASSERTION(runtime, "This should never be null!");
-    }
-
-    // XXX We are assuming that the scope count is low enough that traversing
-    // the linked list is more reasonable then doing a hashtable lookup.
-    XPCWrappedNativeScope* found = nullptr;
-    {   // scoped lock
-        XPCAutoLock lock(runtime->GetMapLock());
-
-        DEBUG_TrackScopeTraversal();
-
-        for (XPCWrappedNativeScope* cur = gScopes; cur; cur = cur->mNext) {
-            if (obj == cur->GetGlobalJSObjectPreserveColor()) {
-                found = cur;
-                break;
-            }
-        }
-    }
-
-    if (found) {
-        // This cannot be called within the map lock!
-        return found;
-    }
-
-    // Failure to find the scope is only OK if the caller told us it might fail.
-    // This flag would only be set in the call from
-    // XPCWrappedNativeScope::GetNewOrUsed
-    NS_ASSERTION(OKIfNotInitialized, "No scope has this global object!");
-    return nullptr;
-}
-
-/***************************************************************************/
-
 static JSDHashOperator
 WNProtoSecPolicyClearer(JSDHashTable *table, JSDHashEntryHdr *hdr,
                         uint32_t number, void *arg)
 {
     XPCWrappedNativeProto* proto =
         ((ClassInfo2WrappedNativeProtoMap::Entry*)hdr)->value;
     *(proto->GetSecurityInfoAddr()) = nullptr;
     return JS_DHASH_NEXT;
@@ -769,17 +647,17 @@ WNProtoRemover(JSDHashTable *table, JSDH
     detachedMap->Add(proto);
 
     return JS_DHASH_REMOVE;
 }
 
 void
 XPCWrappedNativeScope::RemoveWrappedNativeProtos()
 {
-    XPCAutoLock al(mRuntime->GetMapLock());
+    XPCAutoLock al(XPCJSRuntime::Get()->GetMapLock());
 
     mWrappedNativeProtoMap->Enumerate(WNProtoRemover,
                                       GetRuntime()->GetDetachedWrappedNativeProtoMap());
     mMainThreadWrappedNativeProtoMap->Enumerate(WNProtoRemover,
                                                 GetRuntime()->GetDetachedWrappedNativeProtoMap());
 }
 
 static PLDHashOperator
@@ -842,21 +720,19 @@ WrappedNativeProtoMapDumpEnumerator(JSDH
 
 void
 XPCWrappedNativeScope::DebugDump(int16_t depth)
 {
 #ifdef DEBUG
     depth-- ;
     XPC_LOG_ALWAYS(("XPCWrappedNativeScope @ %x", this));
     XPC_LOG_INDENT();
-        XPC_LOG_ALWAYS(("mRuntime @ %x", mRuntime));
         XPC_LOG_ALWAYS(("mNext @ %x", mNext));
         XPC_LOG_ALWAYS(("mComponents @ %x", mComponents.get()));
         XPC_LOG_ALWAYS(("mGlobalJSObject @ %x", mGlobalJSObject.get()));
-        XPC_LOG_ALWAYS(("mPrototypeJSObject @ %x", mPrototypeJSObject.get()));
         XPC_LOG_ALWAYS(("mPrototypeNoHelper @ %x", mPrototypeNoHelper));
 
         XPC_LOG_ALWAYS(("mWrappedNativeMap @ %x with %d wrappers(s)",         \
                         mWrappedNativeMap,                                    \
                         mWrappedNativeMap ? mWrappedNativeMap->Count() : 0));
         // iterate contexts...
         if (depth && mWrappedNativeMap && mWrappedNativeMap->Count()) {
             XPC_LOG_INDENT();
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -995,39 +995,16 @@ nsXPConnect::InitClasses(JSContext * aJS
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, aGlobalJSObj))
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     return NS_OK;
 }
 
-static bool
-CreateNewGlobal(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
-                xpc::CompartmentPrivate *priv, JSObject **global,
-                JSCompartment **compartment)
-{
-    // We take ownership of |priv|. Ensure that either we free it in the case
-    // of failure or give ownership to the compartment in case of success (in
-    // that case it will be free'd in CompartmentCallback during GC).
-    MOZ_ASSERT(priv);
-    nsAutoPtr<xpc::CompartmentPrivate> priv_holder(priv);
-    JSObject *tempGlobal =
-        JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal));
-
-    if (!tempGlobal)
-        return false;
-
-    *global = tempGlobal;
-    *compartment = js::GetObjectCompartment(tempGlobal);
-
-    JS_SetCompartmentPrivate(*compartment, priv_holder.forget());
-    return true;
-}
-
 #ifdef DEBUG
 struct VerifyTraceXPCGlobalCalledTracer
 {
     JSTracer base;
     bool ok;
 };
 
 static void
@@ -1045,20 +1022,21 @@ TraceXPCGlobal(JSTracer *trc, JSObject *
     if (trc->callback == VerifyTraceXPCGlobalCalled) {
         // We don't do anything here, we only want to verify that TraceXPCGlobal
         // was called.
         reinterpret_cast<VerifyTraceXPCGlobalCalledTracer*>(trc)->ok = true;
         return;
     }
 #endif
 
-    if (XPCWrappedNativeScope *scope = XPCWrappedNativeScope::GetNativeScope(obj))
+    if (XPCWrappedNativeScope *scope = GetObjectScope(obj))
         scope->TraceDOMPrototypes(trc);
 
-    mozilla::dom::TraceProtoOrIfaceCache(trc, obj);
+    if (js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL)
+        mozilla::dom::TraceProtoOrIfaceCache(trc, obj);
 }
 
 #ifdef DEBUG
 #include "mozilla/Preferences.h"
 #include "nsIXULRuntime.h"
 static void
 CheckTypeInference(JSContext *cx, JSClass *clasp, nsIPrincipal *principal)
 {
@@ -1093,54 +1071,52 @@ CheckTypeInference(JSContext *cx, JSClas
     MOZ_ASSERT(JS_GetOptions(cx) & JSOPTION_TYPE_INFERENCE);
 }
 #else
 #define CheckTypeInference(cx, clasp, principal) {}
 #endif
 
 namespace xpc {
 
-nsresult
-CreateGlobalObject(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
-                   bool wantXrays, JSObject **global, JSCompartment **compartment)
+JSObject*
+CreateGlobalObject(JSContext *cx, JSClass *clasp, nsIPrincipal *principal)
 {
     // Make sure that Type Inference is enabled for everything non-chrome.
     // Sandboxes and compilation scopes are exceptions. See bug 744034.
     CheckTypeInference(cx, clasp, principal);
 
     NS_ABORT_IF_FALSE(NS_IsMainThread(), "using a principal off the main thread?");
 
-    xpc::CompartmentPrivate *priv = new xpc::CompartmentPrivate(wantXrays);
-    if (!CreateNewGlobal(cx, clasp, principal, priv, global, compartment))
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-
-    XPCCompartmentSet& set = nsXPConnect::GetRuntimeInstance()->GetCompartmentSet();
-    if (!set.put(*compartment))
-        return UnexpectedFailure(NS_ERROR_FAILURE);
+    JSObject *global = JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal));
+    if (!global)
+        return nullptr;
+    JSAutoCompartment ac(cx, global);
+    // The constructor automatically attaches the scope to the compartment private
+    // of |global|.
+    (void) new XPCWrappedNativeScope(cx, global);
 
 #ifdef DEBUG
     // Verify that the right trace hook is called. Note that this doesn't
     // work right for wrapped globals, since the tracing situation there is
     // more complicated. Manual inspection shows that they do the right thing.
-    if (clasp->flags & JSCLASS_XPCONNECT_GLOBAL &&
-        !((js::Class*)clasp)->ext.isWrappedNative)
+    if (!((js::Class*)clasp)->ext.isWrappedNative)
     {
         VerifyTraceXPCGlobalCalledTracer trc;
         JS_TracerInit(&trc.base, JS_GetRuntime(cx), VerifyTraceXPCGlobalCalled);
         trc.ok = false;
-        JS_TraceChildren(&trc.base, *global, JSTRACE_OBJECT);
-        NS_ABORT_IF_FALSE(trc.ok, "Trace hook needs to call TraceXPCGlobal if JSCLASS_XPCONNECT_GLOBAL is set.");
+        JS_TraceChildren(&trc.base, global, JSTRACE_OBJECT);
+        NS_ABORT_IF_FALSE(trc.ok, "Trace hook on global needs to call TraceXPCGlobal for XPConnect compartments.");
     }
 #endif
 
     if (clasp->flags & JSCLASS_DOM_GLOBAL) {
-        AllocateProtoOrIfaceCache(*global);
+        AllocateProtoOrIfaceCache(global);
     }
 
-    return NS_OK;
+    return global;
 }
 
 } // namespace xpc
 
 NS_IMETHODIMP
 nsXPConnect::InitClassesWithNewWrappedGlobal(JSContext * aJSContext,
                                              nsISupports *aCOMObj,
                                              nsIPrincipal * aPrincipal,
@@ -1465,18 +1441,17 @@ nsXPConnect::GetWrappedNativeOfNativeObj
     NS_ASSERTION(_retval, "bad param");
 
     *_retval = nullptr;
 
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    XPCWrappedNativeScope* scope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
+    XPCWrappedNativeScope* scope = GetObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     AutoMarkingNativeInterfacePtr iface(ccx);
     iface = XPCNativeInterface::GetNewOrUsed(ccx, &aIID);
     if (!iface)
         return NS_ERROR_FAILURE;
 
@@ -1497,24 +1472,19 @@ nsXPConnect::ReparentWrappedNativeIfFoun
                                           JSObject * aNewParent,
                                           nsISupports *aCOMObj,
                                           nsIXPConnectJSObjectHolder **_retval)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    XPCWrappedNativeScope* scope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
-    if (!scope)
-        return UnexpectedFailure(NS_ERROR_FAILURE);
-
-    XPCWrappedNativeScope* scope2 =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aNewParent);
-    if (!scope2)
+    XPCWrappedNativeScope* scope = GetObjectScope(aScope);
+    XPCWrappedNativeScope* scope2 = GetObjectScope(aNewParent);
+    if (!scope || !scope2)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     return XPCWrappedNative::
         ReparentWrapperIfFound(ccx, scope, scope2, aNewParent, aCOMObj,
                                (XPCWrappedNative**) _retval);
 }
 
 static JSDHashOperator
@@ -1535,18 +1505,17 @@ MoveableWrapperFinder(JSDHashTable *tabl
 /* void rescueOrphansInScope(in JSContextPtr aJSContext, in JSObjectPtr  aScope); */
 NS_IMETHODIMP
 nsXPConnect::RescueOrphansInScope(JSContext *aJSContext, JSObject *aScope)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    XPCWrappedNativeScope *scope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
+    XPCWrappedNativeScope *scope = GetObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     // First, look through the old scope and find all of the wrappers that we
     // might need to rescue.
     nsTArray<nsRefPtr<XPCWrappedNative> > wrappersToMove;
 
     {   // scoped lock
@@ -1788,18 +1757,17 @@ nsXPConnect::GetWrappedNativePrototype(J
                                        nsIXPConnectJSObjectHolder **_retval)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     JSAutoCompartment ac(aJSContext, aScope);
 
-    XPCWrappedNativeScope* scope =
-        XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
+    XPCWrappedNativeScope* scope = GetObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCNativeScriptableCreateInfo sciProto;
     XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
 
     AutoMarkingWrappedNativeProtoPtr proto(ccx);
     proto = XPCWrappedNativeProto::GetNewOrUsed(ccx, scope, aClassInfo, &sciProto);
@@ -2420,32 +2388,24 @@ DumpJSHeap(FILE* file)
     }
     js::DumpHeapComplete(xpc->GetRuntime()->GetJSRuntime(), file);
 }
 
 void
 SetLocationForGlobal(JSObject *global, const nsACString& location)
 {
     MOZ_ASSERT(global);
-
-    CompartmentPrivate *priv = GetCompartmentPrivate(global);
-    MOZ_ASSERT(priv, "No compartment private");
-
-    priv->SetLocation(location);
+    EnsureCompartmentPrivate(global)->SetLocation(location);
 }
 
 void
 SetLocationForGlobal(JSObject *global, nsIURI *locationURI)
 {
     MOZ_ASSERT(global);
-
-    CompartmentPrivate *priv = GetCompartmentPrivate(global);
-    MOZ_ASSERT(priv, "No compartment private");
-
-    priv->SetLocation(locationURI);
+    EnsureCompartmentPrivate(global)->SetLocation(locationURI);
 }
 
 } // namespace xpc
 
 static void
 NoteJSChildGrayWrapperShim(void *data, void *thing)
 {
     TraversalTracer *trc = static_cast<TraversalTracer*>(data);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -165,18 +165,19 @@
 #include "nsDataHashtable.h"
 #include "nsDeque.h"
 
 #include "nsIScriptSecurityManager.h"
 #include "nsNetUtil.h"
 
 #include "nsIXPCScriptNotify.h"  // used to notify: ScriptEvaluated
 
+#include "nsIPrincipal.h"
+#include "nsJSPrincipals.h"
 #include "nsIScriptObjectPrincipal.h"
-#include "nsIPrincipal.h"
 #include "nsISecurityCheckedComponent.h"
 #include "xpcObjectHelper.h"
 #include "nsIThreadInternal.h"
 
 #ifdef XP_WIN
 // Nasty MS defines
 #ifdef GetClassInfo
 #undef GetClassInfo
@@ -261,22 +262,16 @@ void DEBUG_ReportShadowedMembers(XPCNati
 extern const char XPC_CONTEXT_STACK_CONTRACTID[];
 extern const char XPC_RUNTIME_CONTRACTID[];
 extern const char XPC_EXCEPTION_CONTRACTID[];
 extern const char XPC_CONSOLE_CONTRACTID[];
 extern const char XPC_SCRIPT_ERROR_CONTRACTID[];
 extern const char XPC_ID_CONTRACTID[];
 extern const char XPC_XPCONNECT_CONTRACTID[];
 
-typedef js::HashSet<JSCompartment *,
-                    js::DefaultHasher<JSCompartment *>,
-                    js::SystemAllocPolicy> XPCCompartmentSet;
-
-typedef XPCCompartmentSet::Range XPCCompartmentRange;
-
 /***************************************************************************/
 // Useful macros...
 
 #define XPC_STRING_GETTER_BODY(dest, src)                                     \
     NS_ENSURE_ARG_POINTER(dest);                                              \
     char* result;                                                             \
     if (src)                                                                  \
         result = (char*) nsMemory::Clone(src,                                 \
@@ -712,19 +707,16 @@ public:
         {return mNativeScriptableSharedMap;}
 
     XPCWrappedNativeProtoMap* GetDyingWrappedNativeProtoMap() const
         {return mDyingWrappedNativeProtoMap;}
 
     XPCWrappedNativeProtoMap* GetDetachedWrappedNativeProtoMap() const
         {return mDetachedWrappedNativeProtoMap;}
 
-    XPCCompartmentSet& GetCompartmentSet()
-        {return mCompartmentSet;}
-
     XPCLock* GetMapLock() const {return mMapLock;}
 
     JSBool OnJSContextNew(JSContext* cx);
 
     bool DeferredRelease(nsISupports* obj);
 
 
     /**
@@ -952,17 +944,16 @@ private:
     IID2WrappedJSClassMap*   mWrappedJSClassMap;
     IID2NativeInterfaceMap*  mIID2NativeInterfaceMap;
     ClassInfo2NativeSetMap*  mClassInfo2NativeSetMap;
     NativeSetMap*            mNativeSetMap;
     IID2ThisTranslatorMap*   mThisTranslatorMap;
     XPCNativeScriptableSharedMap* mNativeScriptableSharedMap;
     XPCWrappedNativeProtoMap* mDyingWrappedNativeProtoMap;
     XPCWrappedNativeProtoMap* mDetachedWrappedNativeProtoMap;
-    XPCCompartmentSet        mCompartmentSet;
     XPCLock* mMapLock;
     PRThread* mThreadRunningGC;
     nsTArray<nsXPCWrappedJS*> mWrappedJSToReleaseArray;
     nsTArray<nsISupports*> mNativesToReleaseArray;
     JSBool mDoingFinalization;
     XPCRootSetElem *mVariantRoots;
     XPCRootSetElem *mWrappedJSRoots;
     XPCRootSetElem *mObjectHolderRoots;
@@ -1597,20 +1588,20 @@ enum WrapperType {
 /***************************************************************************/
 // XPCWrappedNativeScope is one-to-one with a JS global object.
 
 class XPCWrappedNativeScope : public PRCList
 {
 public:
 
     static XPCWrappedNativeScope*
-    GetNewOrUsed(XPCCallContext& ccx, JSObject* aGlobal, nsISupports* aNative = nullptr);
+    GetNewOrUsed(JSContext *cx, JSObject* aGlobal);
 
     XPCJSRuntime*
-    GetRuntime() const {return mRuntime;}
+    GetRuntime() const {return XPCJSRuntime::Get();}
 
     Native2WrappedNativeMap*
     GetWrappedNativeMap() const {return mWrappedNativeMap;}
 
     ClassInfo2WrappedNativeProtoMap*
     GetWrappedNativeProtoMap(JSBool aMainThreadOnly) const
         {return aMainThreadOnly ?
                 mMainThreadWrappedNativeProtoMap :
@@ -1625,62 +1616,41 @@ public:
 
     JSObject*
     GetGlobalJSObject() const
         {return xpc_UnmarkGrayObject(mGlobalJSObject);}
 
     JSObject*
     GetGlobalJSObjectPreserveColor() const {return mGlobalJSObject;}
 
-    JSObject*
-    GetPrototypeJSObject() const
-        {return xpc_UnmarkGrayObject(mPrototypeJSObject);}
-
-    JSObject*
-    GetPrototypeJSObjectPreserveColor() const {return mPrototypeJSObject;}
-
     // Getter for the prototype that we use for wrappers that have no
     // helper.
     JSObject*
     GetPrototypeNoHelper(XPCCallContext& ccx);
 
     nsIPrincipal*
-    GetPrincipal() const
-    {return mScriptObjectPrincipal ?
-         mScriptObjectPrincipal->GetPrincipal() : nullptr;}
+    GetPrincipal() const {
+        if (!mGlobalJSObject)
+            return nullptr;
+        JSCompartment *c = js::GetObjectCompartment(mGlobalJSObject);
+        return nsJSPrincipals::get(JS_GetCompartmentPrincipals(c));
+    }
 
     void RemoveWrappedNativeProtos();
 
-    static XPCWrappedNativeScope*
-    FindInJSObjectScope(JSContext* cx, JSObject* obj,
-                        JSBool OKIfNotInitialized = false,
-                        XPCJSRuntime* runtime = nullptr);
-
-    static XPCWrappedNativeScope*
-    FindInJSObjectScope(XPCCallContext& ccx, JSObject* obj,
-                        JSBool OKIfNotInitialized = false)
-    {
-        return FindInJSObjectScope(ccx, obj, OKIfNotInitialized,
-                                   ccx.GetRuntime());
-    }
-
     static void
     SystemIsBeingShutDown();
 
     static void
     TraceWrappedNativesInAllScopes(JSTracer* trc, XPCJSRuntime* rt);
 
     void TraceSelf(JSTracer *trc) {
         JSObject *obj = GetGlobalJSObjectPreserveColor();
         MOZ_ASSERT(obj);
         JS_CALL_OBJECT_TRACER(trc, obj, "XPCWrappedNativeScope::mGlobalJSObject");
-
-        JSObject *proto = GetPrototypeJSObjectPreserveColor();
-        if (proto)
-            JS_CALL_OBJECT_TRACER(trc, proto, "XPCWrappedNativeScope::mPrototypeJSObject");
     }
 
     static void
     SuspectAllWrappers(XPCJSRuntime* rt, nsCycleCollectionTraversalCallback &cb);
 
     static void
     StartFinalizationPhaseOfGC(JSFreeOp *fop, XPCJSRuntime* rt);
 
@@ -1714,46 +1684,54 @@ public:
     SizeOfIncludingThis(nsMallocSizeOfFun mallocSizeOf);
 
     JSBool
     IsValid() const {return mRuntime != nullptr;}
 
     static JSBool
     IsDyingScope(XPCWrappedNativeScope *scope);
 
-    void SetGlobal(XPCCallContext& ccx, JSObject* aGlobal, nsISupports* aNative);
+    void SetGlobal(JSContext *cx, JSObject* aGlobal);
 
     static void InitStatics() { gScopes = nullptr; gDyingScopes = nullptr; }
 
     XPCContext *GetContext() { return mContext; }
     void ClearContext() { mContext = nullptr; }
 
     nsDataHashtable<nsDepCharHashKey, JSObject*>& GetCachedDOMPrototypes()
     {
         return mCachedDOMPrototypes;
     }
 
-    static XPCWrappedNativeScope *GetNativeScope(JSObject *obj)
-    {
-        MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL);
-
-        const js::Value &v = js::GetObjectSlot(obj, JSCLASS_GLOBAL_SLOT_COUNT);
-        return v.isUndefined()
-               ? nullptr
-               : static_cast<XPCWrappedNativeScope *>(v.toPrivate());
-    }
     void TraceDOMPrototypes(JSTracer *trc);
 
     JSBool ExperimentalBindingsEnabled()
     {
         return mExperimentalBindingsEnabled;
     }
 
+    typedef nsTHashtable<nsPtrHashKey<JSObject> > DOMExpandoMap;
+
+    bool RegisterDOMExpandoObject(JSObject *expando) {
+        if (!mDOMExpandoMap) {
+            mDOMExpandoMap = new DOMExpandoMap();
+            mDOMExpandoMap->Init(8);
+        }
+        return mDOMExpandoMap->PutEntry(expando, mozilla::fallible_t());
+    }
+    void RemoveDOMExpandoObject(JSObject *expando) {
+        if (mDOMExpandoMap)
+            mDOMExpandoMap->RemoveEntry(expando);
+    }
+
+    XPCWrappedNativeScope(JSContext *cx, JSObject* aGlobal);
+
+    nsAutoPtr<JSObject2JSObjectMap> mWaiverWrapperMap;
+
 protected:
-    XPCWrappedNativeScope(XPCCallContext& ccx, JSObject* aGlobal, nsISupports* aNative);
     virtual ~XPCWrappedNativeScope();
 
     static void KillDyingScopes();
 
     XPCWrappedNativeScope(); // not implemented
 
 private:
     static XPCWrappedNativeScope* gScopes;
@@ -1766,31 +1744,23 @@ private:
     nsRefPtr<nsXPCComponents>        mComponents;
     XPCWrappedNativeScope*           mNext;
     // The JS global object for this scope.  If non-null, this will be the
     // default parent for the XPCWrappedNatives that have us as the scope,
     // unless a PreCreate hook overrides it.  Note that this _may_ be null (see
     // constructor).
     js::ObjectPtr                    mGlobalJSObject;
 
-    // Cached value of Object.prototype
-    js::ObjectPtr                    mPrototypeJSObject;
     // Prototype to use for wrappers with no helper.
     JSObject*                        mPrototypeNoHelper;
 
     XPCContext*                      mContext;
 
-    // The script object principal instance corresponding to our current global
-    // JS object.
-    // XXXbz what happens if someone calls JS_SetPrivate on mGlobalJSObject.
-    // How do we deal?  Do we need to?  I suspect this isn't worth worrying
-    // about, since all of our scope objects are verified as not doing that.
-    nsIScriptObjectPrincipal* mScriptObjectPrincipal;
-
     nsDataHashtable<nsDepCharHashKey, JSObject*> mCachedDOMPrototypes;
+    nsAutoPtr<DOMExpandoMap> mDOMExpandoMap;
 
     JSBool mExperimentalBindingsEnabled;
 };
 
 /***************************************************************************/
 // XPCNativeMember represents a single idl declared method, attribute or
 // constant.
 
@@ -2863,18 +2833,18 @@ public:
         }
         if (HasProto())
             GetProto()->TraceSelf(trc);
         else
             GetScope()->TraceSelf(trc);
         JSObject* wrapper = GetWrapperPreserveColor();
         if (wrapper)
             JS_CALL_OBJECT_TRACER(trc, wrapper, "XPCWrappedNative::mWrapper");
-        if (mScriptableInfo &&
-            (mScriptableInfo->GetJSClass()->flags & JSCLASS_XPCONNECT_GLOBAL))
+        if (mFlatJSObject && mFlatJSObject != INVALID_OBJECT &&
+            JS_IsGlobalObject(mFlatJSObject))
         {
             TraceXPCGlobal(trc, mFlatJSObject);
         }
     }
 
     void TraceJS(JSTracer *trc) {
         TraceInside(trc);
     }
@@ -4260,16 +4230,19 @@ struct SandboxOptions {
     { }
 
     bool wantXrays;
     bool wantComponents;
     bool wantXHRConstructor;
     JSObject* proto;
     nsCString sandboxName;
 };
+
+JSObject *
+CreateGlobalObject(JSContext *cx, JSClass *clasp, nsIPrincipal *principal);
 }
 
 // Helper for creating a sandbox object to use for evaluating
 // untrusted code completely separated from all other code in the
 // system using xpc_EvalInSandbox(). Takes the JSContext on which to
 // do setup etc on, puts the sandbox object in *vp (which must be
 // rooted by the caller), and uses the principal that's either
 // directly passed in prinOrSop or indirectly as an
@@ -4298,65 +4271,45 @@ xpc_EvalInSandbox(JSContext *cx, JSObjec
 // Inlined utilities.
 
 inline JSBool
 xpc_ForcePropertyResolve(JSContext* cx, JSObject* obj, jsid id);
 
 inline jsid
 GetRTIdByIndex(JSContext *cx, unsigned index);
 
-// Wrapper for JS_NewObject to mark the new object as system when parent is
-// also a system object. If uniqueType is specified then a new type object will
-// be created which is used only by the result, so that its property types
-// will be tracked precisely.
-inline JSObject*
-xpc_NewSystemInheritingJSObject(JSContext *cx, JSClass *clasp, JSObject *proto,
-                                bool uniqueType, JSObject *parent);
-
 nsISupports *
 XPC_GetIdentityObject(JSContext *cx, JSObject *obj);
 
 namespace xpc {
 
 class CompartmentPrivate
 {
 public:
-    typedef nsTHashtable<nsPtrHashKey<JSObject> > DOMExpandoMap;
-
-    CompartmentPrivate(bool wantXrays)
-        : wantXrays(wantXrays)
+    CompartmentPrivate()
+        : wantXrays(false)
         , universalXPConnectEnabled(false)
+        , scope(nullptr)
     {
         MOZ_COUNT_CTOR(xpc::CompartmentPrivate);
     }
 
     ~CompartmentPrivate();
 
     bool wantXrays;
 
     // This is only ever set during mochitest runs when enablePrivilege is called.
     // It's intended as a temporary stopgap measure until we can finish ripping out
     // enablePrivilege. Once set, this value is never unset (i.e., it doesn't follow
     // the old scoping rules of enablePrivilege). Using it is inherently unsafe.
     bool universalXPConnectEnabled;
 
-    nsAutoPtr<JSObject2JSObjectMap> waiverWrapperMap;
-    nsAutoPtr<DOMExpandoMap> domExpandoMap;
-
-    bool RegisterDOMExpandoObject(JSObject *expando) {
-        if (!domExpandoMap) {
-            domExpandoMap = new DOMExpandoMap();
-            domExpandoMap->Init(8);
-        }
-        return domExpandoMap->PutEntry(expando, mozilla::fallible_t());
-    }
-    void RemoveDOMExpandoObject(JSObject *expando) {
-        if (domExpandoMap)
-            domExpandoMap->RemoveEntry(expando);
-    }
+    // Our XPCWrappedNativeScope. This is non-null if and only if this is an
+    // XPConnect compartment.
+    XPCWrappedNativeScope *scope;
 
     const nsACString& GetLocation() {
         if (locationURI) {
             if (NS_FAILED(locationURI->GetSpec(location)))
                 location = NS_LITERAL_CSTRING("<unknown location>");
             locationURI = nullptr;
         }
         return location;
@@ -4376,16 +4329,19 @@ public:
         locationURI = aLocationURI;
     }
 
 private:
     nsCString location;
     nsCOMPtr<nsIURI> locationURI;
 };
 
+CompartmentPrivate*
+EnsureCompartmentPrivate(JSObject *obj);
+
 inline CompartmentPrivate*
 GetCompartmentPrivate(JSCompartment *compartment)
 {
     MOZ_ASSERT(compartment);
     void *priv = JS_GetCompartmentPrivate(compartment);
     return static_cast<CompartmentPrivate*>(priv);
 }
 
@@ -4426,16 +4382,23 @@ inline bool EnableUniversalXPConnect(JSC
     priv->universalXPConnectEnabled = true;
 
     // Recompute all the cross-compartment wrappers leaving the newly-privileged
     // compartment.
     return js::RecomputeWrappers(cx, js::SingleCompartment(compartment),
                                  js::AllCompartments());
 }
 
+// This returns null if and only if it is called on an object in a non-XPConnect
+// compartment.
+inline XPCWrappedNativeScope*
+GetObjectScope(JSObject *obj)
+{
+    return EnsureCompartmentPrivate(obj)->scope;
+}
 }
 
 /***************************************************************************/
 // Inlines use the above - include last.
 
 #include "XPCInlines.h"
 
 /***************************************************************************/
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -35,27 +35,22 @@ class nsScriptNameSpaceManager;
 namespace xpc {
 JSObject *
 TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target);
 
 JSObject *
 TransplantObjectWithWrapper(JSContext *cx,
                             JSObject *origobj, JSObject *origwrapper,
                             JSObject *targetobj, JSObject *targetwrapper);
-
-nsresult
-CreateGlobalObject(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
-                   bool wantXrays, JSObject **global,
-                   JSCompartment **compartment);
 } /* namespace xpc */
 
 #define XPCONNECT_GLOBAL_FLAGS                                                \
-    JSCLASS_DOM_GLOBAL | JSCLASS_XPCONNECT_GLOBAL | JSCLASS_HAS_PRIVATE |     \
+    JSCLASS_DOM_GLOBAL | JSCLASS_HAS_PRIVATE |                                \
     JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_IMPLEMENTS_BARRIERS |            \
-    JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(3)
+    JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(2)
 
 void
 TraceXPCGlobal(JSTracer *trc, JSObject *obj);
 
 // XXX where should this live?
 NS_EXPORT_(void)
 xpc_LocalizeContext(JSContext *cx);
 
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -54,31 +54,31 @@ GetCurrentOuter(JSContext *cx, JSObject 
 }
 
 JSObject *
 WrapperFactory::GetXrayWaiver(JSObject *obj)
 {
     // Object should come fully unwrapped but outerized.
     MOZ_ASSERT(obj == UnwrapObject(obj));
     MOZ_ASSERT(!js::GetObjectClass(obj)->ext.outerObject);
-    CompartmentPrivate *priv = GetCompartmentPrivate(obj);
-    MOZ_ASSERT(priv);
+    XPCWrappedNativeScope *scope = GetObjectScope(obj);
+    MOZ_ASSERT(scope);
 
-    if (!priv->waiverWrapperMap)
+    if (!scope->mWaiverWrapperMap)
         return NULL;
-    return xpc_UnmarkGrayObject(priv->waiverWrapperMap->Find(obj));
+    return xpc_UnmarkGrayObject(scope->mWaiverWrapperMap->Find(obj));
 }
 
 JSObject *
 WrapperFactory::CreateXrayWaiver(JSContext *cx, JSObject *obj)
 {
     // The caller is required to have already done a lookup.
     // NB: This implictly performs the assertions of GetXrayWaiver.
     MOZ_ASSERT(!GetXrayWaiver(obj));
-    CompartmentPrivate *priv = GetCompartmentPrivate(obj);
+    XPCWrappedNativeScope *scope = GetObjectScope(obj);
 
     // Get a waiver for the proto.
     JSObject *proto;
     if (!js::GetObjectProto(cx, obj, &proto))
         return nullptr;
     if (proto && !(proto = WaiveXray(cx, proto)))
         return nullptr;
 
@@ -89,22 +89,22 @@ WrapperFactory::CreateXrayWaiver(JSConte
     JSObject *waiver = Wrapper::New(cx, obj, proto,
                                     JS_GetGlobalForObject(cx, obj),
                                     &XrayWaiver);
     if (!waiver)
         return nullptr;
 
     // Add the new waiver to the map. It's important that we only ever have
     // one waiver for the lifetime of the target object.
-    if (!priv->waiverWrapperMap) {
-        priv->waiverWrapperMap = JSObject2JSObjectMap::
-                                   newMap(XPC_WRAPPER_MAP_SIZE);
-        MOZ_ASSERT(priv->waiverWrapperMap);
+    if (!scope->mWaiverWrapperMap) {
+        scope->mWaiverWrapperMap =
+          JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE);
+        MOZ_ASSERT(scope->mWaiverWrapperMap);
     }
-    if (!priv->waiverWrapperMap->Add(obj, waiver))
+    if (!scope->mWaiverWrapperMap->Add(obj, waiver))
         return nullptr;
     return waiver;
 }
 
 JSObject *
 WrapperFactory::WaiveXray(JSContext *cx, JSObject *obj)
 {
     obj = UnwrapObject(obj);
@@ -601,20 +601,20 @@ FixWaiverAfterTransplant(JSContext *cx, 
     // Update all the cross-compartment references to oldWaiver to point to
     // newWaiver.
     if (!js::RemapAllWrappersForObject(cx, oldWaiver, newWaiver))
         return false;
 
     // There should be no same-compartment references to oldWaiver, and we
     // just remapped all cross-compartment references. It's dead, so we can
     // remove it from the map.
-    CompartmentPrivate *priv = GetCompartmentPrivate(oldWaiver);
+    XPCWrappedNativeScope *scope = GetObjectScope(oldWaiver);
     JSObject *key = Wrapper::wrappedObject(oldWaiver);
-    MOZ_ASSERT(priv->waiverWrapperMap->Find(key));
-    priv->waiverWrapperMap->Remove(key);
+    MOZ_ASSERT(scope->mWaiverWrapperMap->Find(key));
+    scope->mWaiverWrapperMap->Remove(key);
     return true;
 }
 
 JSObject *
 TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
 {
     JSObject *oldWaiver = WrapperFactory::GetXrayWaiver(origobj);
     JSObject *newIdentity = JS_TransplantObject(cx, origobj, target);
--- a/layout/base/nsBidiPresUtils.cpp
+++ b/layout/base/nsBidiPresUtils.cpp
@@ -867,19 +867,20 @@ nsBidiPresUtils::ResolveParagraph(nsBloc
   if (aBpd->mParagraphDepth > 1) {
     nsIFrame* child;
     nsIFrame* parent;
     if (firstFrame) {
       child = firstFrame->GetParent();
       if (child) {
         parent = child->GetParent();
         if (parent && IsBidiSplittable(parent)) {
-          // no need to null-check the result of GetPrevSibling, because
-          // SplitInlineAncestors accepts a null parameter
-          SplitInlineAncestors(parent, child->GetPrevSibling());
+          nsIFrame* prev = child->GetPrevSibling();
+          if (prev) {
+            SplitInlineAncestors(parent, prev);
+          }
         }
       }
     }
     if (lastFrame) {
       child = lastFrame->GetParent();
       if (child) {
         parent = child->GetParent();
         if (parent && IsBidiSplittable(parent)) {
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -1429,24 +1429,27 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
                     0, NS_MAX(clipRectRadii[C_BL].height, clipRectRadii[C_BR].height)));
     }
 
     // When there's a blur radius, gfxAlphaBoxBlur leaves the skiprect area
     // unchanged. And by construction the gfxSkipRect is not touched by the
     // rendered shadow (even after blurring), so those pixels must be completely
     // transparent in the shadow, so drawing them changes nothing.
     gfxContext* renderContext = aRenderingContext.ThebesContext();
-    nsRefPtr<gfxContext> shadowContext;
     nsContextBoxBlur blurringArea;
-    shadowContext =
+    gfxContext* shadowContext =
       blurringArea.Init(shadowPaintRect, 0, blurRadius, twipsPerPixel,
                         renderContext, aDirtyRect, &skipGfxRect);
     if (!shadowContext)
       continue;
 
+    // shadowContext is owned by either blurringArea or aRenderingContext.
+    MOZ_ASSERT(shadowContext == renderContext ||
+               shadowContext == blurringArea.GetContext());
+
     // Set the shadow color; if not specified, use the foreground color
     nscolor shadowColor;
     if (shadowItem->mHasColor)
       shadowColor = shadowItem->mColor;
     else
       shadowColor = aForFrame->GetStyleColor()->mColor;
 
     renderContext->Save();
--- a/layout/base/nsFrameTraversal.cpp
+++ b/layout/base/nsFrameTraversal.cpp
@@ -32,18 +32,18 @@ public:
 
 protected:
   void      setCurrent(nsIFrame *aFrame){mCurrent = aFrame;}
   nsIFrame *getCurrent(){return mCurrent;}
   void      setStart(nsIFrame *aFrame){mStart = aFrame;}
   nsIFrame *getStart(){return mStart;}
   nsIFrame *getLast(){return mLast;}
   void      setLast(nsIFrame *aFrame){mLast = aFrame;}
-  PRInt8    getOffEdge(){return mOffEdge;}
-  void      setOffEdge(PRInt8 aOffEdge){mOffEdge = aOffEdge;}
+  int8_t    getOffEdge(){return mOffEdge;}
+  void      setOffEdge(int8_t aOffEdge){mOffEdge = aOffEdge;}
   void      SetLockInScrollView(bool aLockScroll){mLockScroll = aLockScroll;}
 
   /*
    Our own versions of the standard frame tree navigation
    methods, which, if the iterator is following out-of-flows,
    apply the following rules for placeholder frames:
    
    - If a frame HAS a placeholder frame, getting its parent
@@ -89,17 +89,17 @@ protected:
   bool mLockScroll;
   bool mFollowOOFs;
   nsIteratorType mType;
 
 private:
   nsIFrame *mStart;
   nsIFrame *mCurrent;
   nsIFrame *mLast; //the last one that was in current;
-  PRInt8    mOffEdge; //0= no -1 to far prev, 1 to far next;
+  int8_t    mOffEdge; //0= no -1 to far prev, 1 to far next;
 };
 
 
 
 // Bidi visual iterator
 class nsVisualIterator: public nsFrameIterator
 {
 public:
@@ -163,17 +163,17 @@ nsFrameTraversal::~nsFrameTraversal()
 }
 
 NS_IMPL_ISUPPORTS1(nsFrameTraversal,nsIFrameTraversal)
 
 NS_IMETHODIMP 
  nsFrameTraversal::NewFrameTraversal(nsIFrameEnumerator **aEnumerator,
                                      nsPresContext* aPresContext,
                                      nsIFrame *aStart,
-                                     PRInt32 aType,
+                                     int32_t aType,
                                      bool aVisual,
                                      bool aLockInScrollView,
                                      bool aFollowOOFs)
 {
   return NS_NewFrameTraversal(aEnumerator, aPresContext, aStart,
                               static_cast<nsIteratorType>(aType),
                               aVisual, aLockInScrollView, aFollowOOFs);  
 }
--- a/layout/base/nsFrameTraversal.h
+++ b/layout/base/nsFrameTraversal.h
@@ -24,15 +24,15 @@ public:
   nsFrameTraversal();
   virtual ~nsFrameTraversal();
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD NewFrameTraversal(nsIFrameEnumerator **aEnumerator,
                                nsPresContext* aPresContext,
                                nsIFrame *aStart,
-                               PRInt32 aType,
+                               int32_t aType,
                                bool aVisual,
                                bool aLockInScrollView,
                                bool aFollowOOFs);
 };
 
 #endif //NSFRAMETRAVERSAL_H
--- a/layout/base/nsIFrameTraversal.h
+++ b/layout/base/nsIFrameTraversal.h
@@ -56,17 +56,17 @@ public:
    * @param aFollowOOFs [in] whether the iterator should follow out-of-flows.
    *        If true, when reaching a placeholder frame while going down will get
    *        the real frame. Going back up will go on past the placeholder,
    *        so the placeholders are logically part of the frame tree.
    */
   NS_IMETHOD NewFrameTraversal(nsIFrameEnumerator **aEnumerator,
                                nsPresContext* aPresContext,
                                nsIFrame *aStart,
-                               PRInt32 aType,
+                               int32_t aType,
                                bool aVisual,
                                bool aLockInScrollView,
                                bool aFollowOOFs) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIFrameTraversal, NS_IFRAMETRAVERSAL_IID)
 
 #endif //NSIFRAMETRAVERSAL_H
--- a/layout/base/tests/test_maxLineBoxWidth.html
+++ b/layout/base/tests/test_maxLineBoxWidth.html
@@ -9,34 +9,38 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <style>
   p {
     margin-bottom: 30px;
   }
 
+  .leftPadd {
+    padding-left: 100px;
+  }
+
   #container {
     width: 200px;
   }
 
-  .box {
+  #box {
     position: absolute;
     height: 600px;
     width: 200px;
     border: 1px solid blue;
   }
   </style>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=780258">Mozilla Bug 780258</a>
 <p id="display"></p>
 
 <div id="content" style="display: none">
-  <div class="box">&nbsp;</div>
+  <div id="box">&nbsp;</div>
   <div id="container">
     <p>All of this text should be completely contained
        within the blue box.
     <p>I once knew a man, showed me the sleight of hand.
        In the blink of an eye he danced across the strings.
        He played a song I've never heard; poignant and absurd;
        To this day, it leaves me wondering.
     <p>Don't let tomorrow find you wishin'.
@@ -47,58 +51,104 @@ https://bugzilla.mozilla.org/show_bug.cg
        from the clock up on the wall.
     <p>You are what you are.
        You dream what you dream.
        Play on your blue guitar for me.
   </div>
 </div>
 <pre id="test">
 <script type="application/javascript">
-function doChange() {
-  SpecialPowers.setMaxLineBoxWidth(window, 200);
-}
+/** Test for Bug 780258 and Bug 803211 **/
 
+var gNarrowerContentSnap;
+var gWideContentSnap;
 var gFirstBlankSnap;
 var gUnchangedContentSnap;
 var gIncorrectContentSnap;
 var gCorrectContentSnap;
 
-/** Test for Bug 780258 **/
-SimpleTest.waitForExplicitFinish();
-gFirstBlankSnap = snapshotWindow(window);
+function setupFirstTest() {
+  gFirstBlankSnap = snapshotWindow(window);
+
+  // Display our content.
+  document.getElementById('content').style.display = 'block';
 
-// Display our content.
-document.getElementById('content').style.display = 'block';
+  // Take a snapshot.
+  gUnchangedContentSnap = snapshotWindow(window);
+}
+
+function performFirstTest() {
+  setupFirstTest();
+  // Verify this isn't the same as the blank snapshot.
+  var result = compareSnapshots(gFirstBlankSnap, gUnchangedContentSnap, false);
+  ok(result[0], "content should appear different than blank page");
 
-// Take a snapshot.
-gUnchangedContentSnap = snapshotWindow(window);
+  // Set container width to 350px.
+  document.getElementById('container').style.width = '350px';
+
+  // Take a snapshot.
+  gIncorrectContentSnap = snapshotWindow(window);
+
+  // Verify this is NOT the same as the first content snapshot.
+  result = compareSnapshots(gUnchangedContentSnap, gIncorrectContentSnap, false);
+  ok(result[0], "unchanged content should be different than changed content");
 
-// Verify this isn't the same as the blank snapshot.
-var result = compareSnapshots(gFirstBlankSnap, gUnchangedContentSnap, false);
-ok(result[0], "content should appear different than blank page");
+  // Run the max line box width change.
+  SpecialPowers.setMaxLineBoxWidth(window, 200);
 
-// Set container width to 350px.
-document.getElementById('container').style.width = '350px';
+  // Take snapshot.
+  gCorrectContentSnap = snapshotWindow(window);
+
+  // Compare snapshots.
+  result = compareSnapshots(gUnchangedContentSnap, gCorrectContentSnap, true);
+  ok(result[0], "unchanged content should be the same as corrected content");
+}
 
-// Take a snapshot.
-gIncorrectContentSnap = snapshotWindow(window);
+function setupSecondTest() {
+  var elements = document.getElementById("container").getElementsByTagName("p");
+  for (var i = 0; i < elements.length; i++) {
+    elements[i].setAttribute("class", "leftPadd");
+  }
+
+  document.getElementById("box").style.paddingLeft = "100px";
 
-// Verify this is NOT the same as the first content snapshot.
-result = compareSnapshots(gUnchangedContentSnap, gIncorrectContentSnap, false);
-ok(result[0], "unchanged content should be different than changed content");
+  document.getElementById("container").style.width = "300px";
+}
+
+// Another test to verify that the max line box width is
+// actually forcing the WIDTH of the line boxes, and not
+// the absolute right edge to be set
+function performSecondTest() {
+  setupSecondTest();
+  SpecialPowers.setMaxLineBoxWidth(window, 2000);
+
+  // Take a snapshot with a max line box width of 200px;
+  gWideContentSnap = snapshotWindow(window);
 
-// Run the max line box width change.
-doChange();
+  SpecialPowers.setMaxLineBoxWidth(window, 200);
+
+  // Take a snapshot with the new max line box width
+  gNarrowerContentSnap = snapshotWindow(window);
+
+  // Compare snapshots.
+  result = compareSnapshots(gNarrowerContentSnap, gWideContentSnap, true);
+  ok(result[0], "content with a max line box width of 2000px and content with" +
+     " a max line box width of 200px should be the same with a 100px left padding");
+}
 
-// Take snapshot.
-gCorrectContentSnap = snapshotWindow(window);
+SimpleTest.waitForExplicitFinish();
 
-// Compare snapshots.
-result = compareSnapshots(gUnchangedContentSnap, gCorrectContentSnap, true);
-ok(result[0], "unchanged content should be the same as corrected content");
+// The first test verifies that the max line box width
+// actually causes a change in page layout.
+performFirstTest();
+
+// The second test verifies that the max line box width
+// is actually measuring width, and not position of
+// the left/right edges of the line box.
+performSecondTest();
 
 // Finish the test.
 SimpleTest.finish();
 
 </script>
 </pre>
 </body>
 </html>
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -759,18 +759,18 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra
   // For now, set the available height to unconstrained always.
   nsSize availSize(mBlockReflowState->ComputedWidth(), NS_UNCONSTRAINEDSIZE);
 
   // If the available size is greater than the maximum line box width (if
   // specified), then we need to adjust the line box width to be at the max
   // possible width.
   nscoord maxLineBoxWidth = aFrame->PresContext()->PresShell()->MaxLineBoxWidth();
 
-  if (maxLineBoxWidth > 0 && psd->mRightEdge > maxLineBoxWidth) {
-    psd->mRightEdge = maxLineBoxWidth;
+  if (maxLineBoxWidth > 0 && psd->mRightEdge - psd->mLeftEdge > maxLineBoxWidth) {
+    psd->mRightEdge = psd->mLeftEdge + maxLineBoxWidth;
   }
 
   // Inline-ish and text-ish things don't compute their width;
   // everything else does.  We need to give them an available width that
   // reflects the space left on the line.
   NS_WARN_IF_FALSE(psd->mRightEdge != NS_UNCONSTRAINEDSIZE,
                    "have unconstrained width; this should only result from "
                    "very large sizes, not attempts at intrinsic width "
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/712600-2-dyn.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class="reftest-wait"><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+    <meta charset="utf-8">
+    <title>HTML Test: BDI: neutral when nested</title>
+    <link rel="reference" href="https://bug712600.bugzilla.mozilla.org/bdi-neutral-nested-ref.html">
+    <link rel="author" title="Aharon Lanin" href="mailto:aharon@google.com">
+    <link rel="author" title="HTML5 bidi test WG" href="mailto:html5bidi@googlegroups.com">
+    <link rel="help" href="http://dev.w3.org/html5/spec/Overview.html#the-bdi-element">
+    <meta name="assert" content="
+      'For the purposes of applying the bidirectional algorithm to the paragraph-level
+      container that a bdi element finds itself within, the bdi element must be treated
+      like a U+FFFC OBJECT REPLACEMENT CHARACTER.'">
+    <style>
+      body{
+        font-size:2em;
+      }
+    </style>
+  </head>
+  <body>
+    <!-- Key to entities used below:
+      &#x05D0; ... &#x05D5; - The first six Hebrew letters (strongly RTL).
+      &#x202D; - The LRO (left-to-right-override) formatting character.
+      &#x202C; - The PDF (pop directional formatting) formatting character; closes LRO. -->
+
+      <div dir="ltr">א + <bdi>[a + <bdi>[ב + <bdi>[b + 4]</bdi> + 3]</bdi> + 2]</bdi> + 1</div>
+      <div dir="ltr">א + <bdi dir="rtl">[a + <bdi dir="ltr">[ב + <bdi dir="rtl">[b + 4]</bdi> + 3]</bdi> + 2]</bdi> + 1</div>
+      <div dir="ltr">א + <bdi dir="ltr">[<span id='delete1'>z +</span>a + <bdi dir="rtl">[ב + <bdi dir="ltr">[b + 4]</bdi> + 3]</bdi> + 2]</bdi> + 1</div>
+      <div dir="rtl">a + <bdi>[א + <bdi>[b + <bdi>[ב + 3]</bdi> + 2]</bdi> + 1]</bdi> + 0</div>
+      <div dir="rtl">a + <bdi dir="ltr">[א + <bdi dir="rtl">[b + <bdi dir="ltr">[ב + 3]</bdi> + 2]</bdi> + 1]</bdi> + 0</div>
+      <div dir="rtl">a + <bdi dir="rtl">[א + <bdi dir="ltr">[<span
+      id='delete2'>z + </span>b + <bdi dir="rtl">[ב + 3]</bdi> + 2]</bdi> + 1]</bdi> + 0</div>
+
+      <script type="text/javascript">
+	function deleteSpans() {
+	    var n = document.getElementById('delete1');
+	    var n2 = document.getElementById('delete2');
+	    n.parentNode.removeChild(n);
+	    n2.parentNode.removeChild(n2);
+            document.documentElement.removeAttribute("class");
+        }
+        document.addEventListener("MozReftestInvalidate", deleteSpans, false);
+      </script>
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bidi/779003-1-dynamic.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+   <style type="text/css">
+#searchPaginationFooter {
+  direction: rtl;
+}
+
+.backLink {
+  display: inline;
+}
+
+.nextLink {
+  display: inline;
+}
+
+.pagination,
+.pagination li {
+  display: inline;
+}
+   </style>
+ </head>
+ <body>
+   <div>
+     <div id="searchPaginationFooter">
+       <p class="backLink"> &lt; <span class="gray">السابق</span></p>
+       <ul class="pagination">
+	 <li><span class="select">1</span></li>
+	 <li><a href="#page=2">2</a></li>
+	 <li><a href="#page=3">3</a></li>
+	 <li><a href="#page=4">4</a></li>
+	 <li><a href="#page=5">5</a></li>
+	 <li><a href="#page=6">6</a></li>
+	 <li><a href="#page=7">7</a></li>
+	 <li><a href="#page=8">8</a></li>
+	 <li id="here"><a href="#page=9">9</a></li>
+	 <li>...</li>
+	 <li><a href="#page=325">325</a></li>
+       </ul>
+       <p class="nextLink"><a href="#page=2">التالي</a> &gt; </p>
+     </div>
+   </div>
+<script type="text/javascript">
+function removePage() {
+  var here = document.getElementById("here");
+  here.parentNode.removeChild(here);
+  document.documentElement.removeAttribute("class");
+}
+document.addEventListener("MozReftestInvalidate", removePage, false);
+</script>
+ </body>
+</html>
--- a/layout/reftests/bidi/reftest.list
+++ b/layout/reftests/bidi/reftest.list
@@ -104,24 +104,25 @@ fuzzy-if(Android,24,1) fails-if(/^Window
 == 613157-1.html 613157-1-ref.html
 fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia) == 613157-2.html 613157-2-ref.html # bug 696673
 == 662288-1.html 662288-1-ref.html
 == 670226-1.html 670226-1-ref.html
 == 676245-1.html 676245-1-ref.html
 == 698291-1.html 698291-1-ref.html
 == 698706-1.html 698706-1-ref.html
 == 704837-1.html 704837-1-ref.html
+== 712600-1.html 712600-1-ref.html
+== 712600-2.html 712600-2-ref.html
+== 712600-2-dyn.html 712600-2-ref.html
+== 712600-3.html 712600-3-ref.html
 == 718236-1.html 718236-1-ref.html
 == 718236-2.html 718236-2-ref.html
 == 718236-3.html 718236-3-ref.html
 == 726420-1.html 726420-1-ref.html
 == 726460-1.html 726460-1-ref.html
 == 729047-1.html 729047-1-ref.html
 == 730562-1.html 730562-1-ref.html
 == 746987-1.html 746987-1-ref.html
 == 746987-2.html 746987-2-ref.html
 == 746987-3.html 746987-3-ref.html
 == 746987-4.html 746987-4-ref.html
-# See bug 793233
-random == 779003-1.html 779003-1-ref.html
-random == 712600-1.html 712600-1-ref.html
-random == 712600-2.html 712600-2-ref.html
-random == 712600-3.html 712600-3-ref.html
+== 779003-1.html 779003-1-ref.html
+== 779003-1-dynamic.html 779003-1-ref.html
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -153,20 +153,20 @@ fails-if(Android) == filter-extref-diffe
 == foreignObject-overflow-01.svg pass.svg
 == foreignObject-start-hidden-01.svg pass.svg # followup from Bug 596765
 == foreignObject-start-hidden-02.svg pass.svg
 == foreignObject-style-change-01.svg pass.svg
 == foreignObject-dynamic-abspos-01.html foreignObject-dynamic-abspos-01-ref.html
 == foreignObject-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html
 == foreignObject-dynamic-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html
 == getElementById-a-element-01.svg pass.svg
-== gradient-live-01a.svg gradient-live-01-ref.svg
-== gradient-live-01b.svg gradient-live-01-ref.svg
-== gradient-live-01c.svg gradient-live-01-ref.svg
-== gradient-live-01d.svg gradient-live-01-ref.svg
+fuzzy-if(Android,9,980) == gradient-live-01a.svg gradient-live-01-ref.svg
+fuzzy-if(Android,9,980) == gradient-live-01b.svg gradient-live-01-ref.svg
+fuzzy-if(Android,9,980) == gradient-live-01c.svg gradient-live-01-ref.svg
+fuzzy-if(Android,9,980) == gradient-live-01d.svg gradient-live-01-ref.svg
 fails == inline-in-xul-basic-01.xul pass.svg
 == invalid-text-01.svg pass.svg
 == lang-attribute-01.svg pass.svg
 == lang-attribute-02.svg pass.svg
 == lang-attribute-03.svg pass.svg
 == linearGradient-basic-01.svg pass.svg
 == linearGradient-basic-02.svg pass.svg
 == markers-and-group-opacity-01.svg markers-and-group-opacity-01-ref.svg
--- a/layout/reftests/text/726392-3-ref.html
+++ b/layout/reftests/text/726392-3-ref.html
@@ -1,31 +1,31 @@
 <!DOCTYPE html>
 <html>
  <head>
   <meta charset="utf-8">
   <title>Bug 726392</title>
   <style type="text/css">
-   p { margin: 0; white-space: pre-line; letter-spacing: 10px}
+   p { margin: 0; white-space: pre-line; letter-spacing: 10px; font-size:6px;}
    .alignLeft { text-align: left; }
    .alignRight { text-align: right; }
    .alignCenter { text-align: center; }
    .alignJustify { text-align: justify; }
    .alignStart { text-align: start; }
    .alignEnd { text-align: end; }
    .alignLastAuto { -moz-text-align-last: auto; }
    .alignLastLeft { -moz-text-align-last: left; }
    .alignLastRight { -moz-text-align-last: right; }
    .alignLastCenter { -moz-text-align-last: center; }
    .alignLastJustify { -moz-text-align-last: justify; }
    .alignLastStart { -moz-text-align-last: start; }
    .alignLastEnd { -moz-text-align-last: end; }
   </style>
 </head>
- <body>
+ <body style="width:590px; height:590px;">
   <div>
   <p class="alignLeft alignLastAuto">test
 test</p>
   <p class="alignLeft alignLastLeft">test
 test</p>
   <p class="alignLeft alignLastRight">test
 test</p>
   <p class="alignLeft alignLastCenter">test
--- a/layout/reftests/text/726392-3.html
+++ b/layout/reftests/text/726392-3.html
@@ -1,31 +1,31 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
  <head>
   <meta charset="utf-8">
   <title>Bug 726392</title>
   <style type="text/css">
-   p { margin: 0; white-space: pre-line; letter-spacing: 10px}
+   p { margin: 0; white-space: pre-line; letter-spacing: 10px; font-size:6px;}
    .alignLeft { text-align: left; }
    .alignRight { text-align: right; }
    .alignCenter { text-align: center; }
    .alignJustify { text-align: justify; }
    .alignStart { text-align: start; }
    .alignEnd { text-align: end; }
    .alignLastAuto { -moz-text-align-last: auto; }
    .alignLastLeft { -moz-text-align-last: left; }
    .alignLastRight { -moz-text-align-last: right; }
    .alignLastCenter { -moz-text-align-last: center; }
    .alignLastJustify { -moz-text-align-last: justify; }
    .alignLastStart { -moz-text-align-last: start; }
    .alignLastEnd { -moz-text-align-last: end; }
   </style>
 </head>
- <body>
+ <body style="width:590px; height:590px;">
  <div id="e" style="width:50%">
   <p class="alignLeft alignLastAuto">test
 test</p>
   <p class="alignLeft alignLastLeft">test
 test</p>
   <p class="alignLeft alignLastRight">test
 test</p>
   <p class="alignLeft alignLastCenter">test
--- a/layout/reftests/text/auto-hyphenation-sh-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-sh-1-ref.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="sh">
+<div style="width:1em; -moz-hyphens:manual; font-size:5px" lang="sh">
 Сва људ&shy;ска би&shy;ћа ра&shy;ђа&shy;ју се сло&shy;бод&shy;на и јед&shy;на&shy;ка у до&shy;сто&shy;јан&shy;ству и пра&shy;ви&shy;ма.
 <p>
 Sva ljud&shy;ska bi&shy;ća ra&shy;đa&shy;ju se slo&shy;bod&shy;na i jed&shy;na&shy;ka u do&shy;sto&shy;jan&shy;stvu i pra&shy;vi&shy;ma.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-sh-1.html
+++ b/layout/reftests/text/auto-hyphenation-sh-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="sh">
+<div style="width:1em; -moz-hyphens:auto; font-size:5px" lang="sh">
 Сва људска бића рађају се слободна и једнака у достојанству и правима.
 <p>
 Sva ljudska bića rađaju se slobodna i jednaka u dostojanstvu i pravima.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-sr-1-ref.html
+++ b/layout/reftests/text/auto-hyphenation-sr-1-ref.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:manual;" lang="sr">
+<div style="width:1em; -moz-hyphens:manual; font-size:5px" lang="sr">
 Сва људ&shy;ска би&shy;ћа ра&shy;ђа&shy;ју се сло&shy;бод&shy;на и јед&shy;на&shy;ка у до&shy;сто&shy;јан&shy;ству и пра&shy;ви&shy;ма.
 <p>
 Sva ljud&shy;ska bi&shy;ća ra&shy;đa&shy;ju se slo&shy;bod&shy;na i jed&shy;na&shy;ka u do&shy;sto&shy;jan&shy;stvu i pra&shy;vi&shy;ma.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/auto-hyphenation-sr-1.html
+++ b/layout/reftests/text/auto-hyphenation-sr-1.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=utf-8">
 </head>
 <body>
-<div style="width:1em; -moz-hyphens:auto;" lang="sr">
+<div style="width:1em; -moz-hyphens:auto; font-size:5px" lang="sr">
 Сва људска бића рађају се слободна и једнака у достојанству и правима.
 <p>
 Sva ljudska bića rađaju se slobodna i jednaka u dostojanstvu i pravima.
 </div>
 </body>
 </html>
--- a/layout/reftests/text/pre-line-1-ref.html
+++ b/layout/reftests/text/pre-line-1-ref.html
@@ -4,19 +4,19 @@
 <style>
 span { background:yellow; }
 .float { float:left; background:orange; }
 .outer { overflow:auto; margin:1em; }
 </style>
 </head>
 <body>
 
-<div class="outer">My name is<br><br><br>Fred.</div>
-<div class="outer"><span>My name is<br><br><br>Fred.</span></div>
+<div class="outer">My name is<br><br>Fred.</div>
+<div class="outer"><span>My name is<br><br>Fred.</span></div>
 
-<div class="outer"><div class="float">My name is<br><br><br>Fred.</div></div>
-<div class="outer"><div class="float"><span class="preline">My name is<br><br><br>Fred.</span></div></div>
+<div class="outer"><div class="float">My name is<br><br>Fred.</div></div>
+<div class="outer"><div class="float"><span class="preline">My name is<br><br>Fred.</span></div></div>
 
-<div class="outer"><div style="width:0;"><div class="float">My name is<br><br><br>Fred.</div></div></div>
-<div class="outer"><div style="width:0;"><div class="float"><span>My name is<br><br><br>Fred.</span></div></div></div>
+<div class="outer"><div style="width:0;"><div class="float">My name is<br><br>Fred.</div></div></div>
+<div class="outer"><div style="width:0;"><div class="float"><span>My name is<br><br>Fred.</span></div></div></div>
 
 </body>
 </html>
--- a/layout/reftests/text/pre-line-1.html
+++ b/layout/reftests/text/pre-line-1.html
@@ -11,44 +11,38 @@ span { background:yellow; }
 <body>
 
 
 
 <!-- Note, in the following tests there are trailing spaces after "is" and on the second
      blank line. -->
 
 <div class="outer"><div class="preline">My    name is   
-
  
  Fred.</div></div>
 <div class="outer"><span class="preline">My    name is   
-
  
  Fred.</span></div>
 
 
 
 
 
 <div class="outer"><div class="preline float">My    name is   
-
  
  Fred.</div></div>
 <div class="outer"><div class="float"><span class="preline">My    name is   
-
  
  Fred.</span></div></div>
 
 
 
 
 
 <div class="outer"><div style="width:0;"><div class="preline float">My    name is   
-
  
  Fred.</div></div></div>
 <div class="outer"><div style="width:0;"><div class="float"><span class="preline">My    name is   
-
  
  Fred.</span></div></div></div>
 
 </body>
 </html>
--- a/layout/reftests/text/text-align-center-last-center.html
+++ b/layout/reftests/text/text-align-center-last-center.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: center;
      -moz-text-align-last: center;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-center-last-default.html
+++ b/layout/reftests/text/text-align-center-last-default.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: center;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-center-last-end.html
+++ b/layout/reftests/text/text-align-center-last-end.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: center;
      -moz-text-align-last: end;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-center-last-justify.html
+++ b/layout/reftests/text/text-align-center-last-justify.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: center;
      -moz-text-align-last: justify;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-center-last-start.html
+++ b/layout/reftests/text/text-align-center-last-start.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: center;
      -moz-text-align-last: start;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-default-last-default.html
+++ b/layout/reftests/text/text-align-default-last-default.html
@@ -1,11 +1,17 @@
 <!DOCTYPE html>
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
+  <style type="text/css">
+   p {
+     text-align: start;
+     margin-right:310px;
+   }
+  </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-end-last-center.html
+++ b/layout/reftests/text/text-align-end-last-center.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: end;
      -moz-text-align-last: center;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-end-last-default.html
+++ b/layout/reftests/text/text-align-end-last-default.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: end;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-end-last-end.html
+++ b/layout/reftests/text/text-align-end-last-end.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: end;
      -moz-text-align-last: end;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-end-last-justify.html
+++ b/layout/reftests/text/text-align-end-last-justify.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: end;
      -moz-text-align-last: justify;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-end-last-start.html
+++ b/layout/reftests/text/text-align-end-last-start.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: end;
      -moz-text-align-last: start;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-justify-last-center.html
+++ b/layout/reftests/text/text-align-justify-last-center.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: justify;
      -moz-text-align-last: center;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-justify-last-default.html
+++ b/layout/reftests/text/text-align-justify-last-default.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: justify;
+     margin-right: 310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-justify-last-end.html
+++ b/layout/reftests/text/text-align-justify-last-end.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: justify;
      -moz-text-align-last: end;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-justify-last-justify.html
+++ b/layout/reftests/text/text-align-justify-last-justify.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: justify;
      -moz-text-align-last: justify;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-justify-last-start.html
+++ b/layout/reftests/text/text-align-justify-last-start.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: justify;
      -moz-text-align-last: start;
+     margin-right: 310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-start-last-center.html
+++ b/layout/reftests/text/text-align-start-last-center.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: start;
      -moz-text-align-last: center;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-start-last-default.html
+++ b/layout/reftests/text/text-align-start-last-default.html
@@ -1,16 +1,17 @@
 <!DOCTYPE html>
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: start;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-start-last-end.html
+++ b/layout/reftests/text/text-align-start-last-end.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: start;
      -moz-text-align-last: end;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-start-last-justify.html
+++ b/layout/reftests/text/text-align-start-last-justify.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: start;
      -moz-text-align-last: justify;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/text-align-start-last-start.html
+++ b/layout/reftests/text/text-align-start-last-start.html
@@ -2,16 +2,17 @@
 <html>
  <head>
   <title>text-align-last</title>
   <meta charset="utf-8">
   <style type="text/css">
    p {
      text-align: start;
      -moz-text-align-last: start;
+     margin-right:310px;
    }
   </style>
  </head>
  <body>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis odio est, cursus non adipiscing at, fringilla quis eros. Sed volutpat nibh sit amet ante molestie a vehicula nulla gravida. Mauris elementum cursus urna id vestibulum. Etiam volutpat odio tincidunt libero ullamcorper elementum. Suspendisse potenti. Ut ut arcu lorem. Integer mi sapien, porta a pharetra et, varius laoreet eros. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Sed ut mi at elit consequat aliquam id eu lectus. Etiam tincidunt diam et ante ullamcorper a convallis erat lobortis. Sed blandit ultrices dui et bibendum. Sed condimentum velit eget nibh rutrum cursus. Quisque pretium iaculis gravida. Proin risus eros, iaculis quis fermentum a, adipiscing&nbsp;id&nbsp;mauris.</p>
  <p dir="rtl">אמר המחבר: החיבור הזה לא חברתיו ללמד לבני האדם את אשר לא ידעו, אלא להזכירם את הידוע להם כבר ומפורסם אצלם פירסום גדול. כי לא תמצא ברוב דברי, אלא דברים שרוב בני האדם יודעים אותם ולא מסתפקים בהם כלל, אלא שכפי רוב פרסומם וכנגד מה שאמתתם גלויה לכל, כך ההעלם מהם מצוי מאד והשכחה רבה. על כן אין התועלת הנלקט מזה הספר יוצא מן הקריאה בו פעם אחת, כי כבר אפשר שלא ימצא הקורא בשכלו חדושים אחר קריאתו שלא היו בו לפני קריאתו, אלא מעט. אבל התועלת יוצא מן החזרה עליו וההתמדה. כי יזכרו לו הדברים האלה הנשכחים מבני האדם בטבע, וישים אל לבו חובתו אשר הוא&nbsp;מתעלם&nbsp;ממנה.</p>
  </body>
 </html>
--- a/layout/reftests/text/word-spacing-01-ref.html
+++ b/layout/reftests/text/word-spacing-01-ref.html
@@ -1,16 +1,16 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <style>
 span { display:inline-block; width:10em; }
 </style>
 </head>
-<body>
+<body style="width: 433px; height: 590px;">
 
 <table border="1">
 <tr><td>space <span></span>.</td>
 <tr><td>nonbreaking-space&nbsp;<span></span>.</td>
 <tr><td>ideographic-space&#x3000;.</td>
 <tr><td>newline
 <span></span>.</td>
 <tr><td>tab&#9;<span></span>.</td>
--- a/layout/reftests/text/word-spacing-01.html
+++ b/layout/reftests/text/word-spacing-01.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML>
 <html>
-<body style="word-spacing:10em;">
+<body style="word-spacing:10em; width: 433px; height: 590px;">
 
 <table border="1">
 <tr><td>space .</td>
 <tr><td>nonbreaking-space&nbsp;.</td>
 <tr><td>ideographic-space&#x3000;.</td>
 <tr><td>newline
 .</td>
 <tr><td>tab&#9;.</td>
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -10,24 +10,29 @@
 #include "CSFLogStream.h"
 #include "ccapi_call_info.h"
 #include "CC_SIPCCCallInfo.h"
 #include "ccapi_device_info.h"
 #include "CC_SIPCCDeviceInfo.h"
 #include "cpr_string.h"
 #include "cpr_stdlib.h"
 
+#include "jsapi.h"
 #include "nspr.h"
 #include "nss.h"
 #include "pk11pub.h"
 
 #include "nsNetCID.h"
+#include "nsIProperty.h"
+#include "nsIPropertyBag2.h"
 #include "nsIServiceManager.h"
+#include "nsISimpleEnumerator.h"
 #include "nsServiceManagerUtils.h"
 #include "nsISocketTransportService.h"
+
 #include "nsThreadUtils.h"
 #include "nsProxyRelease.h"
 
 #include "runnable_utils.h"
 #include "PeerConnectionCtx.h"
 #include "PeerConnectionImpl.h"
 
 #include "nsPIDOMWindow.h"
@@ -725,84 +730,151 @@ PeerConnectionImpl::NotifyDataChannel(mo
       mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
       return;
     }
     runnable->Run();
   }
 #endif
 }
 
-/*
- * the Constraints UI IDL work is being done. The CreateOffer below is the one
- * currently called by the signaling unit tests.
+/**
+ * Constraints look like this:
+ *
+ * {
+ *    "mandatory": {"foo":"hello", "bar": false, "baz": 10},
+ *    "optional": [{"hello":"foo"}, {"baz": false}]
+ * }
+ *
+ * Optional constraints are ordered, and hence in an array. This function
+ * converts a jsval that looks like the above into a MediaConstraints object.
  */
-NS_IMETHODIMP
-PeerConnectionImpl::CreateOffer(const char* constraints) {
-  MOZ_ASSERT(constraints);
+nsresult
+PeerConnectionImpl::ConvertConstraints(
+  const JS::Value& aConstraints, MediaConstraints* aObj, JSContext* aCx)
+{
+  size_t i;
+  jsval mandatory, optional;
+  JSObject& constraints = aConstraints.toObject();
+
+  // Mandatory constraints.
+  if (JS_GetProperty(aCx, &constraints, "mandatory", &mandatory)) {
+    if (JSVAL_IS_PRIMITIVE(mandatory) && mandatory.isObject() && !JSVAL_IS_NULL(mandatory)) {
+      JSObject* opts = JSVAL_TO_OBJECT(mandatory);
+      JS::AutoIdArray mandatoryOpts(aCx, JS_Enumerate(aCx, opts));
 
-  CheckIceState();
-  mRole = kRoleOfferer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
-  MediaConstraints aconstraints;
-  CreateOffer(aconstraints);
+      // Iterate over each property.
+      for (i = 0; i < mandatoryOpts.length(); i++) {
+        jsval option, optionName;
+        if (JS_GetPropertyById(aCx, opts, mandatoryOpts[i], &option)) {
+          if (JS_IdToValue(aCx, mandatoryOpts[i], &optionName)) {
+            // We only support boolean constraints for now.
+            if (JSVAL_IS_BOOLEAN(option)) {
+              JSString* optionNameString = JS_ValueToString(aCx, optionName);
+              NS_ConvertUTF16toUTF8 stringVal(JS_GetStringCharsZ(aCx, optionNameString));
+              aObj->setBooleanConstraint(stringVal.get(), JSVAL_TO_BOOLEAN(option), true);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Optional constraints.
+  if (JS_GetProperty(aCx, &constraints, "optional", &optional)) {
+    if (JSVAL_IS_PRIMITIVE(optional) && optional.isObject() && !JSVAL_IS_NULL(optional)) {
+      JSObject* opts = JSVAL_TO_OBJECT(optional);
+      if (JS_IsArrayObject(aCx, opts)) {
+        uint32_t length;
+        if (!JS_GetArrayLength(aCx, opts, &length)) {
+          return NS_ERROR_FAILURE;
+        }
+        for (i = 0; i < length; i++) {
+          jsval val;
+          JS_GetElement(aCx, opts, i, &val);
+          if (JSVAL_IS_PRIMITIVE(val)) {
+            // Extract name & value and store.
+            // FIXME: MediaConstraints does not support optional constraints?
+          }
+        }
+      }
+    }
+  }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PeerConnectionImpl::CreateOffer(MediaConstraints& constraints) {
+PeerConnectionImpl::CreateOffer(const JS::Value& aConstraints, JSContext* aCx)
+{
+  CheckIceState();
+  mRole = kRoleOfferer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
 
+  MediaConstraints* cs = new MediaConstraints();
+  nsresult rv = ConvertConstraints(aConstraints, cs, aCx);
+  if (rv != NS_OK) {
+    return rv;
+  }
+
+  return CreateOffer(*cs);
+}
+
+// Used by unit tests and the IDL CreateOffer.
+NS_IMETHODIMP
+PeerConnectionImpl::CreateOffer(MediaConstraints& constraints)
+{
   cc_media_constraints_t* cc_constraints = nullptr;
   constraints.buildArray(&cc_constraints);
 
   mCall->createOffer(cc_constraints);
   return NS_OK;
 }
 
-/*
- * the Constraints UI IDL work is being done. The CreateAnswer below is the one
- * currently called by the signaling unit tests.
- *
- * The aOffer parameter needs to be removed here and in the PeerConnection IDL
- */
-
 NS_IMETHODIMP
-PeerConnectionImpl::CreateAnswer(const char* constraints, const char* aOffer) {
-  MOZ_ASSERT(constraints);
-
+PeerConnectionImpl::CreateAnswer(const JS::Value& aConstraints, JSContext* aCx)
+{
   CheckIceState();
   mRole = kRoleAnswerer;  // TODO(ekr@rtfm.com): Interrogate SIPCC here?
-  MediaConstraints aconstraints;
-  CreateAnswer(aconstraints);
+
+  MediaConstraints* cs = new MediaConstraints();
+  nsresult rv = ConvertConstraints(aConstraints, cs, aCx);
+  if (rv != NS_OK) {
+    return rv;
+  }
+
+  CreateAnswer(*cs);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PeerConnectionImpl::CreateAnswer(MediaConstraints& constraints) {
-
+PeerConnectionImpl::CreateAnswer(MediaConstraints& constraints)
+{
   cc_media_constraints_t* cc_constraints = nullptr;
   constraints.buildArray(&cc_constraints);
 
   mCall->createAnswer(cc_constraints);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP) {
+PeerConnectionImpl::SetLocalDescription(int32_t aAction, const char* aSDP)
+{
   if (!aSDP) {
     CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
   CheckIceState();
   mLocalRequestedSDP = aSDP;
   mCall->setLocalDescription((cc_jsep_action_t)aAction, mLocalRequestedSDP);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP) {
+PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
+{
   if (!aSDP) {
     CSFLogError(logTag, "%s - aSDP is NULL", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
   CheckIceState();
   mRemoteRequestedSDP = aSDP;
   mCall->setRemoteDescription((cc_jsep_action_t)action, mRemoteRequestedSDP);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -391,19 +391,22 @@ public:
   // Get the DTLS identity
   mozilla::RefPtr<DtlsIdentity> const GetIdentity() { return mIdentity; }
 
   // Create a fake media stream
   nsresult CreateFakeMediaStream(uint32_t hint, nsIDOMMediaStream** retval);
 
   nsPIDOMWindow* GetWindow() const { return mWindow; }
 
-  NS_IMETHODIMP CreateOffer(MediaConstraints& constraints);
-
-  NS_IMETHODIMP CreateAnswer(MediaConstraints& constraints);
+  // Validate constraints and construct a MediaConstraints object
+  // from a JS::Value.
+  nsresult ConvertConstraints(
+    const JS::Value& aConstraints, MediaConstraints* aObj, JSContext* aCx);
+  NS_IMETHODIMP CreateOffer(MediaConstraints& aConstraints);
+  NS_IMETHODIMP CreateAnswer(MediaConstraints& aConstraints);
 
 private:
   PeerConnectionImpl(const PeerConnectionImpl&rhs);
   PeerConnectionImpl& operator=(PeerConnectionImpl);
 
   void ChangeReadyState(ReadyState aReadyState);
   void CheckIceState() {
     PR_ASSERT(mIceState != kIceGathering);
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -338,17 +338,17 @@ pref("gfx.displayport.strategy_vb.revers
 pref("gfx.displayport.strategy_vb.danger_x_base", -1); // danger zone on x-axis when multiplied by viewport width
 pref("gfx.displayport.strategy_vb.danger_y_base", -1); // danger zone on y-axis when multiplied by viewport height
 pref("gfx.displayport.strategy_vb.danger_x_incr", -1); // additional danger zone on x-axis when multiplied by viewport width and velocity
 pref("gfx.displayport.strategy_vb.danger_y_incr", -1); // additional danger zone on y-axis when multiplied by viewport height and velocity
 
 // prediction bias strategy options
 pref("gfx.displayport.strategy_pb.threshold", -1); // velocity threshold in inches/frame
 
-pref("gfx.java.screenshot.enabled", true);
+pref("gfx.java.screenshot.enabled", false);
 
 // don't allow JS to move and resize existing windows
 pref("dom.disable_window_move_resize", true);
 
 // prevent click image resizing for nsImageDocument
 pref("browser.enable_click_image_resizing", false);
 
 // open in tab preferences
@@ -517,17 +517,17 @@ pref("editor.singleLine.pasteNewlines", 
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with nsEventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 pref("layers.acceleration.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", true);
 pref("layers.async-video.enabled", true);
-pref("layers.progressive-paint", false);
+pref("layers.progressive-paint", true);
 
 pref("notification.feature.enabled", true);
 
 // prevent tooltips from showing up
 pref("browser.chrome.toolbar_tips", false);
 pref("indexedDB.feature.enabled", true);
 pref("dom.indexedDB.warningQuota", 5);
 
@@ -542,17 +542,17 @@ pref("widget.ime.android.landscape_fulls
 pref("widget.ime.android.fullscreen_threshold", 250); // in hundreths of inches
 
 // optimize images memory usage
 pref("image.mem.decodeondraw", true);
 pref("content.image.allow_locking", false);
 pref("image.mem.min_discard_timeout_ms", 10000);
 
 // enable touch events interfaces
-pref("dom.w3c_touch_events.enabled", true);
+pref("dom.w3c_touch_events.enabled", 1);
 
 #ifdef MOZ_SAFE_BROWSING
 pref("browser.safebrowsing.enabled", true);
 pref("browser.safebrowsing.malware.enabled", true);
 pref("browser.safebrowsing.debug", false);
 
 pref("browser.safebrowsing.updateURL", "http://safebrowsing.clients.google.com/safebrowsing/downloads?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
 pref("browser.safebrowsing.keyURL", "https://sb-ssl.google.com/safebrowsing/newkey?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -4,16 +4,17 @@
       package="@ANDROID_PACKAGE_NAME@"
       android:installLocation="auto"
       android:versionCode="@ANDROID_VERSION_CODE@"
       android:versionName="@MOZ_APP_VERSION@"
 #ifdef MOZ_ANDROID_SHARED_ID
       android:sharedUserId="@MOZ_ANDROID_SHARED_ID@"
 #endif
       >
+    <supports-screens android:smallScreens="false" />
     <uses-sdk android:minSdkVersion="8"
               android:targetSdkVersion="14"/>
 
 #include ../services/manifests/AnnouncementsAndroidManifest_permissions.xml.in
 #include ../services/manifests/SyncAndroidManifest_permissions.xml.in
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -801,21 +801,17 @@ abstract public class GeckoApp
     }
 
     void handleLoadError(final int tabId, final String uri, final String title) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
             return;
 
         // When a load error occurs, the URLBar can get corrupt so we reset it
-        mMainHandler.post(new Runnable() {
-            public void run() {
-                Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR);
-            }
-        });
+        Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR);
     }
 
     void handlePageShow(final int tabId) { }
 
     void handleClearHistory() {
         BrowserDB.clearHistory(getContentResolver());
         getFavicons().clearFavicons();
     }
@@ -1182,35 +1178,27 @@ abstract public class GeckoApp
         if (tab == null)
             return;
 
         tab.setState(shouldShowProgress(uri) ? Tab.STATE_SUCCESS : Tab.STATE_LOADING);
         tab.updateIdentityData(null);
         tab.setReaderEnabled(false);
         if (Tabs.getInstance().isSelectedTab(tab))
             mLayerView.getRenderer().resetCheckerboard();
-        mMainHandler.post(new Runnable() {
-            public void run() {
-                Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.START, showProgress);
-            }
-        });
+        Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.START, showProgress);
     }
 
     void handleDocumentStop(int tabId, boolean success) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
             return;
 
         tab.setState(success ? Tab.STATE_SUCCESS : Tab.STATE_ERROR);
 
-        mMainHandler.post(new Runnable() {
-            public void run() {
-                Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.STOP);
-            }
-        });
+        Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.STOP);
 
         final String oldURL = tab.getURL();
         GeckoAppShell.getHandler().postDelayed(new Runnable() {
             public void run() {
                 // tab.getURL() may return null
                 if (!TextUtils.equals(oldURL, tab.getURL()))
                     return;
 
@@ -1245,21 +1233,17 @@ abstract public class GeckoApp
         });
     }
 
     void handleContentLoaded(int tabId) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
             return;
 
-        mMainHandler.post(new Runnable() {
-            public void run() {
-                Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOADED);
-            }
-        });
+        Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOADED);
     }
 
     void handleTitleChanged(int tabId, String title) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
             return;
 
         tab.updateTitle(title);
@@ -1543,16 +1527,29 @@ abstract public class GeckoApp
                 editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false);
                 editor.commit();
             }
         });
     }
 
     protected void initializeChrome(String uri, Boolean isExternalURL) {
         mDoorHangerPopup = new DoorHangerPopup(this, null);
+        mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
+        mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
+
+        if (cameraView == null) {
+            cameraView = new SurfaceView(this);
+            cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+        }
+
+        if (mLayerView == null) {
+            LayerView layerView = (LayerView) findViewById(R.id.layer_view);
+            layerView.initializeView(GeckoAppShell.getEventDispatcher());
+            mLayerView = layerView;
+        }
     }
 
     private void initialize() {
         mInitialized = true;
 
         invalidateOptionsMenu();
 
         Intent intent = getIntent();
@@ -1652,30 +1649,16 @@ abstract public class GeckoApp
             mMainHandler.postDelayed(new Runnable() {
                 public void run() {
                     setLaunchState(LaunchState.Launching);
                     sGeckoThread.start();
                 }
             }, 1000 * 5 /* 5 seconds */);
         }
 
-        if (cameraView == null) {
-            cameraView = new SurfaceView(this);
-            cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
-        }
-
-        if (mLayerView == null) {
-            LayerView layerView = (LayerView) findViewById(R.id.layer_view);
-            layerView.initializeView(GeckoAppShell.getEventDispatcher());
-            mLayerView = layerView;
-        }
-
-        mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
-        mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
-
         //register for events
         registerEventListener("DOMContentLoaded");
         registerEventListener("DOMTitleChanged");
         registerEventListener("DOMLinkAdded");
         registerEventListener("DOMWindowClose");
         registerEventListener("log");
         registerEventListener("Content:SecurityChange");
         registerEventListener("Content:ReaderEnabled");
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -244,16 +244,17 @@ public class GeckoAppShell
     public static native void notifyNoMessageInList(int aRequestId, long aProcessId);
     public static native void notifyListCreated(int aListId, int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyGotNextMessage(int aMessageId, String aReceiver, String aSender, String aBody, long aTimestamp, int aRequestId, long aProcessId);
     public static native void notifyReadingMessageListFailed(int aError, int aRequestId, long aProcessId);
 
     public static native void scheduleComposite();
     public static native void schedulePauseComposition();
     public static native void scheduleResumeComposition(int width, int height);
+    public static native float computeRenderIntegrity();
 
     public static native SurfaceBits getSurfaceBits(Surface surface);
 
     public static native void onFullScreenPluginHidden(View view);
 
     private static class GeckoMediaScannerClient implements MediaScannerConnectionClient {
         private String mFile = "";
         private String mMimeType = "";
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -94,26 +94,27 @@ public class Tab {
         mFaviconLoadId = 0;
         mDocumentURI = "";
         mContentType = "";
         mZoomConstraints = new ZoomConstraints(false);
         mPluginViews = new ArrayList<View>();
         mPluginLayers = new HashMap<Object, Layer>();
         mState = GeckoApp.shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING;
         mContentResolver = Tabs.getInstance().getContentResolver();
-        mContentObserver = new ContentObserver(GeckoAppShell.getHandler()) {
+        mContentObserver = new ContentObserver(null) {
             public void onChange(boolean selfChange) {
                 updateBookmark();
             }
         };
         BrowserDB.registerBookmarkObserver(mContentResolver, mContentObserver);
     }
 
     public void onDestroy() {
         BrowserDB.unregisterContentObserver(mContentResolver, mContentObserver);
+        Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.CLOSED);
     }
 
     public int getId() {
         return mId;
     }
 
     public synchronized void onChange() {
         mLastUsed = System.currentTimeMillis();
@@ -170,36 +171,32 @@ public class Tab {
     }
 
     synchronized void freeBuffer() {
         DirectBufferAllocator.free(mThumbnailBuffer);
         mThumbnailBuffer = null;
     }
 
     public void updateThumbnail(final Bitmap b) {
-        final Tab tab = this;
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
                 if (b != null) {
                     try {
                         mThumbnail = new BitmapDrawable(b);
                         if (mState == Tab.STATE_SUCCESS)
                             saveThumbnailToDB();
                     } catch (OutOfMemoryError oom) {
                         Log.e(LOGTAG, "Unable to create/scale bitmap", oom);
                         mThumbnail = null;
                     }
                 } else {
                     mThumbnail = null;
                 }
-                GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
-                    public void run() {
-                        Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.THUMBNAIL);
-                    }
-                });
+
+                Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.THUMBNAIL);
             }
         });
     }
 
     public synchronized String getFaviconURL() {
         return mFaviconUrl;
     }
 
@@ -260,23 +257,17 @@ public class Tab {
         // Keep the title unchanged while entering reader mode
         if (mEnteringReaderMode)
             return;
 
         mTitle = (title == null ? "" : title);
 
         Log.d(LOGTAG, "Updated title for tab with id: " + mId);
         updateHistory(mUrl, mTitle);
-        final Tab tab = this;
-
-        GeckoAppShell.getMainHandler().post(new Runnable() {
-            public void run() {
-                Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.TITLE);
-            }
-        });
+        Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.TITLE);
     }
 
     protected void addHistory(final String uri) {
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
                 GlobalHistory.getInstance().add(uri);
             }
         });
@@ -355,43 +346,34 @@ public class Tab {
     }
 
     public void updateIdentityData(JSONObject identityData) {
         mIdentityData = identityData;
     }
 
     public void setReaderEnabled(boolean readerEnabled) {
         mReaderEnabled = readerEnabled;
-        GeckoAppShell.getMainHandler().post(new Runnable() {
-            public void run() {
-                Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.MENU_UPDATED);
-            }
-        });
+        Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.MENU_UPDATED);
     }
 
     private void updateBookmark() {
-        final String url = getURL();
-        if (url == null)
-            return;
+        GeckoAppShell.getHandler().post(new Runnable() {
+            public void run() {
+                final String url = getURL();
+                if (url == null)
+                    return;
 
-        (new GeckoAsyncTask<Void, Void, Void>(GeckoApp.mAppContext, GeckoAppShell.getHandler()) {
-            @Override
-            public Void doInBackground(Void... params) {
                 if (url.equals(getURL())) {
                     mBookmark = BrowserDB.isBookmark(mContentResolver, url);
                     mReadingListItem = BrowserDB.isReadingListItem(mContentResolver, url);
                 }
-                return null;
-            }
 
-            @Override
-            public void onPostExecute(Void result) {
                 Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.MENU_UPDATED);
             }
-        }).execute();
+        });
     }
 
     public void addBookmark() {
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
                 String url = getURL();
                 if (url == null)
                     return;
@@ -416,38 +398,16 @@ public class Tab {
     public void addToReadingList() {
         if (!mReaderEnabled)
             return;
 
         GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Add", String.valueOf(getId()));
         GeckoAppShell.sendEventToGecko(e);
     }
 
-    public void removeFromReadingList() {
-        if (!mReaderEnabled)
-            return;
-
-        GeckoAppShell.getHandler().post(new Runnable() {
-            public void run() {
-                String url = getURL();
-                if (url == null)
-                    return;
-
-                BrowserDB.removeReadingListItemWithURL(mContentResolver, url);
-
-                GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
-                    public void run() {
-                        GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", getURL());
-                        GeckoAppShell.sendEventToGecko(e);
-                    }
-                });
-            }
-        });
-    }
-
     public void readerMode() {
         if (!mReaderEnabled)
             return;
 
         mEnteringReaderMode = true;
         Tabs.getInstance().loadUrl(ReaderModeUtils.getAboutReaderForUrl(getURL(), mId, mReadingListItem));
     }
 
@@ -550,21 +510,17 @@ public class Tab {
         clearFavicon();
         updateTitle(null);
         updateIdentityData(null);
         setReaderEnabled(false);
         setZoomConstraints(new ZoomConstraints(true));
         setHasTouchListeners(false);
         setCheckerboardColor(Color.WHITE);
 
-        GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
-            public void run() {
-                Tabs.getInstance().notifyListeners(Tab.this, Tabs.TabEvents.LOCATION_CHANGE, uri);
-            }
-        });
+        Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, uri);
     }
 
     protected void saveThumbnailToDB() {
         try {
             String url = getURL();
             if (url == null)
                 return;
 
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -96,21 +96,17 @@ public class Tabs implements GeckoEventL
 
     private Tab addTab(int id, String url, boolean external, int parentId, String title, boolean isPrivate) {
         final Tab tab = isPrivate ? new PrivateTab(id, url, external, parentId, title) :
                                     new Tab(id, url, external, parentId, title);
         mTabs.put(id, tab);
         mOrder.add(tab);
 
         if (!mRestoringSession) {
-            mActivity.runOnUiThread(new Runnable() {
-                public void run() {
-                    notifyListeners(tab, TabEvents.ADDED);
-                }
-            });
+            notifyListeners(tab, TabEvents.ADDED);
         }
 
         Log.i(LOGTAG, "Added a tab with id: " + id);
         return tab;
     }
 
     public void removeTab(int id) {
         if (mTabs.containsKey(id)) {
@@ -194,22 +190,17 @@ public class Tabs implements GeckoEventL
         if (tab == null || nextTab == null)
             return;
 
         selectTab(nextTab.getId());
 
         int tabId = tab.getId();
         removeTab(tabId);
 
-        mActivity.runOnUiThread(new Runnable() { 
-            public void run() {
-                notifyListeners(tab, TabEvents.CLOSED);
-                tab.onDestroy();
-            }
-        });
+        tab.onDestroy();
 
         // Pass a message to Gecko to update tab state in BrowserApp
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Closed", String.valueOf(tabId)));
     }
 
     /** Return the tab that will be selected by default after this one is closed */
     public Tab getNextTab(Tab tab) {
         Tab selectedTab = getSelectedTab();
@@ -292,21 +283,17 @@ public class Tabs implements GeckoEventL
                 Tab tab = getTab(message.getInt("tabID"));
                 if (tab != null) {
                     tab.handleLocationChange(message);
                 }
             } else if (event.equals("Session:RestoreBegin")) {
                 mRestoringSession = true;
             } else if (event.equals("Session:RestoreEnd")) {
                 mRestoringSession = false;
-                mActivity.runOnUiThread(new Runnable() {
-                    public void run() {
-                        notifyListeners(null, TabEvents.RESTORED);
-                    }
-                });
+                notifyListeners(null, TabEvents.RESTORED);
             } else if (event.equals("Reader:Added")) {
                 final boolean success = message.getBoolean("success");
                 final String title = message.getString("title");
                 final String url = message.getString("url");
                 handleReaderAdded(success, title, url);
             } else if (event.equals("Reader:Removed")) {
                 final String url = message.getString("url");
                 handleReaderRemoved(url);
@@ -393,26 +380,30 @@ public class Tabs implements GeckoEventL
         LOCATION_CHANGE,
         MENU_UPDATED
     }
 
     public void notifyListeners(Tab tab, TabEvents msg) {
         notifyListeners(tab, msg, "");
     }
 
-    public void notifyListeners(Tab tab, TabEvents msg, Object data) {
-        onTabChanged(tab, msg, data);
+    public void notifyListeners(final Tab tab, final TabEvents msg, final Object data) {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                onTabChanged(tab, msg, data);
 
-        if (mTabsChangedListeners == null)
-            return;
+                if (mTabsChangedListeners == null)
+                    return;
 
-        Iterator<OnTabsChangedListener> items = mTabsChangedListeners.iterator();
-        while (items.hasNext()) {
-            items.next().onTabChanged(tab, msg, data);
-        }
+                Iterator<OnTabsChangedListener> items = mTabsChangedListeners.iterator();
+                while (items.hasNext()) {
+                    items.next().onTabChanged(tab, msg, data);
+                }
+            }
+        });
     }
 
     private void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
         switch(msg) {
             case LOCATION_CHANGE:
                 mScore += SCORE_INCREMENT_TAB_LOCATION_CHANGE;
                 break;
 
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -405,22 +405,28 @@ public class LayerRenderer implements Ta
         private long mFrameStartTime;
         // A fixed snapshot of the viewport metrics that this frame is using to render content.
         private ImmutableViewportMetrics mFrameMetrics;
         // A rendering context for page-positioned layers, and one for screen-positioned layers.
         private RenderContext mPageContext, mScreenContext;
         // Whether a layer was updated.
         private boolean mUpdated;
         private final Rect mPageRect;
+        private final Rect mAbsolutePageRect;
 
         public Frame(ImmutableViewportMetrics metrics) {
             mFrameMetrics = metrics;
             mPageContext = createPageContext(metrics);
             mScreenContext = createScreenContext(metrics);
-            mPageRect = getPageRect();
+
+            Point origin = PointUtils.round(mFrameMetrics.getOrigin());
+            Rect pageRect = RectUtils.round(mFrameMetrics.getPageRect());
+            mAbsolutePageRect = new Rect(pageRect);
+            pageRect.offset(-origin.x, -origin.y);
+            mPageRect = pageRect;
         }
 
         private void setScissorRect() {
             Rect scissorRect = transformToScissorRect(mPageRect);
             GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
             GLES20.glScissor(scissorRect.left, scissorRect.top,
                              scissorRect.width(), scissorRect.height());
         }
@@ -432,23 +438,16 @@ public class LayerRenderer implements Ta
             int top = Math.max(0, rect.top);
             int right = Math.min(screenSize.width, rect.right);
             int bottom = Math.min(screenSize.height, rect.bottom);
 
             return new Rect(left, screenSize.height - bottom, right,
                             (screenSize.height - bottom) + (bottom - top));
         }
 
-        private Rect getPageRect() {
-            Point origin = PointUtils.round(mFrameMetrics.getOrigin());
-            Rect pageRect = RectUtils.round(mFrameMetrics.getPageRect());
-            pageRect.offset(-origin.x, -origin.y);
-            return pageRect;
-        }
-
         /** This function is invoked via JNI; be careful when modifying signature. */
         public void beginDrawing() {
             mFrameStartTime = SystemClock.uptimeMillis();
 
             TextureReaper.get().reap();
             TextureGenerator.get().fill();
 
             mUpdated = true;
@@ -538,19 +537,17 @@ public class LayerRenderer implements Ta
             GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT |
                            GLES20.GL_DEPTH_BUFFER_BIT);
 
             /* Draw the background. */
             mBackgroundLayer.setMask(mPageRect);
             mBackgroundLayer.draw(mScreenContext);
 
             /* Draw the drop shadow, if we need to. */
-            RectF untransformedPageRect = new RectF(0.0f, 0.0f, mPageRect.width(),
-                                                    mPageRect.height());
-            if (!untransformedPageRect.contains(mFrameMetrics.getViewport()))
+            if (!new RectF(mAbsolutePageRect).contains(mFrameMetrics.getViewport()))
                 mShadowLayer.draw(mPageContext);
 
             /* Draw the 'checkerboard'. We use gfx.show_checkerboard_pattern to
              * determine whether to draw the screenshot layer.
              */
             if (mView.checkerboardShouldShowChecks()) {
                 /* Find the area the root layer will render into, to mask the checkerboard layer */
                 Rect rootMask = getMaskForLayer(mView.getLayerClient().getRoot());
@@ -602,42 +599,49 @@ public class LayerRenderer implements Ta
             if ((rootLayer != null) &&
                 (mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) {
                 // Find out how much of the viewport area is valid
                 Rect viewport = RectUtils.round(mPageContext.viewport);
                 Region validRegion = rootLayer.getValidRegion(mPageContext);
 
                 /* restrict the viewport to page bounds so we don't
                  * count overscroll as checkerboard */
-                if (!viewport.intersect(mPageRect)) {
+                if (!viewport.intersect(mAbsolutePageRect)) {
                     /* if the rectangles don't intersect
                        intersect() doesn't change viewport
                        so we set it to empty by hand */
                     viewport.setEmpty();
                 }
                 validRegion.op(viewport, Region.Op.INTERSECT);
 
-                float checkerboard = 0.0f;
+                // Check if we have total checkerboarding (there's visible
+                // page area and the valid region doesn't intersect with the
+                // viewport).
+                int screenArea = viewport.width() * viewport.height();
+                float checkerboard = (screenArea > 0 &&
+                  validRegion.quickReject(viewport)) ? 1.0f : 0.0f;
 
-                int screenArea = viewport.width() * viewport.height();
-                if (screenArea > 0 && !(validRegion.isRect() && validRegion.getBounds().equals(viewport))) {
+                if (screenArea > 0 && checkerboard < 1.0f) {
                     validRegion.op(viewport, Region.Op.REVERSE_DIFFERENCE);
 
                     // XXX The assumption here is that a Region never has overlapping
                     //     rects. This is true, as evidenced by reading the SkRegion
                     //     source, but is not mentioned in the Android documentation,
                     //     and so is liable to change.
                     //     If it does change, this code will need to be reevaluated.
                     Rect r = new Rect();
                     int checkerboardArea = 0;
                     for (RegionIterator i = new RegionIterator(validRegion); i.next(r);) {
                         checkerboardArea += r.width() * r.height();
                     }
 
                     checkerboard = checkerboardArea / (float)screenArea;
+
+                    // Add any incomplete rendering in the screen area
+                    checkerboard += (1.0 - checkerboard) * (1.0 - GeckoAppShell.computeRenderIntegrity());
                 }
 
                 PanningPerfAPI.recordCheckerboard(checkerboard);
 
                 mCompleteFramesRendered += 1.0f - checkerboard;
                 mFramesRendered ++;
 
                 if (mFrameStartTime - mProfileOutputTime > 1000) {
--- a/mobile/android/base/tests/BaseTest.java.in
+++ b/mobile/android/base/tests/BaseTest.java.in
@@ -10,17 +10,17 @@ import android.content.ContentValues;
 import android.content.Intent;
 import android.content.res.AssetManager;
 import android.database.Cursor;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import java.io.File;
 import java.io.InputStream;
 import java.io.IOException;
-
+import java.lang.reflect.Method;
 import java.util.HashMap;
 
 /**
  *  A convenient base class suitable for most Robocop tests.
  */
 abstract class BaseTest extends ActivityInstrumentationTestCase2<Activity> {
     public static final int TEST_MOCHITEST = 0;
     public static final int TEST_TALOS = 1;
@@ -35,16 +35,33 @@ abstract class BaseTest extends Activity
     protected Driver mDriver;
     protected Assert mAsserter;
     protected Actions mActions;
     protected String mBaseUrl;
     protected String mRawBaseUrl;
     private String mLogFile;
     protected String mProfile;
 
+    protected void blockForGeckoReady() {
+        try {
+            Actions.EventExpecter geckoReadyExpector = mActions.expectGeckoEvent("Gecko:Ready");
+            ClassLoader classLoader = getActivity().getClassLoader();
+            Class appsCls = classLoader.loadClass("org.mozilla.gecko.GeckoApp");
+            Class launchStateCls = classLoader.loadClass("org.mozilla.gecko.GeckoApp$LaunchState");
+            Method checkLaunchState =  appsCls.getMethod("checkLaunchState", launchStateCls);
+            Object states[] =  launchStateCls.getEnumConstants();
+            Boolean ret = (Boolean)checkLaunchState.invoke(null, states[3]);
+            if (!ret.booleanValue()) {
+	        geckoReadyExpector.blockForEvent();
+            }
+        } catch (Exception e) {
+            mAsserter.dumpLog("Exception in blockForGeckoReady", e);
+        }
+    }
+
     static {
         try {
             mLauncherActivityClass = (Class<Activity>)Class.forName(LAUNCH_ACTIVITY_FULL_CLASSNAME);
         } catch (ClassNotFoundException e) {
             throw new RuntimeException(e);
         }
     }
 
--- a/mobile/android/base/tests/testAboutPage.java.in
+++ b/mobile/android/base/tests/testAboutPage.java.in
@@ -11,17 +11,17 @@ import android.util.Log;
  */
 public class testAboutPage extends PixelTest {
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testAboutPage() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // Load the about: page and verify its title
         String url = "about:";
         loadAndPaint(url);
 
         Element awesomebar = mDriver.findElement(getActivity(), "awesome_bar_title");
         mAsserter.isnot(awesomebar, null, "Got the awesomebar");
         assertMatches(awesomebar.getText(), "About (Fennec|Nightly|Aurora|Firefox|Firefox Beta)", "page title match");
--- a/mobile/android/base/tests/testAddonManager.java.in
+++ b/mobile/android/base/tests/testAddonManager.java.in
@@ -22,17 +22,17 @@ public class testAddonManager extends Pi
 
     /* This test will check the behavior of the Addons Manager:
     First the test will open the Addons Manager from the Menu and then close it
     Then the test will open the Addons Manager by visiting about:addons
     The test will tap/click on the addons.mozilla.org icon to open the AMO page in a new tab
     With the Addons Manager open the test will verify that when it is opened again from the menu no new tab will be opened*/
 
     public void testAddonManager() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // Use the menu to open the Addon Manger
         selectMenuItem("Add-ons");
 
         // Set up listeners to catch the page load we're about to do
         tabEventExpecter = mActions.expectGeckoEvent("Tab:Added");
         contentEventExpecter = mActions.expectGeckoEvent("DOMContentLoaded");
 
--- a/mobile/android/base/tests/testAllPagesTab.java.in
+++ b/mobile/android/base/tests/testAllPagesTab.java.in
@@ -36,17 +36,17 @@ public class testAllPagesTab extends Bas
     };
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testAllPagesTab() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // load one page so there is something in our history
         String url = getAbsoluteUrl("/robocop/robocop_big_link.html");
         loadUrl(url);
 
         testList(url);
         testClick(url);
         testContextMenu(url);
--- a/mobile/android/base/tests/testAwesomebar.java.in
+++ b/mobile/android/base/tests/testAwesomebar.java.in
@@ -5,17 +5,17 @@ import @ANDROID_PACKAGE_NAME@.*;
 
 public class testAwesomebar extends BaseTest {
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testAwesomebar() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
         loadUrl(url);
 
         mDriver.setupScrollHandling();
         // Calculate where we should be dragging.
         int midX = mDriver.getGeckoLeft() + mDriver.getGeckoWidth()/2;
         int midY = mDriver.getGeckoTop() + mDriver.getGeckoHeight()/2;
--- a/mobile/android/base/tests/testAxisLocking.java.in
+++ b/mobile/android/base/tests/testAxisLocking.java.in
@@ -18,17 +18,17 @@ public class testAxisLocking extends Pix
         return TEST_MOCHITEST;
     }
 
     public void testAxisLocking() {
         String url = getAbsoluteUrl("/robocop/robocop_boxes.html");
 
         MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // load page and check we're at 0,0
         loadAndVerifyBoxes(url);
 
         // drag page upwards by 100 pixels with a slight angle. verify that
         // axis locking prevents any horizontal scrolling
         Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
         meh.dragSync(20, 150, 10, 50);
--- a/mobile/android/base/tests/testBookmark.java.in
+++ b/mobile/android/base/tests/testBookmark.java.in
@@ -69,17 +69,17 @@ public class testBookmark extends PixelT
         } catch(java.lang.reflect.InvocationTargetException ex) {
             mAsserter.is(true, false, "Error calling addBookmark");
         }
     }
 
     public void runAwesomeScreenTest() {
         final long PAINT_CLEAR_DELAY = 1000;  // milliseconds
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // Open the bookmark list and check the root folder view
         ListView bookmarksList = openBookmarksList();
 
         // Clear VKB so that list is not obscured
         mActions.sendSpecialKey(Actions.SpecialKey.BACK);
 
         // Wait for bookmark to appear in list
--- a/mobile/android/base/tests/testBookmarklets.java.in
+++ b/mobile/android/base/tests/testBookmarklets.java.in
@@ -16,17 +16,17 @@ public class testBookmarklets extends Pi
     }
 
     public void testBookmarklets() {
         final String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
         final String title = "alertBookmarklet";
         final String js = "javascript:alert(12 + .34)";
         boolean alerted;
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // load a standard page so bookmarklets work
         loadAndPaint(url);
 
         // verify that user-entered bookmarklets do *not* work
         enterUrl(js);
         mActions.sendSpecialKey(Actions.SpecialKey.ENTER);
         alerted = waitForTest(new BooleanTest() {
--- a/mobile/android/base/tests/testBookmarksTab.java.in
+++ b/mobile/android/base/tests/testBookmarksTab.java.in
@@ -36,17 +36,17 @@ public class testBookmarksTab extends Ba
     };
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testBookmarksTab() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
         String url = "http://www.example.com";
 
         // add one page to desktop folders so that we can see them
         addBookmark("BOOKMARK_TITLE", url);
 
         testList(url);
         testContextMenu(url);
     }
--- a/mobile/android/base/tests/testCheck.java.in
+++ b/mobile/android/base/tests/testCheck.java.in
@@ -15,17 +15,17 @@ public class testCheck extends PixelTest
     @Override
     protected int getTestType() {
         return TEST_TALOS;
     }
 
     public void testCheck() {
         String url = getAbsoluteUrl("/startup_test/fennecmark/timecube.html");
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         loadAndPaint(url);
 
         mDriver.setupScrollHandling();
 
         // Setup scrolling coordinates.
         MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
         int midX = mDriver.getGeckoWidth() / 2;
--- a/mobile/android/base/tests/testCheck2.java.in
+++ b/mobile/android/base/tests/testCheck2.java.in
@@ -7,17 +7,17 @@ public class testCheck2 extends PixelTes
     @Override
     protected int getTestType() {
         return TEST_TALOS;
     }
 
     public void testCheck2() {
         String url = getAbsoluteUrl("/startup_test/fennecmark/cnn/cnn.com/index.html");
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
         loadAndPaint(url);
         mDriver.setupScrollHandling();
 
         /*
          * for this test, we load the timecube page, and replay a recorded sequence of events
          * that is a user panning/zooming around the page. specific things in the sequence
          * include:
          * - scroll on one axis followed by scroll on another axis
--- a/mobile/android/base/tests/testCheck3.java.in
+++ b/mobile/android/base/tests/testCheck3.java.in
@@ -18,17 +18,17 @@ public class testCheck3 extends PixelTes
         if (!disableScreenshot()) {
             // if disabling the screenshot fails, there is no point in running
             // this test, so abort. the lack of __start_report output from the
             // end of the test should get picked up as an error by the talos
             // harness.
             return;
         }
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
         loadAndPaint(url);
         mDriver.setupScrollHandling();
 
         /*
          * for this test, we load the timecube page, and replay a recorded sequence of events
          * that is a user panning/zooming around the page. specific things in the sequence
          * include:
          * - scroll on one axis followed by scroll on another axis
--- a/mobile/android/base/tests/testFlingCorrectness.java.in
+++ b/mobile/android/base/tests/testFlingCorrectness.java.in
@@ -16,17 +16,17 @@ public class testFlingCorrectness extend
         return TEST_MOCHITEST;
     }
 
     public void testFlingCorrectness() {
         String url = getAbsoluteUrl("/robocop/robocop_boxes.html");
 
         MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // load page and check we're at 0,0
         loadAndVerifyBoxes(url);
 
         // drag page upwards by 200 pixels (use two drags instead of one in case
         // the screen size is small)
         Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
         meh.dragSync(10, 150, 10, 50);
--- a/mobile/android/base/tests/testFormHistory.java.in
+++ b/mobile/android/base/tests/testFormHistory.java.in
@@ -28,19 +28,18 @@ public class testFormHistory extends Bas
     }
 
     public void testFormHistory() {
         Context context = (Context)getActivity();
         ContentResolver cr = context.getContentResolver();
         ContentValues[] cvs = new ContentValues[1];
         cvs[0] = new ContentValues();
   
-        Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("Gecko:Ready");
-        contentEventExpecter.blockForEvent();
-  
+	blockForGeckoReady();
+
         Uri formHistoryUri;
         Uri insertUri;
         Uri expectedUri;
         int numUpdated;
         int numDeleted;
 
         try {
             ClassLoader classLoader = getActivity().getClassLoader();
--- a/mobile/android/base/tests/testHistory.java.in
+++ b/mobile/android/base/tests/testHistory.java.in
@@ -14,17 +14,17 @@ public class testHistory extends PixelTe
     private View mFirstChild;
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testHistory() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
         String url2 = getAbsoluteUrl("/robocop/robocop_blank_02.html");
         String url3 = getAbsoluteUrl("/robocop/robocop_blank_03.html");
 
         loadAndPaint(url);
         verifyPageTitle("Browser Blank Page 01");
         loadAndPaint(url2);
--- a/mobile/android/base/tests/testHistoryTab.java.in
+++ b/mobile/android/base/tests/testHistoryTab.java.in
@@ -40,17 +40,17 @@ public class testHistoryTab extends Pixe
     private boolean mNearMidnight;
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testHistoryTab() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // very approximate date-rollover detection
         Calendar cal = new GregorianCalendar();
         mNearMidnight = (cal.get(Calendar.HOUR_OF_DAY) == 23);
 
         // load two pages so there is something in our history
         // bookmark one of them
         String url = getAbsoluteUrl("/robocop/robocop_big_link.html");
--- a/mobile/android/base/tests/testLoad.java.in
+++ b/mobile/android/base/tests/testLoad.java.in
@@ -13,15 +13,15 @@ public class testLoad extends PixelTest 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testLoad() {
         String url = getAbsoluteUrl("/robocop/robocop_boxes.html");
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         loadAndVerifyBoxes(url);
 
         verifyUrl(url);
     }
 }
--- a/mobile/android/base/tests/testNewTab.java.in
+++ b/mobile/android/base/tests/testNewTab.java.in
@@ -18,17 +18,17 @@ public class testNewTab extends BaseTest
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testNewTab() {
         String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
         String url2 = getAbsoluteUrl("/robocop/robocop_blank_02.html");
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         Activity activity = getActivity();
         tabCount = mDriver.findElement(activity, "tabs_count");
         tabs = mDriver.findElement(activity, "tabs");
         addTab = mDriver.findElement(activity, "add_tab");
         closeTab = mDriver.findElement(activity, "close");
         mAsserter.ok(tabCount != null &&
                      tabs != null &&
--- a/mobile/android/base/tests/testOverscroll.java.in
+++ b/mobile/android/base/tests/testOverscroll.java.in
@@ -16,17 +16,17 @@ public class testOverscroll extends Pixe
         return TEST_MOCHITEST;
     }
 
     public void testOverscroll() {
         String url = getAbsoluteUrl("/robocop/robocop_boxes.html");
 
         MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // load page and check we're at 0,0
         loadAndVerifyBoxes(url);
 
         // drag page downwards by 100 pixels so that it goes into overscroll.
         // wait for it to bounce back and check we're at the right spot.
         // the screen size is small). Note that since we only go into overscroll
         // and back this should NOT trigger a gecko-paint
--- a/mobile/android/base/tests/testPan.java.in
+++ b/mobile/android/base/tests/testPan.java.in
@@ -12,17 +12,17 @@ public class testPan extends PixelTest {
     @Override
     protected int getTestType() {
         return TEST_TALOS;
     }
 
     public void testPan() {
         String url = getAbsoluteUrl("/startup_test/fennecmark/wikipedia.html");
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         loadAndPaint(url);
 
         mDriver.setupScrollHandling();
 
         // Setup scrolling coordinates.
         int midX = mDriver.getGeckoLeft() + mDriver.getGeckoWidth()/2;
         int midY = mDriver.getGeckoTop() + mDriver.getGeckoHeight()/2;
--- a/mobile/android/base/tests/testPanCorrectness.java.in
+++ b/mobile/android/base/tests/testPanCorrectness.java.in
@@ -16,17 +16,17 @@ public class testPanCorrectness extends 
         return TEST_MOCHITEST;
     }
 
     public void testPanCorrectness() {
         String url = getAbsoluteUrl("/robocop/robocop_boxes.html");
 
         MotionEventHelper meh = new MotionEventHelper(getInstrumentation(), mDriver.getGeckoLeft(), mDriver.getGeckoTop());
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // load page and check we're at 0,0
         loadAndVerifyBoxes(url);
 
         // drag page upwards by 100 pixels
         Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
         meh.dragSync(10, 150, 10, 50);
         PaintedSurface painted = waitForPaint(paintExpecter);
--- a/mobile/android/base/tests/testPasswordEncrypt.java.in
+++ b/mobile/android/base/tests/testPasswordEncrypt.java.in
@@ -22,18 +22,17 @@ public class testPasswordEncrypt extends
     }
 
     public void testPasswordEncrypt() {
       Context context = (Context)getActivity();
       ContentResolver cr = context.getContentResolver();
       mAsserter.isnot(cr, null, "Found a content resolver");
       ContentValues cvs = new ContentValues();
 
-      Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("Gecko:Ready");
-      contentEventExpecter.blockForEvent();
+      blockForGeckoReady();
 
       File db = new File(mProfile, "signons.sqlite");
       String dbPath = db.getPath();
 
       Uri passwordUri;
       try {
           ClassLoader classLoader = getActivity().getClassLoader();
           Class pwds = classLoader.loadClass("org.mozilla.gecko.db.BrowserContract$Passwords");
--- a/mobile/android/base/tests/testPasswordProvider.java.in
+++ b/mobile/android/base/tests/testPasswordProvider.java.in
@@ -26,18 +26,17 @@ public class testPasswordProvider extend
     }
 
     public void testPasswordProvider() {
         Context context = (Context)getActivity();
         ContentResolver cr = context.getContentResolver();
         ContentValues[] cvs = new ContentValues[1];
         cvs[0] = new ContentValues();
   
-        Actions.EventExpecter contentEventExpecter = mActions.expectGeckoEvent("Gecko:Ready");
-        contentEventExpecter.blockForEvent();
+        blockForGeckoReady();
   
         Uri passwordUri;
         try {
             ClassLoader classLoader = getActivity().getClassLoader();
             Class pwds = classLoader.loadClass("org.mozilla.gecko.db.BrowserContract$Passwords");
       
             cvs[0].put("hostname", "http://www.example.com");
             cvs[0].put("httpRealm", "http://www.example.com");
--- a/mobile/android/base/tests/testPermissions.java.in
+++ b/mobile/android/base/tests/testPermissions.java.in
@@ -10,17 +10,17 @@ public class testPermissions extends Pix
     private Actions.RepeatedEventExpecter mPaintExpecter;
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testPermissions() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         geolocationTest();
     }
 
     private void geolocationTest() {
         // Test geolocation notification
         loadAndPaint(getAbsoluteUrl("/robocop/robocop_geolocation.html"));
         mSolo.waitForText("wants your location");
--- a/mobile/android/base/tests/testSearchSuggestions.java.in
+++ b/mobile/android/base/tests/testSearchSuggestions.java.in
@@ -28,17 +28,17 @@ public class testSearchSuggestions exten
     private static final String SUGGESTION_TEMPLATE = "/robocop/robocop_suggestions.sjs?query=__searchTerms__";
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testSearchSuggestions() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // Map of expected values. See robocop_suggestions.sjs.
         final HashMap<String, ArrayList<String>> suggestMap = new HashMap<String, ArrayList<String>>();
         buildSuggestMap(suggestMap);
 
         final int suggestionLayoutId = mDriver.findElement(getActivity(), "suggestion_layout").getId();
         final int suggestionTextId = mDriver.findElement(getActivity(), "suggestion_text").getId();
 
--- a/mobile/android/base/tests/testThumbnails.java.in
+++ b/mobile/android/base/tests/testThumbnails.java.in
@@ -40,17 +40,17 @@ public class testThumbnails extends Base
         final String site1Title = "changeColor";
         final String site2Title = "do404";
 
         // the session snapshot runnable is run 500ms after document stop. a
         // 3000ms delay gives us 2.5 seconds to take the screenshot, which
         // should be plenty of time, even on slow devices
         final int thumbnailDelay = 3000;
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         // load sites; both will return HTTP 200 with a green background
         loadUrl(site1Url);
         mSolo.sleep(thumbnailDelay);
         loadUrl(site2Url);
         mSolo.sleep(thumbnailDelay);
         loadUrl("about:home");
         waitForTest(new ThumbnailTest(site1Title, Color.GREEN), 5000);
--- a/mobile/android/base/tests/testWebContentContextMenu.java.in
+++ b/mobile/android/base/tests/testWebContentContextMenu.java.in
@@ -11,17 +11,17 @@ import android.util.DisplayMetrics;
  */
 public class testWebContentContextMenu extends PixelTest {
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void testWebContentContextMenu() {
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         DisplayMetrics dm = new DisplayMetrics();
         getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
 
         // The link has a 60px height, so let's try to hit the middle
         float top = mDriver.getGeckoTop() + 30 * dm.density;
         float left = mDriver.getGeckoLeft() + mDriver.getGeckoWidth() / 2;
 
--- a/mobile/android/base/tests/test_bug720538.java.in
+++ b/mobile/android/base/tests/test_bug720538.java.in
@@ -8,17 +8,17 @@ public class test_bug720538 extends Pixe
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
     public void test_bug720538() {
         String url = getAbsoluteUrl("/robocop/test_bug720538.html");
 
-        mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
+        blockForGeckoReady();
 
         /*
          * for this test, we load the associated test_bug720538.html file. this file has two
          * iframes (painted completely blue - #0000FF) and the rest of the page is the background
          * color, which is #008000 green. When we first render the page there is an iframe in
          * the top-left corner, and when we double-tap on it it should zoom to fill the visible
          * view area leaving a little bit of space on either side. We can test for this by checking
          * a few pixels to ensure that there is some background visible on either side of the iframe.
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -3579,16 +3579,23 @@ var BrowserEventHandler = {
     document.addEventListener("MozMagnifyGestureStart", this, true);
     document.addEventListener("MozMagnifyGestureUpdate", this, true);
     document.addEventListener("MozMagnifyGesture", this, true);
 
     Services.prefs.addObserver("browser.zoom.reflowOnZoom", this, false);
     this.updateReflozPref();
   },
 
+  resetMaxLineBoxWidth: function() {
+    let webNav = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIWebNavigation);
+    let docShell = webNav.QueryInterface(Ci.nsIDocShell);
+    let docViewer = docShell.contentViewer.QueryInterface(Ci.nsIMarkupDocumentViewer);
+    docViewer.changeMaxLineBoxWidth(0);
+  },
+
   updateReflozPref: function() {
      this.mReflozPref = Services.prefs.getBoolPref("browser.zoom.reflowOnZoom");
   },
 
   handleEvent: function(aEvent) {
     switch (aEvent.type) {
       case 'touchstart':
         this._handleTouchStart(aEvent);
@@ -3742,16 +3749,17 @@ var BrowserEventHandler = {
     } else if (aTopic == "nsPref:changed") {
       if (aData == "browser.zoom.reflowOnZoom") {
         this.updateReflozPref();
       }
     }
   },
 
   _zoomOut: function() {
+    BrowserEventHandler.resetMaxLineBoxWidth();
     sendMessageToJava({ gecko: { type: "Browser:ZoomToPageWidth"} });
   },
 
   _isRectZoomedIn: function(aRect, aViewport) {
     // This function checks to see if the area of the rect visible in the
     // viewport (i.e. the "overlapArea" variable below) is approximately
     // the max area of the rect we can show. It also checks that the rect
     // is actually on-screen by testing the left and right edges of the rect.
@@ -3834,16 +3842,20 @@ var BrowserEventHandler = {
       // the 1.2 multiplier is just a little fuzz to compensate for bRect including horizontal
       // margins but not vertical ones.
       let cssTapY = viewport.cssY + aClickY;
       if ((bRect.height > rect.h) && (cssTapY > rect.y + (rect.h * 1.2))) {
         rect.y = cssTapY - (rect.h / 2);
       }
     }
 
+    if (rect.w > viewport.cssWidth || rect.h > viewport.cssHeight) {
+      BrowserEventHandler.resetMaxLineBoxWidth();
+    }
+
     sendMessageToJava({ gecko: rect });
   },
 
   _zoomInAndSnapToElement: function(aX, aY, aElement) {
     let viewport = BrowserApp.selectedTab.getViewport();
     if (viewport.zoom < 1.0) {
       // We don't want to do this on zoom out.
       return;
--- a/mobile/xul/app/mobile.js
+++ b/mobile/xul/app/mobile.js
@@ -574,17 +574,17 @@ pref("widget.ime.android.landscape_fulls
 pref("widget.ime.android.fullscreen_threshold", 250); // in hundreths of inches
 
 // optimize images memory usage
 pref("image.mem.decodeondraw", true);
 pref("content.image.allow_locking", false);
 pref("image.mem.min_discard_timeout_ms", 10000);
 
 // enable touch events interfaces
-pref("dom.w3c_touch_events.enabled", true);
+pref("dom.w3c_touch_events.enabled", 1);
 pref("dom.w3c_touch_events.safetyX", 5); // escape borders in units of 1/240"
 pref("dom.w3c_touch_events.safetyY", 20); // escape borders in units of 1/240"
 
 #ifdef MOZ_SAFE_BROWSING
 // Safe browsing does nothing unless this pref is set
 pref("browser.safebrowsing.enabled", true);
 
 // Prevent loading of pages identified as malware
--- a/mobile/xul/chrome/content/content.js
+++ b/mobile/xul/chrome/content/content.js
@@ -1361,17 +1361,17 @@ var TouchEventHandler = {
       // first "touchmove" event.  After it's cancelled, it stays cancelled
       // until the next touchstart event.
       if (cancelled || aMessage.name == "Browser:MouseMove")
         this.isCancellable = false;
     }
   },
 
   sendEvent: function(aName, aData, aElement) {
-    if (!Services.prefs.getBoolPref("dom.w3c_touch_events.enabled"))
+    if (!Services.prefs.getIntPref("dom.w3c_touch_events.enabled"))
       return true;
 
     let evt = content.document.createEvent("touchevent");
     let scrollOffset = ContentScroll.getScrollOffset(aElement.ownerDocument.defaultView);
     let point = content.document.createTouch(content, aElement, 0,
                                              aData.x, aData.y, aData.x, aData.y, aData.x - scrollOffset.x, aData.y - scrollOffset.y,
                                              1, 1, 0, 0);
     let touches = content.document.createTouchList(point);
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -914,17 +914,17 @@ pref("network.http.fast-fallback-to-IPv4
 // Try and use SPDY when using SSL
 pref("network.http.spdy.enabled", true);
 pref("network.http.spdy.enabled.v2", true);
 pref("network.http.spdy.enabled.v3", true);
 pref("network.http.spdy.chunk-size", 4096);
 pref("network.http.spdy.timeout", 180);
 pref("network.http.spdy.coalesce-hostnames", true);
 pref("network.http.spdy.use-alternate-protocol", true);
-pref("network.http.spdy.ping-threshold", 44);
+pref("network.http.spdy.ping-threshold", 58);
 pref("network.http.spdy.ping-timeout", 8);
 pref("network.http.spdy.send-buffer-size", 131072);
 
 pref("network.http.diagnostics", false);
 
 // default values for FTP
 // in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
 // Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
@@ -3745,18 +3745,19 @@ pref("dom.mozAlarms.enabled", false);
 // WebNetworkStats
 pref("dom.mozNetworkStats.enabled", false);
 
 // WebSettings
 pref("dom.mozSettings.enabled", false);
 pref("dom.mozPermissionSettings.enabled", false);
 
 // W3C touch events
+// 0 - disabled, 1 - enabled, 2 - autodetect (win)
 #ifdef XP_WIN
-pref("dom.w3c_touch_events.enabled", true);
+pref("dom.w3c_touch_events.enabled", 2);
 #endif
 
 // enable JS dump() function.
 pref("browser.dom.window.dump.enabled", false);
 
 // SPS Profiler
 pref("profiler.enabled", false);
 pref("profiler.interval", 10);
@@ -3805,8 +3806,12 @@ pref("dom.mozApps.dev_mode", false);
 // Lowest localId for apps.
 pref("dom.mozApps.maxLocalId", 1000);
 
 // Minimum delay in milliseconds between network activity notifications (0 means
 // no notifications). The delay is the same for both download and upload, though
 // they are handled separately. This pref is only read once at startup:
 // a restart is required to enable a new value.
 pref("network.activity.blipIntervalMilliseconds", 0);
+
+// When we're asked to take a screenshot, don't wait more than 2000ms for the
+// event loop to become idle before actually taking the screenshot.
+pref("dom.browserElement.maxScreenshotDelayMS", 2000);
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -301,16 +301,17 @@ SHELL_WRAPPER1(onChangeNetworkLinkStatus
 SHELL_WRAPPER1(reportJavaCrash, jstring)
 SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray)
 SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble)
 SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong)
 SHELL_WRAPPER0(bindWidgetTexture)
 SHELL_WRAPPER0(scheduleComposite)
 SHELL_WRAPPER0(schedulePauseComposition)
 SHELL_WRAPPER2(scheduleResumeComposition, jint, jint)
+SHELL_WRAPPER0_WITH_RETURN(computeRenderIntegrity, jfloat)
 SHELL_WRAPPER3_WITH_RETURN(saveMessageInSentbox, jint, jstring, jstring, jlong)
 SHELL_WRAPPER6(notifySmsSent, jint, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER4(notifySmsDelivered, jint, jstring, jstring, jlong)
 SHELL_WRAPPER3(notifySmsSendFailed, jint, jint, jlong)
 SHELL_WRAPPER7(notifyGetSms, jint, jstring, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER3(notifyGetSmsFailed, jint, jint, jlong)
 SHELL_WRAPPER3(notifySmsDeleted, jboolean, jint, jlong)
 SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong)
@@ -724,16 +725,17 @@ loadGeckoLibs(const char *apkName)
   GETFUNC(reportJavaCrash);
   GETFUNC(cameraCallbackBridge);
   GETFUNC(notifyBatteryChange);
   GETFUNC(notifySmsReceived);
   GETFUNC(bindWidgetTexture);
   GETFUNC(scheduleComposite);
   GETFUNC(schedulePauseComposition);
   GETFUNC(scheduleResumeComposition);
+  GETFUNC(computeRenderIntegrity);
   GETFUNC(saveMessageInSentbox);
   GETFUNC(notifySmsSent);
   GETFUNC(notifySmsDelivered);
   GETFUNC(notifySmsSendFailed);
   GETFUNC(notifyGetSms);
   GETFUNC(notifyGetSmsFailed);
   GETFUNC(notifySmsDeleted);
   GETFUNC(notifySmsDeleteFailed);
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -37,22 +37,24 @@
 #include "nsIPermissionManager.h"
 #include "nsTArray.h"
 #include "nsIConsoleService.h"
 #include "nsIUploadChannel2.h"
 #include "nsXULAppAPI.h"
 #include "nsIProxiedChannel.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsICancelable.h"
-
+#include "mozilla/Util.h"
 
 #if defined(XP_WIN) || defined(MOZ_PLATFORM_MAEMO)
 #include "nsNativeConnectionHelper.h"
 #endif
 
+using namespace mozilla;
+
 #define PORT_PREF_PREFIX           "network.security.ports."
 #define PORT_PREF(x)               PORT_PREF_PREFIX x
 #define AUTODIAL_PREF              "network.autodial-helper.enabled"
 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
 
 // Nb: these have been misnomers since bug 715770 removed the buffer cache.
 // "network.segment.count" and "network.segment.size" would be better names,
 // but the old names are still used to preserve backward compatibility.
@@ -687,17 +689,16 @@ nsIOService::SetOffline(bool offline)
             (void)observerService->NotifyObservers(nullptr,
                 NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, offline ? 
                 NS_LITERAL_STRING("true").get() :
                 NS_LITERAL_STRING("false").get());
         }
     }
 
     nsIIOService *subject = static_cast<nsIIOService *>(this);
-    nsresult rv;
     while (mSetOfflineValue != mOffline) {
         offline = mSetOfflineValue;
 
         if (offline && !mOffline) {
             NS_NAMED_LITERAL_STRING(offlineString, NS_IOSERVICE_OFFLINE);
             mOffline = true; // indicate we're trying to shutdown
 
             // don't care if notifications fail
@@ -716,17 +717,17 @@ nsIOService::SetOffline(bool offline)
                 observerService->NotifyObservers(subject,
                                                  NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
                                                  offlineString.get());
         }
         else if (!offline && mOffline) {
             // go online
             if (mDNSService) {
                 mDNSService->SetOffline(false);
-                rv = mDNSService->Init();
+                DebugOnly<nsresult> rv = mDNSService->Init();
                 NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service init failed");
             }
             InitializeSocketTransportService();
             mOffline = false;    // indicate success only AFTER we've
                                     // brought up the services
 
             // trigger a PAC reload when we come back online
             if (mProxyService)
@@ -740,21 +741,21 @@ nsIOService::SetOffline(bool offline)
         }
     }
 
     // Don't notify here, as the above notifications (if used) suffice.
     if (mShutdown && mOffline) {
         // be sure to try and shutdown both (even if the first fails)...
         // shutdown dns service first, because it has callbacks for socket transport
         if (mDNSService) {
-            rv = mDNSService->Shutdown();
+            DebugOnly<nsresult> rv = mDNSService->Shutdown();
             NS_ASSERTION(NS_SUCCEEDED(rv), "DNS service shutdown failed");
         }
         if (mSocketTransportService) {
-            rv = mSocketTransportService->Shutdown();
+            DebugOnly<nsresult> rv = mSocketTransportService->Shutdown();
             NS_ASSERTION(NS_SUCCEEDED(rv), "socket transport service shutdown failed");
         }
     }
 
     mSettingOffline = false;
 
     return NS_OK;
 }
--- a/netwerk/base/src/nsLoadGroup.cpp
+++ b/netwerk/base/src/nsLoadGroup.cpp
@@ -13,16 +13,17 @@
 #include "prlog.h"
 #include "nsCRT.h"
 #include "netCore.h"
 #include "nsXPIDLString.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/Util.h"
 
 using namespace mozilla;
 
 #if defined(PR_LOGGING)
 //
 // Log module for nsILoadGroup logging...
 //
 // To enable logging (see prlog.h for full details):
@@ -127,19 +128,17 @@ nsLoadGroup::nsLoadGroup(nsISupports* ou
     // Initialize the ops in the hash to null to make sure we get
     // consistent errors if someone fails to call ::Init() on an
     // nsLoadGroup.
     mRequests.ops = nullptr;
 }
 
 nsLoadGroup::~nsLoadGroup()
 {
-    nsresult rv;
-
-    rv = Cancel(NS_BINDING_ABORTED);
+    DebugOnly<nsresult> rv = Cancel(NS_BINDING_ABORTED);
     NS_ASSERTION(NS_SUCCEEDED(rv), "Cancel failed");
 
     if (mRequests.ops) {
         PL_DHashTableFinish(&mRequests);
     }
 
     mDefaultLoadRequest = 0;
 
--- a/netwerk/base/src/nsRequestObserverProxy.cpp
+++ b/netwerk/base/src/nsRequestObserverProxy.cpp
@@ -6,16 +6,19 @@
 #include "nscore.h"
 #include "nsRequestObserverProxy.h"
 #include "nsIRequest.h"
 #include "nsIServiceManager.h"
 #include "nsProxyRelease.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "prlog.h"
+#include "mozilla/Util.h"
+
+using namespace mozilla;
 
 #if defined(PR_LOGGING)
 static PRLogModuleInfo *gRequestObserverProxyLog;
 #endif
 
 #define LOG(args) PR_LOG(gRequestObserverProxyLog, PR_LOG_DEBUG, args)
 
 //-----------------------------------------------------------------------------
@@ -85,29 +88,28 @@ public:
     {
         NS_PRECONDITION(mProxy, "null pointer");
     }
 
     virtual ~nsOnStopRequestEvent() {}
 
     NS_IMETHOD Run()
     {
-        nsresult rv, status = NS_OK;
-
         LOG(("nsOnStopRequestEvent::HandleEvent [req=%x]\n", mRequest.get()));
 
         nsCOMPtr<nsIRequestObserver> observer = mProxy->mObserver;
         if (!observer) {
             NS_NOTREACHED("already handled onStopRequest event (observer is null)");
             return NS_OK;
         }
         // Do not allow any more events to be handled after OnStopRequest
         mProxy->mObserver = 0;
 
-        rv = mRequest->GetStatus(&status);
+        nsresult status = NS_OK;
+        DebugOnly<nsresult> rv = mRequest->GetStatus(&status);
         NS_ASSERTION(NS_SUCCEEDED(rv), "GetStatus failed for request!");
 
         LOG(("handle stopevent=%p\n", this));
         (void) observer->OnStopRequest(mRequest, mContext, status);
 
         return NS_OK;
     }
 };
--- a/netwerk/cache/nsDiskCacheDevice.cpp
+++ b/netwerk/cache/nsDiskCacheDevice.cpp
@@ -41,16 +41,17 @@
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsCRT.h"
 #include "nsCOMArray.h"
 #include "nsISimpleEnumerator.h"
 
 #include "nsThreadUtils.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/Util.h"
 
 static const char DISK_CACHE_DEVICE_ID[] = { "disk" };
 using namespace mozilla;
 
 class nsDiskCacheDeviceDeactivateEntryEvent : public nsRunnable {
 public:
     nsDiskCacheDeviceDeactivateEntryEvent(nsDiskCacheDevice *device,
                                           nsCacheEntry * entry,
@@ -531,31 +532,30 @@ nsDiskCacheDevice::FindEntry(nsCString *
 
 
 /**
  *  NOTE: called while holding the cache service lock
  */
 nsresult
 nsDiskCacheDevice::DeactivateEntry(nsCacheEntry * entry)
 {
-    nsresult              rv = NS_OK;
     nsDiskCacheBinding * binding = GetCacheEntryBinding(entry);
     if (!IsValidBinding(binding))
         return NS_ERROR_UNEXPECTED;
 
     CACHE_LOG_DEBUG(("CACHE: disk DeactivateEntry [%p %x]\n",
         entry, binding->mRecord.HashNumber()));
 
     nsDiskCacheDeviceDeactivateEntryEvent *event =
         new nsDiskCacheDeviceDeactivateEntryEvent(this, entry, binding);
 
     // ensure we can cancel the event via the binding later if necessary
     binding->mDeactivateEvent = event;
 
-    rv = nsCacheService::DispatchToCacheIOThread(event);
+    DebugOnly<nsresult> rv = nsCacheService::DispatchToCacheIOThread(event);
     NS_ASSERTION(NS_SUCCEEDED(rv), "DeactivateEntry: Failed dispatching "
                                    "deactivation event");
     return NS_OK;
 }
 
 /**
  *  NOTE: called while holding the cache service lock
  */
--- a/netwerk/cookie/nsCookieService.cpp
+++ b/netwerk/cookie/nsCookieService.cpp
@@ -460,21 +460,20 @@ public:
     , mCanceled(false)
   {
   }
 
   void Cancel() { mCanceled = true; }
 
   NS_IMETHOD HandleResult(mozIStorageResultSet *aResult)
   {
-    nsresult rv;
     nsCOMPtr<mozIStorageRow> row;
 
     while (1) {
-      rv = aResult->GetNextRow(getter_AddRefs(row));
+      DebugOnly<nsresult> rv = aResult->GetNextRow(getter_AddRefs(row));
       NS_ASSERT_SUCCESS(rv);
 
       if (!row)
         break;
 
       CookieDomainTuple *tuple = mDBState->hostArray.AppendElement();
       row->GetUTF8String(9, tuple->key.mBaseDomain);
       tuple->key.mAppId = static_cast<uint32_t>(row->AsInt32(10));
@@ -1418,17 +1417,17 @@ nsCookieService::RebuildCorruptDB(DBStat
   if (length == 0) {
     COOKIE_LOGSTRING(PR_LOG_DEBUG,
       ("RebuildCorruptDB(): nothing to write, rebuild complete"));
     mDefaultDBState->corruptFlag = DBState::OK;
     return;
   }
 
   // Execute the statement. If any errors crop up, we won't try again.
-  nsresult rv = stmt->BindParameters(paramsArray);
+  DebugOnly<nsresult> rv = stmt->BindParameters(paramsArray);
   NS_ASSERT_SUCCESS(rv);
   nsCOMPtr<mozIStoragePendingStatement> handle;
   rv = stmt->ExecuteAsync(aDBState->insertListener, getter_AddRefs(handle));
   NS_ASSERT_SUCCESS(rv);    
 }
 
 nsCookieService::~nsCookieService()
 {
@@ -1971,17 +1970,17 @@ nsCookieService::Read()
 
 // Extract data from a single result row and create an nsCookie.
 // This is templated since 'T' is different for sync vs async results.
 template<class T> nsCookie*
 nsCookieService::GetCookieFromRow(T &aRow)
 {
   // Skip reading 'baseDomain' -- up to the caller.
   nsCString name, value, host, path;
-  nsresult rv = aRow->GetUTF8String(0, name);
+  DebugOnly<nsresult> rv = aRow->GetUTF8String(0, name);
   NS_ASSERT_SUCCESS(rv);
   rv = aRow->GetUTF8String(1, value);
   NS_ASSERT_SUCCESS(rv);
   rv = aRow->GetUTF8String(2, host);
   NS_ASSERT_SUCCESS(rv);
   rv = aRow->GetUTF8String(3, path);
   NS_ASSERT_SUCCESS(rv);
 
@@ -2047,17 +2046,17 @@ nsCookieService::CancelAsyncRead(bool aP
   // mode.) As long as we do all our operations on the default state, we're OK.
   NS_ASSERTION(mDefaultDBState, "no default DBState");
   NS_ASSERTION(mDefaultDBState->pendingRead, "no pending read");
   NS_ASSERTION(mDefaultDBState->readListener, "no read listener");
 
   // Cancel the pending read, kill the read listener, and empty the array
   // of data already read in on the background thread.
   mDefaultDBState->readListener->Cancel();
-  mozilla::DebugOnly<nsresult> rv = mDefaultDBState->pendingRead->Cancel();
+  DebugOnly<nsresult> rv = mDefaultDBState->pendingRead->Cancel();
   NS_ASSERT_SUCCESS(rv);
 
   mDefaultDBState->stmtReadDomain = nullptr;
   mDefaultDBState->pendingRead = nullptr;
   mDefaultDBState->readListener = nullptr;
   mDefaultDBState->hostArray.Clear();
 
   // Only clear the 'readSet' table if we no longer need to know what set of
@@ -2597,17 +2596,17 @@ nsCookieService::GetCookieStringInternal
       if (currentTimeInUsec - cookie->LastAccessed() > kCookieStaleThreshold)
         UpdateCookieInList(cookie, currentTimeInUsec, paramsArray);
     }
     // Update the database now if necessary.
     if (paramsArray) {
       uint32_t length;
       paramsArray->GetLength(&length);
       if (length) {
-        nsresult rv = stmt->BindParameters(paramsArray);
+        DebugOnly<nsresult> rv = stmt->BindParameters(paramsArray);
         NS_ASSERT_SUCCESS(rv);
         nsCOMPtr<mozIStoragePendingStatement> handle;
         rv = stmt->ExecuteAsync(mDBState->updateListener,
           getter_AddRefs(handle));
         NS_ASSERT_SUCCESS(rv);
       }
     }
   }
@@ -3615,17 +3614,17 @@ nsCookieService::PurgeCookies(int64_t aC
     RemoveCookieFromList(purgeList[i], paramsArray);
   }
 
   // Update the database if we have entries to purge.
   if (paramsArray) {
     uint32_t length;
     paramsArray->GetLength(&length);
     if (length) {
-      nsresult rv = stmt->BindParameters(paramsArray);
+      DebugOnly<nsresult> rv = stmt->BindParameters(paramsArray);
       NS_ASSERT_SUCCESS(rv);
       nsCOMPtr<mozIStoragePendingStatement> handle;
       rv = stmt->ExecuteAsync(mDBState->removeListener, getter_AddRefs(handle));
       NS_ASSERT_SUCCESS(rv);
     }
   }
 
   // reset the oldest time indicator
@@ -4053,17 +4052,17 @@ nsCookieService::AddCookieToList(const n
     if (!paramsArray) {
       stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
     }
     bindCookieParameters(paramsArray, aKey, aCookie);
 
     // If we were supplied an array to store parameters, we shouldn't call
     // executeAsync - someone up the stack will do this for us.
     if (!aParamsArray) {
-      nsresult rv = stmt->BindParameters(paramsArray);
+      DebugOnly<nsresult> rv = stmt->BindParameters(paramsArray);
       NS_ASSERT_SUCCESS(rv);
       nsCOMPtr<mozIStoragePendingStatement> handle;
       rv = stmt->ExecuteAsync(mDBState->insertListener, getter_AddRefs(handle));
       NS_ASSERT_SUCCESS(rv);
     }
   }
 }
 
@@ -4079,18 +4078,19 @@ nsCookieService::UpdateCookieInList(nsCo
 
   // if it's a non-session cookie, update it in the db too
   if (!aCookie->IsSession() && aParamsArray) {
     // Create our params holder.
     nsCOMPtr<mozIStorageBindingParams> params;
     aParamsArray->NewBindingParams(getter_AddRefs(params));
 
     // Bind our parameters.
-    nsresult rv = params->BindInt64ByName(NS_LITERAL_CSTRING("lastAccessed"),
-                                          aLastAccessed);
+    DebugOnly<nsresult> rv =
+      params->BindInt64ByName(NS_LITERAL_CSTRING("lastAccessed"),
+                              aLastAccessed);
     NS_ASSERT_SUCCESS(rv);
 
     rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("name"),
                                       aCookie->Name());
     NS_ASSERT_SUCCESS(rv);
 
     rv = params->BindUTF8StringByName(NS_LITERAL_CSTRING("host"),
                                       aCookie->Host());
--- a/netwerk/dns/effective_tld_names.dat
+++ b/netwerk/dns/effective_tld_names.dat
@@ -214,17 +214,16 @@ or.at
 // au : http://en.wikipedia.org/wiki/.au
 // http://www.auda.org.au/
 // 2LDs
 com.au
 net.au
 org.au
 edu.au
 gov.au
-csiro.au
 asn.au
 id.au
 // Historic 2LDs (closed to new registration, but sites still exist)
 info.au
 conf.au
 oz.au
 // CGDNs - http://www.cgdn.org.au/
 act.au
@@ -4167,16 +4166,17 @@ net.my
 org.my
 gov.my
 edu.my
 mil.my
 name.my
 
 // mz : http://www.gobin.info/domainname/mz-template.doc
 *.mz
+!teledata.mz
 
 // na : http://www.na-nic.com.na/
 // http://www.info.na/domain/
 na
 info.na
 pro.na
 name.na
 school.na
@@ -5360,18 +5360,27 @@ nome.pt
 pw
 co.pw
 ne.pw
 or.pw
 ed.pw
 go.pw
 belau.pw
 
-// py : http://www.nic.py/faq_a.html#faq_b
-*.py
+// py : http://www.nic.py/pautas.html#seccion_9
+// Confirmed by registry 2012-10-03
+com.py
+coop.py
+edu.py
+gov.py
+mil.py
+net.py
+org.py
+!nic.py
+!una.py
 
 // qa : http://domains.qa/en/
 qa
 com.qa
 edu.qa
 gov.qa
 mil.qa
 name.qa
@@ -6575,18 +6584,61 @@ us.org
 uy.com
 za.com
 
 // Opera Software, A.S.A.
 // Requested by Yngve Pettersen <yngve@opera.com> 2009-11-26
 operaunite.com
 
 // Google, Inc.
-// Requested by Eduardo Vela <evn@google.com> 2010-09-06
+// Requested by Eduardo Vela <evn@google.com> 2012-10-24
 appspot.com
+blogspot.be
+blogspot.bj
+blogspot.ca
+blogspot.cf
+blogspot.ch
+blogspot.co.at
+blogspot.co.il
+blogspot.co.nz
+blogspot.co.uk
+blogspot.com
+blogspot.com.ar
+blogspot.com.au
+blogspot.com.br
+blogspot.com.es
+blogspot.cv
+blogspot.cz
+blogspot.de
+blogspot.dk
+blogspot.fi
+blogspot.fr
+blogspot.gr
+blogspot.hk
+blogspot.hu
+blogspot.ie
+blogspot.in
+blogspot.it
+blogspot.jp
+blogspot.kr
+blogspot.mr
+blogspot.mx
+blogspot.nl
+blogspot.no
+blogspot.pt
+blogspot.re
+blogspot.ro
+blogspot.se
+blogspot.sg
+blogspot.sk
+blogspot.td
+blogspot.tw
+codespot.com
+googleapis.com
+googlecode.com
 
 // DreamHost : http://www.dreamhost.com/
 // Requested by Andrew Farmer <andrew.farmer@dreamhost.com> 2012-10-02
 dreamhosters.com
 
 // iki.fi : Submitted by Hannu Aronsson <haa@iki.fi> 2009-11-05
 iki.fi
 
@@ -6882,9 +6934,17 @@ thruhere.net
 traeumtgerade.de
 webhop.biz
 webhop.info
 webhop.net
 webhop.org
 worse-than.tv
 writesthisblog.com
 
+// BetaInABox
+// Requested by adrian@betainabox.com 2012-09-13
+betainabox.com
+
+// Red Hat, Inc. OpenShift : https://openshift.redhat.com/
+// Requested by Tim Kramer <tkramer@rhcloud.com> 2012-10-24
+rhcloud.com
+
 // ===END PRIVATE DOMAINS===
--- a/netwerk/protocol/http/SpdySession2.cpp
+++ b/netwerk/protocol/http/SpdySession2.cpp
@@ -55,18 +55,17 @@ SpdySession2::SpdySession2(nsAHttpTransa
     mMaxConcurrent(kDefaultMaxConcurrent),
     mConcurrent(0),
     mServerPushedResources(0),
     mOutputQueueSize(kDefaultQueueSize),
     mOutputQueueUsed(0),
     mOutputQueueSent(0),
     mLastReadEpoch(PR_IntervalNow()),
     mPingSentEpoch(0),
-    mNextPingID(1),
-    mPingThresholdExperiment(false)
+    mNextPingID(1)
 {
   NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
 
   LOG3(("SpdySession2::SpdySession2 %p transaction 1 = %p",
         this, aHttpTransaction));
   
   mStreamIDHash.Init();
   mStreamTransactionHash.Init();
@@ -76,50 +75,17 @@ SpdySession2::SpdySession2(nsAHttpTransa
   mOutputQueueBuffer = new char[mOutputQueueSize];
   zlibInit();
   
   mSendingChunkSize = gHttpHandler->SpdySendingChunkSize();
   if (!aHttpTransaction->IsNullTransaction())
     AddStream(aHttpTransaction, firstPriority);
   mLastDataReadEpoch = mLastReadEpoch;
   
-  DeterminePingThreshold();
-}
-
-void
-SpdySession2::DeterminePingThreshold()
-{
   mPingThreshold = gHttpHandler->SpdyPingThreshold();
-
-  if (!mPingThreshold || !gHttpHandler->AllowExperiments())
-    return;
-
-  uint32_t randomVal = gHttpHandler->Get32BitsOfPseudoRandom();
-  
-  // Use the lower 10 bits to select 1 in 1024 sessions for the
-  // ping threshold experiment. Somewhat less than that will actually be
-  // used because random values greater than the total http idle timeout
-  // for the session are discarded.
-  if ((randomVal & 0x3ff) != 1)  // lottery
-    return;
-  
-  randomVal = randomVal >> 10; // those bits are used up
-
-  // This session has been selected - use a random ping threshold of 10 +
-  // a random number from 0 to 255, based on the next 8 bits of the
-  // random buffer
-  PRIntervalTime randomThreshold =
-    PR_SecondsToInterval((randomVal & 0xff) + 10);
-  if (randomThreshold > gHttpHandler->IdleTimeout())
-    return;
-  
-  mPingThreshold = randomThreshold;
-  mPingThresholdExperiment = true;
-  LOG3(("SpdySession2 %p Ping Threshold Experimental Selection : %dsec\n",
-        this, PR_IntervalToSeconds(mPingThreshold)));
 }
 
 PLDHashOperator
 SpdySession2::ShutdownEnumerator(nsAHttpTransaction *key,
                                 nsAutoPtr<SpdyStream2> &stream,
                                 void *closure)
 {
   SpdySession2 *self = static_cast<SpdySession2 *>(closure);
@@ -236,26 +202,26 @@ SpdySession2::ReadTimeoutTick(PRInterval
       return;
 
     LOG(("SpdySession2::ReadTimeoutTick %p delta since last read %ds\n",
          this, PR_IntervalToSeconds(now - mLastReadEpoch)));
 
     if ((now - mLastReadEpoch) < mPingThreshold) {
       // recent activity means ping is not an issue
       if (mPingSentEpoch)
-        ClearPing(true);
+        mPingSentEpoch = 0;
       return;
     }
 
     if (mPingSentEpoch) {
       LOG(("SpdySession2::ReadTimeoutTick %p handle outstanding ping\n"));
       if ((now - mPingSentEpoch) >= gHttpHandler->SpdyPingTimeout()) {
         LOG(("SpdySession2::ReadTimeoutTick %p Ping Timer Exhaustion\n",
              this));
-        ClearPing(false);
+        mPingSentEpoch = 0;
         Close(NS_ERROR_NET_TIMEOUT);
       }
       return;
     }
     
     LOG(("SpdySession2::ReadTimeoutTick %p generating ping 0x%x\n",
          this, mNextPingID));
 
@@ -274,37 +240,16 @@ SpdySession2::ReadTimeoutTick(PRInterval
 
     if (mNextPingID == 0xffffffff) {
       LOG(("SpdySession2::ReadTimeoutTick %p "
            "ping ids exhausted marking goaway\n", this));
       mShouldGoAway = true;
     }
 }
 
-void
-SpdySession2::ClearPing(bool pingOK)
-{
-  mPingSentEpoch = 0;
-
-  if (mPingThresholdExperiment) {
-    LOG3(("SpdySession2::ClearPing %p mPingThresholdExperiment %dsec %s\n",
-          this, PR_IntervalToSeconds(mPingThreshold),
-          pingOK ? "pass" :"fail"));
-
-    if (pingOK)
-      Telemetry::Accumulate(Telemetry::SPDY_PING_EXPERIMENT_PASS,
-                            PR_IntervalToSeconds(mPingThreshold));
-    else
-      Telemetry::Accumulate(Telemetry::SPDY_PING_EXPERIMENT_FAIL,
-                            PR_IntervalToSeconds(mPingThreshold));
-    mPingThreshold = gHttpHandler->SpdyPingThreshold();
-    mPingThresholdExperiment = false;
-  }
-}
-
 uint32_t
 SpdySession2::RegisterStreamID(SpdyStream2 *stream)
 {
   NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
 
   LOG3(("SpdySession2::RegisterStreamID session=%p stream=%p id=0x%X "
         "concurrent=%d",this, stream, mNextStreamID, mConcurrent));
 
@@ -1337,17 +1282,17 @@ SpdySession2::HandlePing(SpdySession2 *s
 
   uint32_t pingID =
     PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
 
   LOG3(("SpdySession2::HandlePing %p PING ID 0x%X.", self, pingID));
 
   if (pingID & 0x01) {
     // presumably a reply to our timeout ping
-    self->ClearPing(true);
+    self->mPingSentEpoch = 0;
   }
   else {
     // Servers initiate even numbered pings, go ahead and echo it back
     self->GeneratePing(pingID);
   }
     
   self->ResetDownstreamState();
   return NS_OK;
--- a/netwerk/protocol/http/SpdySession2.h
+++ b/netwerk/protocol/http/SpdySession2.h
@@ -163,28 +163,26 @@ private:
     BUFFERING_FRAME_HEADER,
     BUFFERING_CONTROL_FRAME,
     PROCESSING_DATA_FRAME,
     DISCARDING_DATA_FRAME,
     PROCESSING_CONTROL_SYN_REPLY,
     PROCESSING_CONTROL_RST_STREAM
   };
 
-  void        DeterminePingThreshold();
   nsresult    HandleSynReplyForValidStream();
   uint32_t    GetWriteQueueSize();
   void        ChangeDownstreamState(enum stateType);
   void        ResetDownstreamState();
   nsresult    DownstreamUncompress(char *, uint32_t);
   void        zlibInit();
   nsresult    FindHeader(nsCString, nsDependentCSubstring &);
   nsresult    ConvertHeaders(nsDependentCSubstring &,
                              nsDependentCSubstring &);
   void        GeneratePing(uint32_t);
-  void        ClearPing(bool);
   void        GenerateRstStream(uint32_t, uint32_t);
   void        GenerateGoAway();
   void        CleanupStream(SpdyStream2 *, nsresult, rstReason);
   void        CloseStream(SpdyStream2 *, nsresult);
 
   void        SetWriteCallbacks();
   void        FlushOutputQueue();
 
@@ -331,14 +329,13 @@ private:
   uint32_t             mOutputQueueSent;
   nsAutoArrayPtr<char> mOutputQueueBuffer;
 
   PRIntervalTime       mPingThreshold;
   PRIntervalTime       mLastReadEpoch;     // used for ping timeouts
   PRIntervalTime       mLastDataReadEpoch; // used for IdleTime()
   PRIntervalTime       mPingSentEpoch;
   uint32_t             mNextPingID;
-  bool                 mPingThresholdExperiment;
 };
 
 }} // namespace mozilla::net
 
 #endif // mozilla_net_SpdySession2_h
--- a/netwerk/protocol/http/SpdySession3.cpp
+++ b/netwerk/protocol/http/SpdySession3.cpp
@@ -55,18 +55,17 @@ SpdySession3::SpdySession3(nsAHttpTransa
     mConcurrent(0),
     mServerPushedResources(0),
     mServerInitialWindow(kDefaultServerRwin),
     mOutputQueueSize(kDefaultQueueSize),
     mOutputQueueUsed(0),
     mOutputQueueSent(0),
     mLastReadEpoch(PR_IntervalNow()),
     mPingSentEpoch(0),
-    mNextPingID(1),
-    mPingThresholdExperiment(false)
+    mNextPingID(1)
 {
   NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
 
   LOG3(("SpdySession3::SpdySession3 %p transaction 1 = %p",
         this, aHttpTransaction));
   
   mStreamIDHash.Init();
   mStreamTransactionHash.Init();
@@ -77,50 +76,17 @@ SpdySession3::SpdySession3(nsAHttpTransa
   
   mSendingChunkSize = gHttpHandler->SpdySendingChunkSize();
   GenerateSettings();
 
   if (!aHttpTransaction->IsNullTransaction())
     AddStream(aHttpTransaction, firstPriority);
   mLastDataReadEpoch = mLastReadEpoch;
   
-  DeterminePingThreshold();
-}
-
-void
-SpdySession3::DeterminePingThreshold()
-{
   mPingThreshold = gHttpHandler->SpdyPingThreshold();
-
-  if (!mPingThreshold || !gHttpHandler->AllowExperiments())
-    return;
-
-  uint32_t randomVal = gHttpHandler->Get32BitsOfPseudoRandom();
-  
-  // Use the lower 10 bits to select 1 in 1024 sessions for the
-  // ping threshold experiment. Somewhat less than that will actually be
-  // used because random values greater than the total http idle timeout
-  // for the session are discarded.
-  if ((randomVal & 0x3ff) != 1)  // lottery
-    return;
-  
-  randomVal = randomVal >> 10; // those bits are used up
-
-  // This session has been selected - use a random ping threshold of 10 +
-  // a random number from 0 to 255, based on the next 8 bits of the
-  // random buffer
-  PRIntervalTime randomThreshold =
-    PR_SecondsToInterval((randomVal & 0xff) + 10);
-  if (randomThreshold > gHttpHandler->IdleTimeout())
-    return;
-  
-  mPingThreshold = randomThreshold;
-  mPingThresholdExperiment = true;
-  LOG3(("SpdySession3 %p Ping Threshold Experimental Selection : %dsec\n",
-        this, PR_IntervalToSeconds(mPingThreshold)));
 }
 
 PLDHashOperator
 SpdySession3::ShutdownEnumerator(nsAHttpTransaction *key,
                                 nsAutoPtr<SpdyStream3> &stream,
                                 void *closure)
 {
   SpdySession3 *self = static_cast<SpdySession3 *>(closure);
@@ -237,26 +203,26 @@ SpdySession3::ReadTimeoutTick(PRInterval
       return;
 
     LOG(("SpdySession3::ReadTimeoutTick %p delta since last read %ds\n",
          this, PR_IntervalToSeconds(now - mLastReadEpoch)));
 
     if ((now - mLastReadEpoch) < mPingThreshold) {
       // recent activity means ping is not an issue
       if (mPingSentEpoch)
-        ClearPing(true);
+        mPingSentEpoch = 0;
       return;
     }
 
     if (mPingSentEpoch) {
       LOG(("SpdySession3::ReadTimeoutTick %p handle outstanding ping\n"));
       if ((now - mPingSentEpoch) >= gHttpHandler->SpdyPingTimeout()) {
         LOG(("SpdySession3::ReadTimeoutTick %p Ping Timer Exhaustion\n",
              this));
-        ClearPing(false);
+        mPingSentEpoch = 0;
         Close(NS_ERROR_NET_TIMEOUT);
       }
       return;
     }
     
     LOG(("SpdySession3::ReadTimeoutTick %p generating ping 0x%X\n",
          this, mNextPingID));
 
@@ -275,37 +241,16 @@ SpdySession3::ReadTimeoutTick(PRInterval
 
     if (mNextPingID == 0xffffffff) {
       LOG(("SpdySession3::ReadTimeoutTick %p "
            "ping ids exhausted marking goaway\n", this));
       mShouldGoAway = true;
     }
 }
 
-void
-SpdySession3::ClearPing(bool pingOK)
-{
-  mPingSentEpoch = 0;
-
-  if (mPingThresholdExperiment) {
-    LOG3(("SpdySession3::ClearPing %p mPingThresholdExperiment %dsec %s\n",
-          this, PR_IntervalToSeconds(mPingThreshold),
-          pingOK ? "pass" :"fail"));
-
-    if (pingOK)
-      Telemetry::Accumulate(Telemetry::SPDY_PING_EXPERIMENT_PASS,
-                            PR_IntervalToSeconds(mPingThreshold));
-    else
-      Telemetry::Accumulate(Telemetry::SPDY_PING_EXPERIMENT_FAIL,
-                            PR_IntervalToSeconds(mPingThreshold));
-    mPingThreshold = gHttpHandler->SpdyPingThreshold();
-    mPingThresholdExperiment = false;
-  }
-}
-
 uint32_t
 SpdySession3::RegisterStreamID(SpdyStream3 *stream)
 {
   NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
 
   LOG3(("SpdySession3::RegisterStreamID session=%p stream=%p id=0x%X "
         "concurrent=%d",this, stream, mNextStreamID, mConcurrent));
 
@@ -1211,17 +1156,17 @@ SpdySession3::HandlePing(SpdySession3 *s
 
   uint32_t pingID =
     PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
 
   LOG3(("SpdySession3::HandlePing %p PING ID 0x%X.", self, pingID));
 
   if (pingID & 0x01) {
     // presumably a reply to our timeout ping
-    self->ClearPing(true);
+    self->mPingSentEpoch = 0;
   }
   else {
     // Servers initiate even numbered pings, go ahead and echo it back
     self->GeneratePing(pingID);
   }
     
   self->ResetDownstreamState();
   return NS_OK;
--- a/netwerk/protocol/http/SpdySession3.h
+++ b/netwerk/protocol/http/SpdySession3.h
@@ -166,25 +166,23 @@ private:
     BUFFERING_FRAME_HEADER,
     BUFFERING_CONTROL_FRAME,
     PROCESSING_DATA_FRAME,
     DISCARDING_DATA_FRAME,
     PROCESSING_COMPLETE_HEADERS,
     PROCESSING_CONTROL_RST_STREAM
   };
 
-  void        DeterminePingThreshold();
   nsresult    ResponseHeadersComplete();
   uint32_t    GetWriteQueueSize();
   void        ChangeDownstreamState(enum stateType);
   void        ResetDownstreamState();
   nsresult    UncompressAndDiscard(uint32_t, uint32_t);
   void        zlibInit();
   void        GeneratePing(uint32_t);
-  void        ClearPing(bool);
   void        GenerateRstStream(uint32_t, uint32_t);
   void        GenerateGoAway();
   void        CleanupStream(SpdyStream3 *, nsresult, rstReason);
   void        CloseStream(SpdyStream3 *, nsresult);
   void        GenerateSettings();
 
   void        SetWriteCallbacks();
   void        FlushOutputQueue();
@@ -334,14 +332,13 @@ private:
   uint32_t             mOutputQueueSent;
   nsAutoArrayPtr<char> mOutputQueueBuffer;
 
   PRIntervalTime       mPingThreshold;
   PRIntervalTime       mLastReadEpoch;     // used for ping timeouts
   PRIntervalTime       mLastDataReadEpoch; // used for IdleTime()
   PRIntervalTime       mPingSentEpoch;
   uint32_t             mNextPingID;
-  bool                 mPingThresholdExperiment;
 };
 
 }} // namespace mozilla::net
 
 #endif // mozilla_net_SpdySession3_h
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -170,17 +170,17 @@ nsHttpHandler::nsHttpHandler()
     , mHandlerActive(false)
     , mEnableSpdy(false)
     , mSpdyV2(true)
     , mSpdyV3(true)
     , mCoalesceSpdy(true)
     , mUseAlternateProtocol(false)
     , mSpdySendingChunkSize(ASpdySession::kSendingChunkSize)
     , mSpdySendBufferSize(ASpdySession::kTCPSendBufferSize)
-    , mSpdyPingThreshold(PR_SecondsToInterval(44))
+    , mSpdyPingThreshold(PR_SecondsToInterval(58))
     , mSpdyPingTimeout(PR_SecondsToInterval(8))
     , mConnectTimeout(90000)
 {
 #if defined(PR_LOGGING)
     gHttpLog = PR_NewLogModule("nsHttp");
 #endif
 
     LOG(("Creating nsHttpHandler [this=%x].\n", this));
--- a/parser/html/nsHtml5AttributeName.cpp
+++ b/parser/html/nsHtml5AttributeName.cpp
@@ -22,17 +22,16 @@
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit AttributeName.java instead and regenerate.
  */
 
 #define nsHtml5AttributeName_cpp__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5AttributeName.h
+++ b/parser/html/nsHtml5AttributeName.h
@@ -23,17 +23,16 @@
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit AttributeName.java instead and regenerate.
  */
 
 #ifndef nsHtml5AttributeName_h__
 #define nsHtml5AttributeName_h__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5ElementName.cpp
+++ b/parser/html/nsHtml5ElementName.cpp
@@ -22,17 +22,16 @@
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit ElementName.java instead and regenerate.
  */
 
 #define nsHtml5ElementName_cpp__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5ElementName.h
+++ b/parser/html/nsHtml5ElementName.h
@@ -23,17 +23,16 @@
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit ElementName.java instead and regenerate.
  */
 
 #ifndef nsHtml5ElementName_h__
 #define nsHtml5ElementName_h__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5HtmlAttributes.cpp
+++ b/parser/html/nsHtml5HtmlAttributes.cpp
@@ -23,17 +23,16 @@
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit HtmlAttributes.java instead and regenerate.
  */
 
 #define nsHtml5HtmlAttributes_cpp__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5HtmlAttributes.h
+++ b/parser/html/nsHtml5HtmlAttributes.h
@@ -24,17 +24,16 @@
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit HtmlAttributes.java instead and regenerate.
  */
 
 #ifndef nsHtml5HtmlAttributes_h__
 #define nsHtml5HtmlAttributes_h__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5MetaScanner.cpp
+++ b/parser/html/nsHtml5MetaScanner.cpp
@@ -23,17 +23,16 @@
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit MetaScanner.java instead and regenerate.
  */
 
 #define nsHtml5MetaScanner_cpp__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5MetaScanner.h
+++ b/parser/html/nsHtml5MetaScanner.h
@@ -24,17 +24,16 @@
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit MetaScanner.java instead and regenerate.
  */
 
 #ifndef nsHtml5MetaScanner_h__
 #define nsHtml5MetaScanner_h__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5Portability.h
+++ b/parser/html/nsHtml5Portability.h
@@ -23,17 +23,16 @@
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit Portability.java instead and regenerate.
  */
 
 #ifndef nsHtml5Portability_h__
 #define nsHtml5Portability_h__
 
-#include "prtypes.h"
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
--- a/parser/html/nsHtml5StackNode.cpp
+++ b/parser/html/nsHtml5StackNode.cpp
@@ -23,17 +23,16 @@
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit StackNode.java instead and regenerate.