Merge mozilla-central to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 09 Oct 2013 14:14:15 +0200
changeset 150207 130904eff2c5674bd32bf11c65506787342b1ad5
parent 150206 d6f61630aa82927143e8e37df47e7b599c454559 (current diff)
parent 150184 c22969eec61dd6ebc65469d25a5f9265ce7075b4 (diff)
child 150208 b66fef773b22e4c2e7a2ff6c8b912ce03d9e8525
push id2976
push userryanvm@gmail.com
push dateWed, 09 Oct 2013 19:32:52 +0000
treeherderfx-team@a141e39bf6da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
Merge mozilla-central to b2g-inbound
browser/base/content/test/chrome/moz.build
browser/base/content/test/moz.build
browser/base/content/test/newtab/moz.build
browser/base/content/test/social/moz.build
browser/base/content/test/social/opengraph/Makefile.in
browser/base/content/test/social/opengraph/moz.build
browser/metro/base/tests/Makefile.in
browser/metro/base/tests/mochiperf/Makefile.in
browser/metro/base/tests/mochiperf/moz.build
browser/metro/base/tests/mochiperf/perfhelpers.js
browser/metro/base/tests/mochiperf/res/Makefile.in
browser/metro/base/tests/mochiperf/res/moz.build
browser/metro/base/tests/mochitest/Makefile.in
browser/metro/base/tests/mochitest/moz.build
browser/metro/base/tests/mochitest/res/Makefile.in
browser/metro/base/tests/mochitest/res/moz.build
browser/metro/base/tests/moz.build
--- a/accessible/src/base/TextAttrs.cpp
+++ b/accessible/src/base/TextAttrs.cpp
@@ -10,16 +10,17 @@
 #include "nsCoreUtils.h"
 #include "StyleInfo.h"
 
 #include "gfxFont.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 #include "HyperTextAccessible.h"
 #include "mozilla/AppUnits.h"
+#include "mozilla/gfx/2D.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // TextAttrsMgr
 ////////////////////////////////////////////////////////////////////////////////
 
--- a/accessible/src/windows/sdn/sdnTextAccessible.cpp
+++ b/accessible/src/windows/sdn/sdnTextAccessible.cpp
@@ -12,16 +12,17 @@
 #include "DocAccessible.h"
 
 #include "nsIFrame.h"
 #include "nsFontMetrics.h"
 #include "nsPresContext.h"
 #include "nsLayoutUtils.h"
 #include "gfxFont.h"
 #include "nsIAccessibleTypes.h"
+#include "mozilla/gfx/2D.h"
 
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // sdnTextAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 IMPL_IUNKNOWN_QUERY_HEAD(sdnTextAccessible)
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -319,17 +319,16 @@ pref("browser.safebrowsing.provider.0.ge
 // HTML report pages
 pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
 
 // FAQ URLs
-pref("browser.safebrowsing.warning.infoURL", "http://www.mozilla.com/%LOCALE%/%APP%/phishing-protection/");
 pref("browser.geolocation.warning.infoURL", "http://www.mozilla.com/%LOCALE%/%APP%/geolocation/");
 
 // Name of the about: page contributed by safebrowsing to handle display of error
 // pages on phishing/malware hits.  (bug 399233)
 pref("urlclassifier.alternate_error_page", "blocked");
 
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -790,17 +790,16 @@ pref("browser.safebrowsing.keyURL", "htt
 pref("browser.safebrowsing.gethashURL", "http://safebrowsing.clients.google.com/safebrowsing/gethash?client=SAFEBROWSING_ID&appver=%VERSION%&pver=2.2");
 pref("browser.safebrowsing.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/report?");
 pref("browser.safebrowsing.reportGenericURL", "http://%LOCALE%.phish-generic.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportErrorURL", "http://%LOCALE%.phish-error.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportPhishURL", "http://%LOCALE%.phish-report.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportMalwareURL", "http://%LOCALE%.malware-report.mozilla.com/?hl=%LOCALE%");
 pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-error.mozilla.com/?hl=%LOCALE%");
 
-pref("browser.safebrowsing.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/phishing-protection/");
 pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
 // Since the application reputation query isn't hooked in anywhere yet, this
 // preference does not matter. To be extra safe, don't turn this preference on
 // for official builds without whitelisting (bug 842828).
 #ifndef MOZILLA_OFFICIAL
 pref("browser.safebrowsing.appRepURL", "https://sb-ssl.google.com/safebrowsing/clientreport/download");
 #endif
 
--- a/browser/base/content/abouthome/aboutHome.xhtml
+++ b/browser/base/content/abouthome/aboutHome.xhtml
@@ -62,11 +62,11 @@
       <button class="launchButton" id="apps" hidden="true">&abouthome.appsButton.label;</button>
       <button class="launchButton" id="addons">&abouthome.addonsButton.label;</button>
       <button class="launchButton" id="sync">&abouthome.syncButton.label;</button>
       <button class="launchButton" id="settings">&abouthome.settingsButton.label;</button>
       <div id="restorePreviousSessionSeparator"/>
       <button class="launchButton" id="restorePreviousSession">&historyRestoreLastSession.label;</button>
     </div>
 
-    <a id="aboutMozilla" href="http://www.mozilla.org/about/"/>
+    <a id="aboutMozilla" href="https://www.mozilla.org/about/?utm_source=about-home&amp;utm_medium=Referral"/>
   </body>
 </html>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2399,21 +2399,17 @@ let BrowserOnClick = {
             let reportURL = formatURL("browser.safebrowsing.malware.reportURL", true);
             reportURL += aOwnerDoc.location.href;
             content.location = reportURL;
           } catch (e) {
             Components.utils.reportError("Couldn't get malware report URL: " + e);
           }
         }
         else { // It's a phishing site, not malware
-          try {
-            content.location = formatURL("browser.safebrowsing.warning.infoURL", true);
-          } catch (e) {
-            Components.utils.reportError("Couldn't get phishing info URL: " + e);
-          }
+          openHelpLink("phishing-malware", false, "current");
         }
         break;
 
       case "ignoreWarningButton":
         secHistogram.add(nsISecTel[bucketName + "IGNORE_WARNING"]);
         this.ignoreWarningButton(isMalware);
         break;
     }
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1907,17 +1907,17 @@
             var evt = document.createEvent("UIEvent");
             evt.initUIEvent("TabClose", true, false, window, aTabWillBeMoved ? 1 : 0);
             aTab.dispatchEvent(evt);
 
             if (!gMultiProcessBrowser) {
               // Prevent this tab from showing further dialogs, since we're closing it
               var windowUtils = browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).
                                 getInterface(Ci.nsIDOMWindowUtils);
-              windowUtils.preventFurtherDialogs();
+              windowUtils.disableDialogs();
             }
 
             // Remove the tab's filter and progress listener.
             const filter = this.mTabFilters[aTab._tPos];
 
             browser.webProgress.removeProgressListener(filter);
 
             filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
deleted file mode 100644
--- a/browser/base/content/test/chrome/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
-
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -277,8 +277,10 @@ support-files =
 [browser_visibleFindSelection.js]
 [browser_visibleTabs.js]
 [browser_visibleTabs_bookmarkAllPages.js]
 [browser_visibleTabs_bookmarkAllTabs.js]
 [browser_visibleTabs_contextMenu.js]
 [browser_visibleTabs_tabPreview.js]
 [browser_wyciwyg_urlbarCopying.js]
 [browser_zbug569342.js]
+[browser_registerProtocolHandler_notification.js]
+[browser_registerProtocolHandler_notification.html]
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_registerProtocolHandler_notification.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+  <head>
+    <title>Protocol registrar page</title>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+    <meta content="utf-8" http-equiv="encoding">
+  </head>
+  <body>
+    <script type="text/javascript">
+      navigator.registerProtocolHandler("testprotocol",
+          "https://example.com/foobar?uri=%s",
+          "Test Protocol");
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_registerProtocolHandler_notification.js
@@ -0,0 +1,39 @@
+/* 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/. */
+
+function test() {
+  waitForExplicitFinish();
+  let notificationValue = "Protocol Registration: testprotocol";
+  let testURI = "http://example.com/browser/" +
+    "browser/base/content/test/general/browser_registerProtocolHandler_notification.html";
+
+    waitForCondition(function() {
+        // Do not start until the notification is up
+        let notificationBox = window.gBrowser.getNotificationBox();
+        let notification = notificationBox.getNotificationWithValue(notificationValue);
+        return notification;
+    },
+    function() {
+
+        let notificationBox = window.gBrowser.getNotificationBox();
+        let notification = notificationBox.getNotificationWithValue(notificationValue);
+        ok(notification, "Notification box should be displayed");
+        is(notification.type, "info", "We expect this notification to have the type of 'info'.");
+        isnot(notification.image, null, "We expect this notification to have an icon.");
+
+        let buttons = notification.getElementsByClassName("notification-button-default");
+        is(buttons.length, 1, "We expect see one default button.");
+
+        buttons = notification.getElementsByClassName("notification-button");
+        is(buttons.length, 1, "We expect see one button.");
+
+        let button = buttons[0];
+        isnot(button.label, null, "We expect the add button to have a label.");
+        todo_isnot(button.accesskey, null, "We expect the add button to have a accesskey.");
+
+        finish();
+    }, 100);
+
+    window.gBrowser.selectedBrowser.loadURI(testURI);
+}
--- a/browser/base/content/test/general/browser_unloaddialogs.js
+++ b/browser/base/content/test/general/browser_unloaddialogs.js
@@ -1,134 +1,73 @@
-function notify(event)
-{
-  if (event.target.location == "about:blank")
-    return;
-
-  var eventname = event.type;
-  if (eventname == "pagehide")
-    details.pagehides++;
-  else if (eventname == "beforeunload")
-    details.beforeunloads++;
-  else if (eventname == "unload")
-    details.unloads++;
-}
-
-var details;
-
-var gUseFrame = false;
-
-const windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
-
-const TEST_BASE_URL = "data:text/html,<script>" +
-                      "function note(event) { try { alert(event.type); } catch(ex) { return; } throw 'alert appeared'; }" +
-                      "</script>" +
-                      "<body onpagehide='note(event)' onbeforeunload='alert(event.type);' onunload='note(event)'>";
-
-const TEST_URL = TEST_BASE_URL + "Test</body>";
-const TEST_FRAME_URL = TEST_BASE_URL + "Frames</body>";
+var testUrls =
+  [
+    "data:text/html,<script>" +
+      "function handle(evt) {" +
+        "evt.target.removeEventListener(evt.type, handle, true);" +
+        "try { alert('This should NOT appear'); } catch(e) { }" +
+      "}" +
+      "window.addEventListener('pagehide', handle, true);" +
+      "window.addEventListener('beforeunload', handle, true);" +
+      "window.addEventListener('unload', handle, true);" +
+      "</script><body>Testing alert during pagehide/beforeunload/unload</body>",
+    "data:text/html,<script>" +
+      "function handle(evt) {" +
+        "evt.target.removeEventListener(evt.type, handle, true);" +
+        "try { prompt('This should NOT appear'); } catch(e) { }" +
+      "}" +
+      "window.addEventListener('pagehide', handle, true);" +
+      "window.addEventListener('beforeunload', handle, true);" +
+      "window.addEventListener('unload', handle, true);" +
+      "</script><body>Testing prompt during pagehide/beforeunload/unload</body>",
+    "data:text/html,<script>" +
+      "function handle(evt) {" +
+        "evt.target.removeEventListener(evt.type, handle, true);" +
+        "try { confirm('This should NOT appear'); } catch(e) { }" +
+      "}" +
+      "window.addEventListener('pagehide', handle, true);" +
+      "window.addEventListener('beforeunload', handle, true);" +
+      "window.addEventListener('unload', handle, true);" +
+      "</script><body>Testing confirm during pagehide/beforeunload/unload</body>",
+  ];
+var testsDone = 0;
 
 function test()
 {
   waitForExplicitFinish();
-  windowMediator.addListener(promptListener);
   runTest();
 }
 
 function runTest()
 {
-  details = {
-    testNumber : 0,
-    beforeunloads : 0,
-    pagehides : 0,
-    unloads : 0,
-    prompts : 0
-  };
-
-  var tab = gBrowser.addTab(TEST_URL);
-  gBrowser.selectedTab = tab;
-  tab.linkedBrowser.addEventListener("pageshow", shown, true);
-
-  tab.linkedBrowser.addEventListener("pagehide", notify, true);
-  tab.linkedBrowser.addEventListener("beforeunload", notify, true);
-  tab.linkedBrowser.addEventListener("unload", notify, true);
+  whenNewTabLoaded(window, function() {
+    gBrowser.selectedBrowser.addEventListener("load", onLoad, true);
+    executeSoon(function() {
+      info("Loading page with pagehide, beforeunload, and unload handlers that attempt to create dialogs");
+      gBrowser.selectedBrowser.loadURI(testUrls[testsDone]);
+    });
+  });
 }
 
-function shown(event)
+function onLoad(event)
 {
-  if (details.testNumber == 0) {
-    var browser;
-    var iframe;
-    if (gUseFrame) {
-      iframe = event.target.createElement("iframe");
-      iframe.src = TEST_FRAME_URL;
-      event.target.documentElement.appendChild(iframe);
-      browser = iframe.contentWindow;
-    }
-    else {
-      browser = gBrowser.selectedTab.linkedBrowser;
-      details.testNumber = 1; // Move onto to the next step immediately
-    }
-  }
+  info("Page loaded");
+
+  event.target.removeEventListener("load", onLoad, true);
+  gBrowser.selectedBrowser.addEventListener("unload", done, true);
 
-  if (details.testNumber == 1) {
-    // Test going to another page
-    executeSoon(function () {
-      const urlToLoad = "data:text/html,<body>Another Page</body>";
-      if (gUseFrame) {
-        event.target.location = urlToLoad;
-      }
-      else {
-        gBrowser.selectedBrowser.loadURI(urlToLoad);
-      }
-    });
-  }
-  else if (details.testNumber == 2) {
-    is(details.pagehides, 1, "pagehides after next page")
-    is(details.beforeunloads, 1, "beforeunloads after next page")
-    is(details.unloads, 1, "unloads after next page")
-    is(details.prompts, 1, "prompts after next page")
+  executeSoon(function () {
+    info("Closing page");
+    gBrowser.removeCurrentTab();
+  });
+}
 
-    executeSoon(function () gUseFrame ? gBrowser.goBack() : event.target.defaultView.back());
-  }
-  else if (details.testNumber == 3) {
-    is(details.pagehides, 2, "pagehides after back")
-    is(details.beforeunloads, 2, "beforeunloads after back")
-    // No cache, so frame is unloaded
-    is(details.unloads, gUseFrame ? 2 : 1, "unloads after back")
-    is(details.prompts, 1, "prompts after back")
-
-    // Test closing the tab
-    gBrowser.selectedBrowser.removeEventListener("pageshow", shown, true);
-    gBrowser.removeTab(gBrowser.selectedTab);
+function done() {
+  ok(true, "Page closed (hopefully) without timeout");
 
-    // When the frame is present, there is are two beforeunload and prompts,
-    // one for the frame and the other for the parent.
-    is(details.pagehides, 3, "pagehides after close")
-    is(details.beforeunloads, gUseFrame ? 4 : 3, "beforeunloads after close")
-    is(details.unloads, gUseFrame ? 3 : 2, "unloads after close")
-    is(details.prompts, gUseFrame ? 3 : 2, "prompts after close")
-
-    // Now run the test again using a child frame.
-    if (gUseFrame) {
-      windowMediator.removeListener(promptListener);
-      finish();
-    }
-    else {
-      gUseFrame = true;
-      runTest();
-    }
-
+  testsDone++;
+  if (testsDone == testUrls.length) {
+    finish();
     return;
   }
 
-  details.testNumber++;
+  executeSoon(runTest);
 }
-
-var promptListener = {
-  onWindowTitleChange: function () {},
-  onOpenWindow: function (win) {
-    details.prompts++;
-    let domWin = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
-    executeSoon(function () { domWin.close() });
-  },
-  onCloseWindow: function () {},
-};
--- a/browser/base/content/test/general/moz.build
+++ b/browser/base/content/test/general/moz.build
@@ -1,10 +1,5 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_MANIFESTS += ['mochitest.ini']
-
-BROWSER_CHROME_MANIFESTS += ['browser.ini']
-
deleted file mode 100644
--- a/browser/base/content/test/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DIRS += ['chrome', 'general', 'newtab', 'social']
-
deleted file mode 100644
--- a/browser/base/content/test/newtab/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-BROWSER_CHROME_MANIFESTS += ['browser.ini']
-
--- a/browser/base/content/test/social/browser.ini
+++ b/browser/base/content/test/social/browser.ini
@@ -1,13 +1,18 @@
 [DEFAULT]
 support-files =
   blocklist.xml
   checked.jpg
   head.js
+  opengraph/og_invalid_url.html
+  opengraph/opengraph.html
+  opengraph/shortlink_linkrel.html
+  opengraph/shorturl_link.html
+  opengraph/shorturl_linkrel.html
   share.html
   social_activate.html
   social_activate_iframe.html
   social_chat.html
   social_flyout.html
   social_mark.html
   social_panel.html
   social_sidebar.html
deleted file mode 100644
--- a/browser/base/content/test/social/moz.build
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DIRS += ['opengraph']
-
-BROWSER_CHROME_MANIFESTS += ['browser.ini']
-
deleted file mode 100644
--- a/browser/base/content/test/social/opengraph/Makefile.in
+++ /dev/null
@@ -1,11 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_BROWSER_FILES := \
-                 opengraph.html \
-                 og_invalid_url.html \
-                 shortlink_linkrel.html \
-                 shorturl_link.html \
-                 shorturl_linkrel.html \
-                 $(NULL)
deleted file mode 100644
--- a/browser/base/content/test/social/opengraph/moz.build
+++ /dev/null
@@ -1,4 +0,0 @@
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -651,23 +651,26 @@ function isValidFeed(aLink, aPrincipal, 
     catch(ex) {
     }
   }
 
   return null;
 }
 
 // aCalledFromModal is optional
-function openHelpLink(aHelpTopic, aCalledFromModal) {
+function openHelpLink(aHelpTopic, aCalledFromModal, aWhere) {
   var url = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
                       .getService(Components.interfaces.nsIURLFormatter)
                       .formatURLPref("app.support.baseURL");
   url += aHelpTopic;
 
-  var where = aCalledFromModal ? "window" : "tab";
+  var where = aWhere;
+  if (!aWhere)
+    where = aCalledFromModal ? "window" : "tab";
+
   openUILinkIn(url, where);
 }
 
 function openPrefsHelp() {
   // non-instant apply prefwindows are usually modal, so we can't open in the topmost window, 
   // since its probably behind the window.
   var instantApply = getBoolPref("browser.preferences.instantApply");
 
--- a/browser/base/moz.build
+++ b/browser/base/moz.build
@@ -1,7 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-TEST_DIRS += ['content/test']
+TEST_DIRS += [
+    'content/test/general',
+]
+
+MOCHITEST_MANIFESTS += [
+    'content/test/general/mochitest.ini',
+]
+
+MOCHITEST_CHROME_MANIFESTS += [
+    'content/test/chrome/chrome.ini',
+]
+
+BROWSER_CHROME_MANIFESTS += [
+    'content/test/general/browser.ini',
+    'content/test/newtab/browser.ini',
+    'content/test/social/browser.ini',
+]
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -752,30 +752,33 @@ DownloadsDataCtor.prototype = {
     }
   },
 
   /**
    * Updates the given data item and sends related notifications.
    */
   _updateDataItemState: function (aDataItem)
   {
+    let oldState = aDataItem.state;
     let wasInProgress = aDataItem.inProgress;
     let wasDone = aDataItem.done;
 
     aDataItem.updateFromJSDownload();
 
     if (wasInProgress && !aDataItem.inProgress) {
       aDataItem.endTime = Date.now();
     }
 
-    for (let view of this._views) {
-      try {
-        view.getViewItem(aDataItem).onStateChange({});
-      } catch (ex) {
-        Cu.reportError(ex);
+    if (oldState != aDataItem.state) {
+      for (let view of this._views) {
+        try {
+          view.getViewItem(aDataItem).onStateChange(oldState);
+        } catch (ex) {
+          Cu.reportError(ex);
+        }
       }
     }
 
     if (!aDataItem.newDownloadNotified) {
       aDataItem.newDownloadNotified = true;
       this._notifyDownloadEvent("start");
     }
 
--- a/browser/components/feeds/src/WebContentConverter.js
+++ b/browser/components/feeds/src/WebContentConverter.js
@@ -446,24 +446,23 @@ WebContentConverterRegistrar.prototype =
           // use.
           handlerInfo.alwaysAskBeforeHandling = true;
 
           var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
                    getService(Ci.nsIHandlerService);
           hs.store(handlerInfo);
         }
     };
-    var buttons;
     var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
     var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
     notificationBox.appendNotification(message,
                                        notificationValue,
                                        notificationIcon,
                                        notificationBox.PRIORITY_INFO_LOW,
-                                       buttons);
+                                       [addButton]);
   },
 
   /**
    * See nsIWebContentHandlerRegistrar
    * If a DOM window is provided, then the request came from content, so we
    * prompt the user to confirm the registration.
    */
   registerContentHandler: 
--- a/browser/components/places/content/placesOverlay.xul
+++ b/browser/components/places/content/placesOverlay.xul
@@ -192,28 +192,28 @@
               label="&cmd.deleteDomainData.label;"
               accesskey="&cmd.deleteDomainData.accesskey;"
               closemenu="single"
               selection="link|host"
               selectiontype="single"
               hideifprivatebrowsing="true"
               forcehideselection="bookmark"/>
     <menuseparator id="placesContext_deleteSeparator"/>
+    <menuitem id="placesContext_sortBy:name"
+              command="placesCmd_sortBy:name"
+              label="&cmd.sortby_name.label;"
+              accesskey="&cmd.context_sortby_name.accesskey;"
+              closemenu="single"
+              selection="folder"/>
     <menuitem id="placesContext_reload"
               command="placesCmd_reload"
               label="&cmd.reloadLivebookmark.label;"
               accesskey="&cmd.reloadLivebookmark.accesskey;"
               closemenu="single"
               selection="livemark/feedURI"/>
-    <menuitem id="placesContext_sortBy:name"
-              command="placesCmd_sortBy:name"
-              label="&cmd.sortby_name.label;"
-              accesskey="&cmd.context_sortby_name.accesskey;"
-              closemenu="single"
-              selection="folder"/>
     <menuseparator id="placesContext_sortSeparator"/>
     <menuitem id="placesContext_show:info"
               command="placesCmd_show:info"
               label="&cmd.properties.label;" 
               accesskey="&cmd.properties.accesskey;"
               selection="bookmark|folder|query"
               forcehideselection="livemarkChild"/>
   </menupopup>
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -179,17 +179,17 @@ this.SessionStore = {
   getTabState: function ss_getTabState(aTab) {
     return SessionStoreInternal.getTabState(aTab);
   },
 
   setTabState: function ss_setTabState(aTab, aState) {
     SessionStoreInternal.setTabState(aTab, aState);
   },
 
-  duplicateTab: function ss_duplicateTab(aWindow, aTab, aDelta) {
+  duplicateTab: function ss_duplicateTab(aWindow, aTab, aDelta = 0) {
     return SessionStoreInternal.duplicateTab(aWindow, aTab, aDelta);
   },
 
   getNumberOfTabsClosedLast: function ss_getNumberOfTabsClosedLast(aWindow) {
     return SessionStoreInternal.getNumberOfTabsClosedLast(aWindow);
   },
 
   setNumberOfTabsClosedLast: function ss_setNumberOfTabsClosedLast(aWindow, aNumber) {
@@ -1451,17 +1451,17 @@ let SessionStoreInternal = {
       this._resetTabRestoringState(aTab);
     }
 
     TabStateCache.delete(aTab);
     this._setWindowStateBusy(window);
     this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0);
   },
 
-  duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta) {
+  duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
     if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi ||
         !aWindow.getBrowser)
       throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
 
     // Duplicate the tab state
     let tabState = TabState.clone(aTab);
 
     tabState.index += aDelta;
--- a/browser/metro/base/content/ContentAreaObserver.js
+++ b/browser/metro/base/content/ContentAreaObserver.js
@@ -227,19 +227,21 @@ var ContentAreaObserver = {
 
     if (!aNewState) {
       this._shiftBrowserDeck(0);
       return;
     }
 
     // Request info about the target form element to see if we
     // need to reposition the browser above the keyboard.
-    Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:RepositionInfoRequest", {
-      viewHeight: this.viewableHeight,
-    });
+    if (SelectionHelperUI.layerMode === 2 /*kContentLayer*/) {
+      Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:RepositionInfoRequest", {
+        viewHeight: this.viewableHeight,
+      });
+    }
   },
 
   _onRepositionResponse: function _onRepositionResponse(aJsonMsg) {
     if (!aJsonMsg.reposition || !this.isKeyboardOpened) {
       this._shiftBrowserDeck(0);
       return;
     }
     this._shiftBrowserDeck(aJsonMsg.raiseContent);
--- a/browser/metro/base/content/WebProgress.js
+++ b/browser/metro/base/content/WebProgress.js
@@ -6,18 +6,16 @@
 const kHeartbeatDuration = 1000;
 // Start and end progress screen css margins as percentages
 const kProgressMarginStart = 30;
 const kProgressMarginEnd = 70;
 
 const WebProgress = {
   get _identityBox() { return document.getElementById("identity-box"); },
 
-  _progressActive: false,
-
   init: function init() {
     messageManager.addMessageListener("Content:StateChange", this);
     messageManager.addMessageListener("Content:LocationChange", this);
     messageManager.addMessageListener("Content:SecurityChange", this);
 
     Elements.progress.addEventListener("transitionend", this, true);
     Elements.tabList.addEventListener("TabSelect", this, true);
 
@@ -42,29 +40,29 @@ const WebProgress = {
 
         if (json.stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) {
           if (json.stateFlags & Ci.nsIWebProgressListener.STATE_START)
             this._networkStart(json, tab);
           else if (json.stateFlags & Ci.nsIWebProgressListener.STATE_STOP)
             this._networkStop(json, tab);
         }
 
-        this._progressStep();
+        this._progressStep(tab);
         break;
       }
 
       case "Content:LocationChange": {
         this._locationChange(json, tab);
-        this._progressStep();
+        this._progressStep(tab);
         break;
       }
 
       case "Content:SecurityChange": {
         this._securityChange(json, tab);
-        this._progressStep();
+        this._progressStep(tab);
         break;
       }
     }
   },
 
   handleEvent: function handleEvent(aEvent) {
     switch (aEvent.type) {
       case "transitionend":
@@ -148,67 +146,70 @@ const WebProgress = {
 
   _windowStop: function _windowStop(aJson, aTab) {
     this._progressStop(aJson, aTab);
   },
 
   _progressStart: function _progressStart(aJson, aTab) {
     // We will get multiple calls from _windowStart, so
     // only process once.
-    if (this._progressActive)
+    if (aTab._progressActive)
       return;
 
-    this._progressActive = true;
+    aTab._progressActive = true;
 
+    // 'Whoosh' in
+    aTab._progressCount = kProgressMarginStart;
+    this._showProgressBar(aTab);
+  },
+
+  _showProgressBar: function (aTab) {
     // display the track
     Elements.progressContainer.removeAttribute("collapsed");
-
-    // 'Whoosh' in
-    this._progressCount = kProgressMarginStart;
-    Elements.progress.style.width = this._progressCount + "%";
+    Elements.progress.style.width = aTab._progressCount + "%";
     Elements.progress.removeAttribute("fade");
 
     // Create a pulse timer to keep things moving even if we don't
     // collect any state changes.
     setTimeout(function() {
-      WebProgress._progressStepTimer();
+      WebProgress._progressStepTimer(aTab);
     }, kHeartbeatDuration, this);
   },
 
-  _stepProgressCount: function _stepProgressCount() {
+  _stepProgressCount: function _stepProgressCount(aTab) {
     // Step toward the end margin in smaller slices as we get closer
-    let left = kProgressMarginEnd - this._progressCount;
+    let left = kProgressMarginEnd - aTab._progressCount;
     let step = left * .05;
-    this._progressCount += Math.ceil(step);
+    aTab._progressCount += Math.ceil(step);
 
     // Don't go past the 'whoosh out' margin.
-    if (this._progressCount > kProgressMarginEnd) {
-      this._progressCount = kProgressMarginEnd;
+    if (aTab._progressCount > kProgressMarginEnd) {
+      aTab._progressCount = kProgressMarginEnd;
     }
   },
 
-  _progressStep: function _progressStep() {
-    if (!this._progressActive)
+  _progressStep: function _progressStep(aTab) {
+    if (!aTab._progressActive)
       return;
-    this._stepProgressCount();
-    Elements.progress.style.width = this._progressCount + "%";
+    this._stepProgressCount(aTab);
+    Elements.progress.style.width = aTab._progressCount + "%";
   },
 
-  _progressStepTimer: function _progressStepTimer() {
-    if (!this._progressActive)
+  _progressStepTimer: function _progressStepTimer(aTab) {
+    if (!aTab._progressActive)
       return;
-    this._progressStep();
+    this._progressStep(aTab);
 
     setTimeout(function() {
-      WebProgress._progressStepTimer();
+      WebProgress._progressStepTimer(aTab);
     }, kHeartbeatDuration, this);
   },
 
   _progressStop: function _progressStop(aJson, aTab) {
-    this._progressActive = false;
+    aTab._progressActive = false;
     // 'Whoosh out' and fade
     Elements.progress.style.width = "100%";
     Elements.progress.setAttribute("fade", true);
   },
 
   _progressTransEnd: function _progressTransEnd(aEvent) {
     if (!Elements.progress.hasAttribute("fade"))
       return;
@@ -217,14 +218,20 @@ const WebProgress = {
       Elements.progress.style.width = "0px";
       Elements.progressContainer.setAttribute("collapsed", true);
     }
   },
 
   _onTabSelect: function(aEvent) {
     let tab = Browser.getTabFromChrome(aEvent.originalTarget);
     this._identityBox.className = tab._identityState || "";
+    if (tab._progressActive) {
+      this._showProgressBar(tab);
+    } else {
+      Elements.progress.setAttribute("fade", true);
+      Elements.progressContainer.setAttribute("collapsed", true);
+    }
   },
 
   _onUrlBarInput: function(aEvent) {
     Browser.selectedTab._identityState = this._identityBox.className = "";
   },
 };
--- a/browser/metro/base/content/bindings/circularprogress.xml
+++ b/browser/metro/base/content/bindings/circularprogress.xml
@@ -4,16 +4,20 @@
    - 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/. -->
 
 <bindings xmlns="http://www.mozilla.org/xbl"
           xmlns:xbl="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:html="http://www.w3.org/1999/xhtml">
   <binding id="circular-progress-indicator">
+    <resources>
+      <stylesheet src="chrome://browser/skin/circularprogress.css"/>
+    </resources>
+
     <content>
       <xul:stack>
         <xul:toolbarbutton anonid="progressButton" class="circularprogressindicator-progressButton appbar-secondary"/>
         <html:div anonid="progressTrack" xbl:inherits="progress" class="circularprogressindicator-progressTrack"></html:div>
         <html:canvas anonid="progressRing" xbl:inherits="progress" class="circularprogressindicator-progressRing" width="40" height="40"></html:canvas>
       </xul:stack>
     </content>
     <implementation>
@@ -75,9 +79,9 @@
             this._progressCircleCtx.clearRect(0, 0,
               this._progressCanvas.width, this._progressCanvas.height);
             this.removeAttribute("progress");
           ]]>
         </body>
       </method>
     </implementation>
   </binding>
-</bindings>
\ No newline at end of file
+</bindings>
--- a/browser/metro/base/content/browser-ui.js
+++ b/browser/metro/base/content/browser-ui.js
@@ -1055,33 +1055,57 @@ var BrowserUI = {
         break;
       case "cmd_closeTab":
         this.closeTab();
         break;
       case "cmd_undoCloseTab":
         this.undoCloseTab();
         break;
       case "cmd_sanitize":
-        SanitizeUI.onSanitize();
+        this.confirmSanitizeDialog();
         break;
       case "cmd_flyout_back":
         FlyoutPanelsUI.onBackButton();
         break;
       case "cmd_panel":
         PanelUI.toggle();
         break;
       case "cmd_openFile":
         this.openFile();
         break;
       case "cmd_savePage":
         this.savePage();
         break;
     }
   },
 
+  confirmSanitizeDialog: function () {
+    let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+    let title = bundle.GetStringFromName("clearPrivateData.title");
+    let message = bundle.GetStringFromName("clearPrivateData.message");
+    let clearbutton = bundle.GetStringFromName("clearPrivateData.clearButton");
+
+    let buttonPressed = Services.prompt.confirmEx(
+                          null,
+                          title,
+                          message,
+                          Ci.nsIPrompt.BUTTON_POS_0 * Ci.nsIPrompt.BUTTON_TITLE_IS_STRING +
+                          Ci.nsIPrompt.BUTTON_POS_1 * Ci.nsIPrompt.BUTTON_TITLE_CANCEL,
+                          clearbutton,
+                          null,
+                          null,
+                          null,
+                          { value: false });
+
+    // Clicking 'Clear' will call onSanitize().
+    if (buttonPressed === 0) {
+      SanitizeUI.onSanitize();
+    }
+  },
+
   crashReportingPrefChanged: function crashReportingPrefChanged(aState) {
     CrashReporter.submitReports = aState;
   }
 };
 
 var PanelUI = {
   get _panels() { return document.getElementById("panel-items"); },
 
--- a/browser/metro/base/content/browser.js
+++ b/browser/metro/base/content/browser.js
@@ -672,23 +672,19 @@ var Browser = {
           reportURL += json.url;
           this.loadURI(reportURL);
         } catch (e) {
           Cu.reportError("Couldn't get malware report URL: " + e);
         }
         break;
       }
       case "report-phishing": {
-        // It's a phishing site, not malware
-        try {
-          let reportURL = formatter.formatURLPref("browser.safebrowsing.warning.infoURL");
-          this.loadURI(reportURL);
-        } catch (e) {
-          Cu.reportError("Couldn't get phishing info URL: " + e);
-        }
+        // It's a phishing site, just link to the generic information page
+        let url = Services.urlFormatter.formatURLPref("app.support.baseURL");
+        this.loadURI(url + "phishing-malware");
         break;
       }
     }
   },
 
   pinSite: function browser_pinSite() {
     // Get a path to our app tile
     var file = Components.classes["@mozilla.org/file/directory_service;1"].
@@ -1237,16 +1233,18 @@ function showDownloadManager(aWindowCont
   // TODO: Bug 883962: Toggle the downloads infobar as our current "download manager".
 }
 
 function Tab(aURI, aParams, aOwner) {
   this._id = null;
   this._browser = null;
   this._notification = null;
   this._loading = false;
+  this._progressActive = false;
+  this._progressCount = 0;
   this._chromeTab = null;
   this._eventDeferred = null;
   this._updateThumbnailTimeout = null;
 
   this.owner = aOwner || null;
 
   // Set to 0 since new tabs that have not been viewed yet are good tabs to
   // toss if app needs more memory.
--- a/browser/metro/base/content/contenthandlers/SelectionHandler.js
+++ b/browser/metro/base/content/contenthandlers/SelectionHandler.js
@@ -317,27 +317,16 @@ var SelectionHandler = {
   },
 
   /*
    * _repositionInfoRequest - fired at us by ContentAreaObserver when the
    * soft keyboard is being displayed. CAO wants to make a decision about
    * whether the browser deck needs repositioning.
    */
   _repositionInfoRequest: function _repositionInfoRequest(aJsonMsg) {
-    if (!this.isActive) {
-      Util.dumpLn("unexpected: repositionInfoRequest but selection isn't active.");
-      this.sendAsync("Content:RepositionInfoResponse", { reposition: false });
-      return;
-    }
-    
-    if (!this.targetIsEditable) {
-      Util.dumpLn("unexpected: repositionInfoRequest but targetIsEditable is false.");
-      this.sendAsync("Content:RepositionInfoResponse", { reposition: false });
-    }
-    
     let result = this._calcNewContentPosition(aJsonMsg.viewHeight);
 
     // no repositioning needed
     if (result == 0) {
       this.sendAsync("Content:RepositionInfoResponse", { reposition: false });
       return;
     }
 
@@ -417,19 +406,20 @@ var SelectionHandler = {
    * raised to move the focused form input out of the way of the soft
    * keyboard.
    *
    * @param aNewViewHeight the new content view height
    * @return 0 if no positioning is required or a positive val equal to the
    * distance content should be raised to center the target element.
    */
   _calcNewContentPosition: function _calcNewContentPosition(aNewViewHeight) {
-    // We don't support this on non-editable elements
-    if (!this._targetIsEditable) {
-      return 0;
+    // We have no target element but the keyboard is up
+    // so lets not cover content
+    if (!this._cache || !this._cache.element) {
+      return Services.metro.keyboardHeight;
     }
 
     let position = Util.centerElementInView(aNewViewHeight, this._cache.element);
     if (position !== undefined) {
       return position;
     }
 
     // Special case: we are dealing with an input that is taller than the
--- a/browser/metro/base/content/cursor.css
+++ b/browser/metro/base/content/cursor.css
@@ -1,19 +1,11 @@
 /* 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/. */
 
 @namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
 @namespace html url(http://www.w3.org/1999/xhtml);
 
-xul|*:-moz-system-metric(touch-enabled) {
-  cursor: none !important;
-}
-
-html|*:-moz-system-metric(touch-enabled) {
-  cursor: none !important;
-}
-
 /* For touch input, *all* select boxes use the SelectHelper popup. */
 select option, select optgroup {
   pointer-events: none;
 }
--- a/browser/metro/base/content/downloads.js
+++ b/browser/metro/base/content/downloads.js
@@ -9,16 +9,17 @@ const TOAST_URI_GENERIC_ICON_DOWNLOAD = 
 var MetroDownloadsView = {
   /**
    * _downloadCount keeps track of the number of downloads that a single
    * notification bar groups together. A download is grouped with other
    * downloads if it starts before other downloads have completed.
    */
   _downloadCount: 0,
   _downloadsInProgress: 0,
+  _lastDownload: null,
   _inited: false,
   _progressAlert: null,
   _lastSec: Infinity,
   _notificationBox: null,
   _progressNotification: null,
   _progressNotificationInfo: new Map(),
   _runDownloadBooleanMap: new Map(),
 
@@ -49,20 +50,18 @@ var MetroDownloadsView = {
       return;
 
     this._inited = true;
 
     Services.obs.addObserver(this, "dl-start", true);
     Services.obs.addObserver(this, "dl-done", true);
     Services.obs.addObserver(this, "dl-run", true);
     Services.obs.addObserver(this, "dl-failed", true);
-    Services.obs.addObserver(this, "dl-request", true);
 
     this._notificationBox = Browser.getNotificationBox();
-    this._notificationBox.addEventListener('AlertClose', this.handleEvent, true);
 
     this._progress = new DownloadProgressListener(this);
     this.manager.addListener(this._progress);
 
     this._downloadProgressIndicator = document.getElementById("download-progress");
 
     if (this.manager.activeDownloadCount) {
       setTimeout (this._restartWithActiveDownloads.bind(this), 0);
@@ -70,17 +69,16 @@ var MetroDownloadsView = {
   },
 
   uninit: function dh_uninit() {
     if (this._inited) {
       Services.obs.removeObserver(this, "dl-start");
       Services.obs.removeObserver(this, "dl-done");
       Services.obs.removeObserver(this, "dl-run");
       Services.obs.removeObserver(this, "dl-failed");
-      Services.obs.removeObserver(this, "dl-request");
     }
   },
 
   _restartWithActiveDownloads: function() {
     let activeDownloads = this.manager.activeDownloads;
 
     while (activeDownloads.hasMoreElements()) {
       let dl = activeDownloads.getNext();
@@ -88,17 +86,17 @@ var MetroDownloadsView = {
         case 0: // Downloading
         case 5: // Queued
           this.watchDownload(dl);
           this.updateInfobar();
           break;
       }
     }
     if (this.manager.activeDownloadCount) {
-      Services.obs.notifyObservers(null, "dl-request", "");
+      ContextUI.displayNavbar();
     }
   },
 
   openDownload: function dh_openDownload(aDownload) {
     let fileURI = aDownload.target
 
     if (!(fileURI && fileURI.spec)) {
       Util.dumpLn("Cant open download "+id+", fileURI is invalid");
@@ -228,102 +226,107 @@ var MetroDownloadsView = {
           MetroDownloadsView._downloadProgressIndicator.reset();
         }
       }
     ];
     this.showNotification("download-failed", message, buttons,
       this._notificationBox.PRIORITY_WARNING_HIGH);
   },
 
-  _showDownloadCompleteNotification: function (aDownload) {
+  _showDownloadCompleteNotification: function () {
     let message = "";
     let showInFilesButtonText = Strings.browser.GetStringFromName("downloadShowInFiles");
 
     let buttons = [
       {
         label: showInFilesButtonText,
         accessKey: "",
         callback: function() {
-          let fileURI = aDownload.target;
+          let fileURI = MetroDownloadsView._lastDownload.target;
           let file = MetroDownloadsView._getLocalFile(fileURI);
           file.reveal();
+          MetroDownloadsView._resetCompletedDownloads();
         }
       }
     ];
 
     if (this._downloadCount > 1) {
       message = PluralForm.get(this._downloadCount,
                                Strings.browser.GetStringFromName("alertMultipleDownloadsComplete"))
                                .replace("#1", this._downloadCount)
     } else {
       let runButtonText =
         Strings.browser.GetStringFromName("downloadRun");
       message = Strings.browser.formatStringFromName("alertDownloadsDone2",
-        [aDownload.displayName], 1);
+        [this._lastDownload.displayName], 1);
 
       buttons.unshift({
         isDefault: true,
         label: runButtonText,
         accessKey: "",
         callback: function() {
-          MetroDownloadsView.openDownload(aDownload);
+          MetroDownloadsView.openDownload(MetroDownloadsView._lastDownload);
+          MetroDownloadsView._resetCompletedDownloads();
         }
       });
     }
+    this._removeNotification("download-complete");
     this.showNotification("download-complete", message, buttons,
       this._notificationBox.PRIORITY_WARNING_MEDIUM);
   },
 
-  _showDownloadCompleteToast: function (aDownload) {
+  _showDownloadCompleteToast: function () {
     let name = "DownloadComplete";
     let msg = "";
     let title = "";
     let observer = null;
     if (this._downloadCount > 1) {
       title = PluralForm.get(this._downloadCount,
                              Strings.browser.GetStringFromName("alertMultipleDownloadsComplete"))
                              .replace("#1", this._downloadCount)
       msg = PluralForm.get(2, Strings.browser.GetStringFromName("downloadShowInFiles"));
 
       observer = {
         observe: function (aSubject, aTopic, aData) {
           switch (aTopic) {
             case "alertclickcallback":
-              let fileURI = aDownload.target;
+              let fileURI = MetroDownloadsView._lastDownload.target;
               let file = MetroDownloadsView._getLocalFile(fileURI);
               file.reveal();
-
-              let downloadCompleteNotification =
-                MetroDownloadsView._notificationBox.getNotificationWithValue("download-complete");
-              MetroDownloadsView._notificationBox.removeNotification(downloadCompleteNotification);
+              MetroDownloadsView._resetCompletedDownloads();
               break;
           }
         }
       }
     } else {
       title = Strings.browser.formatStringFromName("alertDownloadsDone",
-        [aDownload.displayName], 1);
+        [this._lastDownload.displayName], 1);
       msg = Strings.browser.GetStringFromName("downloadRunNow");
       observer = {
         observe: function (aSubject, aTopic, aData) {
           switch (aTopic) {
             case "alertclickcallback":
-              MetroDownloadsView.openDownload(aDownload);
-
-              let downloadCompleteNotification =
-                MetroDownloadsView._notificationBox.getNotificationWithValue("download-complete");
-              MetroDownloadsView._notificationBox.removeNotification(downloadCompleteNotification);
+              MetroDownloadsView.openDownload(MetroDownloadsView._lastDownload);
+              MetroDownloadsView._resetCompletedDownloads();
               break;
           }
         }
       }
     }
     this.showAlert(name, msg, title, null, observer);
   },
 
+  _resetCompletedDownloads: function () {
+    this._progressNotificationInfo.clear();
+    this._downloadCount = 0;
+    this._lastDownload = null;
+    this._downloadProgressIndicator.reset();
+    this._removeNotification("download-complete");
+  },
+
   _updateCircularProgressMeter: function dv_updateCircularProgressMeter() {
     if (!this._progressNotificationInfo) {
       return;
     }
 
     let totPercent = 0;
     for (let [guid, info] of this._progressNotificationInfo) {
       // info.download => nsIDownload
@@ -376,26 +379,36 @@ var MetroDownloadsView = {
       this._progressNotificationInfo.set(aDownload.guid, {});
     }
     let infoObj = this._progressNotificationInfo.get(aDownload.guid);
     infoObj.download = aDownload;
     this._progressNotificationInfo.set(aDownload.guid, infoObj);
   },
 
   onDownloadButton: function dv_onDownloadButton() {
-    if (this._progressNotification) {
-      let progressBar = this._notificationBox.getNotificationWithValue("download-progress");
-      if (progressBar) {
-        this._notificationBox.removeNotification(progressBar);
-      } else {
+    if (this._downloadsInProgress) {
+      if (!this._removeNotification("download-progress")) {
         this.updateInfobar();
       }
+    } else if (this._downloadCount) {
+      if (!this._removeNotification("download-complete")) {
+        this._showDownloadCompleteNotification();
+      }
     }
   },
 
+  _removeNotification: function (aValue) {
+    let notification = this._notificationBox.getNotificationWithValue(aValue);
+    if (!notification) {
+      return false;
+    }
+    this._notificationBox.removeNotification(notification);
+    return true;
+  },
+
   updateInfobar: function dv_updateInfobar() {
     let message = this._computeDownloadProgressString();
     this._updateCircularProgressMeter();
 
     if (this._progressNotification == null ||
         !this._notificationBox.getNotificationWithValue("download-progress")) {
       let cancelButtonText =
               Strings.browser.GetStringFromName("downloadCancel");
@@ -410,16 +423,18 @@ var MetroDownloadsView = {
             MetroDownloadsView._downloadProgressIndicator.reset();
           }
         }
       ];
 
       this._progressNotification =
         this.showNotification("download-progress", message, buttons,
         this._notificationBox.PRIORITY_WARNING_LOW);
+
+      ContextUI.displayNavbar();
     } else {
       this._progressNotification.label = message;
     }
   },
 
   updateDownload: function dv_updateDownload(aDownload) {
     if (this._progressNotification != null) {
       this._saveDownloadData(aDownload);
@@ -437,27 +452,16 @@ var MetroDownloadsView = {
       this._progressNotificationInfo.set(aDownload.guid, {});
     }
     if (!this._progressAlert) {
       this._progressAlert = new AlertDownloadProgressListener();
       this.manager.addListener(this._progressAlert);
     }
   },
 
-  handleEvent: function handleEvent(aEvent) {
-    switch (aEvent.type) {
-      case "AlertClose":
-        if (aEvent.notification.value == "download-complete" &&
-            !MetroDownloadsView._notificationBox.getNotificationWithValue("download-complete")) {
-          MetroDownloadsView._downloadProgressIndicator.reset();
-        }
-        break;
-    }
-  },
-
   observe: function (aSubject, aTopic, aData) {
     let message = "";
     let msgTitle = "";
 
     switch (aTopic) {
       case "dl-run":
         let file = aSubject.QueryInterface(Ci.nsIFile);
         this._runDownloadBooleanMap.set(file.path, (aData == 'true'));
@@ -465,42 +469,36 @@ var MetroDownloadsView = {
       case "dl-start":
         let download = aSubject.QueryInterface(Ci.nsIDownload);
         this.watchDownload(download);
         this.updateInfobar();
         break;
       case "dl-done":
         this._downloadsInProgress--;
         download = aSubject.QueryInterface(Ci.nsIDownload);
+        this._lastDownload = download;
         let runAfterDownload = this._runDownloadBooleanMap.get(download.targetFile.path);
         if (runAfterDownload) {
           this.openDownload(download);
         }
 
         this._runDownloadBooleanMap.delete(download.targetFile.path);
         if (this._downloadsInProgress == 0) {
           if (this._downloadCount > 1 || !runAfterDownload) {
-            this._showDownloadCompleteToast(download);
-            this._showDownloadCompleteNotification(download);
+            this._showDownloadCompleteToast();
+            this._showDownloadCompleteNotification();
           }
-          this._progressNotificationInfo.clear();
-          this._downloadCount = 0;
           this._notificationBox.removeNotification(this._progressNotification);
           this._progressNotification = null;
         }
         break;
       case "dl-failed":
         download = aSubject.QueryInterface(Ci.nsIDownload);
         this._showDownloadFailedNotification(download);
         break;
-      case "dl-request":
-        setTimeout(function() {
-          ContextUI.displayNavbar();
-        }, 1000);
-        break;
     }
   },
 
   QueryInterface: function (aIID) {
     if (!aIID.equals(Ci.nsIObserver) &&
         !aIID.equals(Ci.nsISupportsWeakReference) &&
         !aIID.equals(Ci.nsISupports))
       throw Components.results.NS_ERROR_NO_INTERFACE;
--- a/browser/metro/base/moz.build
+++ b/browser/metro/base/moz.build
@@ -1,6 +1,8 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+METRO_CHROME_MANIFESTS += ['tests/mochiperf/metro.ini', 'tests/mochitest/metro.ini']
+XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
deleted file mode 100644
--- a/browser/metro/base/tests/Makefile.in
+++ /dev/null
@@ -1,12 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# For now we're copying the actual Util code.
-# We should make this into a jsm module. See bug 848137
-XPCSHELL_RESOURCES = \
-  $(DEPTH)/browser/metro/base/content/Util.js \
-  $(NULL)
-
-libs:: $(XPCSHELL_RESOURCES)
-	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/unit/
deleted file mode 100644
--- a/browser/metro/base/tests/mochiperf/Makefile.in
+++ /dev/null
@@ -1,17 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ifndef MOZ_DEBUG
-MOCHITEST_METRO_FILES = \
-  ../mochitest/head.js \
-  perfhelpers.js \
-  browser_miscgfx_01.js \
-  browser_tabs_01.js \
-  browser_deck_01.js \
-  browser_msgmgr_01.js \
-  msgmanagerecho.js \
-  browser_layers_01.js \
-  browser_firstx.js \
-  $(NULL)
-endif
--- a/browser/metro/base/tests/mochiperf/browser_deck_01.js
+++ b/browser/metro/base/tests/mochiperf/browser_deck_01.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function test() {
-  let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-  Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);
   runTests();
 }
 
 gTests.push({
   desc: "deck offset",
   run: function run() {
     yield addTab("about:mozilla");
     yield hideContextUI();
--- a/browser/metro/base/tests/mochiperf/browser_firstx.js
+++ b/browser/metro/base/tests/mochiperf/browser_firstx.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function test() {
-  let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-  Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);
   runTests();
 }
 
 gTests.push({
   desc: "first x metrics",
   run: function run() {
     PerfTest.declareTest("5F2A456E-2BB2-4073-A751-936F222FEAE0",
                          "startup perf metrics", "browser", "ux",
--- a/browser/metro/base/tests/mochiperf/browser_layers_01.js
+++ b/browser/metro/base/tests/mochiperf/browser_layers_01.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function test() {
-  let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-  Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);
   runTests();
 }
 
 gTests.push({
   desc: "rotating divs",
   run: function run() {
     yield addTab(chromeRoot + "res/divs_test.html", true);
 
--- a/browser/metro/base/tests/mochiperf/browser_miscgfx_01.js
+++ b/browser/metro/base/tests/mochiperf/browser_miscgfx_01.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function test() {
-  let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-  Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);
   requestLongerTimeout(2);
   runTests();
 }
 
 function tapRadius() {
   let dpi = Util.displayDPI;
   return Services.prefs.getIntPref("ui.dragThresholdX") / 240 * dpi; // 27.999998728434246
 }
--- a/browser/metro/base/tests/mochiperf/browser_msgmgr_01.js
+++ b/browser/metro/base/tests/mochiperf/browser_msgmgr_01.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function test() {
-  let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-  Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);
   runTests();
 }
 
 var EchoServer = {
   _deferred: null,
   _stopwatch: null,
   _browser: null,
 
--- a/browser/metro/base/tests/mochiperf/browser_tabs_01.js
+++ b/browser/metro/base/tests/mochiperf/browser_tabs_01.js
@@ -1,16 +1,14 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 function test() {
-  let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
-  Services.scriptloader.loadSubScript(testDir + "/perfhelpers.js", this);
   runTests();
 }
 
 function timeTab(aUrl) {
   return Task.spawn(function() {
     let stopwatch = new StopWatch(true);
     let tab = Browser.addTab(aUrl, true);
     yield tab.pageShowPromise;
rename from browser/metro/base/tests/mochiperf/perfhelpers.js
rename to browser/metro/base/tests/mochiperf/head.js
--- a/browser/metro/base/tests/mochiperf/perfhelpers.js
+++ b/browser/metro/base/tests/mochiperf/head.js
@@ -1,13 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
+// Load common code from ../mochitest/head.js
+let mochitestDir = getRootDirectory(gTestPath).replace('/mochiperf', '/mochitest');
+Services.scriptloader.loadSubScript(mochitestDir + "head.js", this);
+
 // Misc. constants
 const kInfoHeader = "PERF-TEST | ";
 const kDeclareId = "DECLARE ";
 const kResultsId = "RESULTS ";
 
 // Mochitest log data format version
 const kDataSetVersion = "1";
 
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/mochiperf/metro.ini
@@ -0,0 +1,19 @@
+[DEFAULT]
+# Don't run performance tests in debug builds.
+skip-if = debug
+support-files =
+  head.js
+  msgmanagerecho.js
+  res/ripples.html
+  res/scroll_test.html
+  res/tidevideo.html
+  res/tide.mp4
+  res/divs_test.html
+  res/fx.png
+
+[browser_miscgfx_01.js]
+[browser_tabs_01.js]
+[browser_deck_01.js]
+[browser_msgmgr_01.js]
+[browser_layers_01.js]
+[browser_firstx.js]
deleted file mode 100644
--- a/browser/metro/base/tests/mochiperf/moz.build
+++ /dev/null
@@ -1,6 +0,0 @@
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_DIRS += ['res']
deleted file mode 100644
--- a/browser/metro/base/tests/mochiperf/res/Makefile.in
+++ /dev/null
@@ -1,14 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-ifndef MOZ_DEBUG
-MOCHITEST_METRO_FILES = \
-  ripples.html \
-  scroll_test.html \
-  tidevideo.html \
-  tide.mp4 \
-  divs_test.html \
-  fx.png \
-  $(NULL)
-endif
deleted file mode 100644
--- a/browser/metro/base/tests/mochiperf/res/moz.build
+++ /dev/null
@@ -1,4 +0,0 @@
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
deleted file mode 100644
--- a/browser/metro/base/tests/mochitest/Makefile.in
+++ /dev/null
@@ -1,63 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_METRO_FILES = \
-  head.js \
-  helpers/BookmarksHelper.js \
-  helpers/HistoryHelper.js \
-  helpers/ViewStateHelper.js \
-  browser_bookmarks.js \
-  browser_canonizeURL.js \
-  browser_circular_progress_indicator.js \
-  browser_crashprompt.js \
-  browser_context_menu_tests.js \
-  browser_context_menu_tests_01.html \
-  browser_context_menu_tests_02.html \
-  browser_context_menu_tests_03.html \
-  browser_context_menu_tests_04.html \
-  browser_context_ui.js \
-  browser_downloads.js \
-  browser_findbar.js \
-  browser_findbar.html \
-  browser_form_auto_complete.js \
-  browser_form_auto_complete.html \
-  browser_history.js \
-  browser_inputsource.js \
-  browser_onscreen_keyboard.js \
-  browser_onscreen_keyboard.html \
-  browser_prefs_ui.js \
-  browser_progress_indicator.xul \
-  browser_remotetabs.js \
-  browser_snappedState.js \
-  browser_tabs.js \
-  browser_test.js \
-  browser_tiles.js \
-  browser_tilegrid.xul \
-  browser_topsites.js \
-  browser_urlbar.js \
-  browser_urlbar_highlightURLs.js \
-  browser_urlbar_trimURLs.js \
-  $(NULL)
-
-ifndef MOZ_DEBUG
-MOCHITEST_METRO_FILES += \
-  browser_selection_basic.js \
-  browser_selection_basic.html \
-  browser_selection_textarea.js \
-  browser_selection_textarea.html \
-  browser_selection_frame_content.js \
-  browser_selection_frame_content.html \
-  browser_selection_inputs.js \
-  browser_selection_inputs.html \
-  browser_selection_frame_textarea.js \
-  browser_selection_frame_textarea.html \
-  browser_selection_frame_inputs.js \
-  browser_selection_frame_inputs.html \
-  browser_selection_urlbar.js \
-  browser_selection_contenteditable.js \
-  browser_selection_contenteditable.html \
-  browser_selection_caretfocus.js \
-  browser_selection_caretfocus.html \
-  $(NULL)
-endif
--- a/browser/metro/base/tests/mochitest/browser_prefs_ui.js
+++ b/browser/metro/base/tests/mochitest/browser_prefs_ui.js
@@ -1,46 +1,99 @@
 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
 /* 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 Ci = Components.interfaces;
+const Cm = Components.manager;
+const Cc = Components.classes;
+
+const CONTRACT_ID = "@mozilla.org/xre/runtime;1";
+
+function MockAppInfo() {
+}
+
+MockAppInfo.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIXULRuntime]),
+}
+
+let newFactory = {
+  createInstance: function(aOuter, aIID) {
+    if (aOuter)
+      throw Components.results.NS_ERROR_NO_AGGREGATION;
+    return new MockAppInfo().QueryInterface(aIID);
+  },
+  lockFactory: function(aLock) {
+    throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+  },
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
+};
+
 var SanitizeHelper = {
   _originalSanitizer: null,
 
   MockSanitizer: {
     clearCalled: [],
     clearItem: function clearItem(aItemName) {
       info("Clear item called for: " + aItemName);
       this.clearCalled.push(aItemName);
     }
   },
 
   setUp: function setUp() {
     SanitizeHelper._originalSanitizer = SanitizeUI._sanitizer;
     SanitizeUI._sanitizer = SanitizeHelper.MockSanitizer;
+
+    let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+    this.gAppInfoClassID = registrar.contractIDToCID(CONTRACT_ID);
+    this.gIncOldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
+    registrar.unregisterFactory(this.gAppInfoClassID, this.gIncOldFactory);
+    let components = [MockAppInfo];
+    registrar.registerFactory(this.gAppInfoClassID, "", CONTRACT_ID, newFactory);
+    this.gIncOldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory);
+
+    this.oldPrompt = Services.prompt;
   },
 
   tearDown: function tearDown() {
     SanitizeUI._sanitizer = SanitizeHelper._originalSanitizer;
+
+    if (this.gIncOldFactory) {
+      var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
+      registrar.unregisterFactory(this.gAppInfoClassID, newFactory);
+      registrar.registerFactory(this.gAppInfoClassID, "", CONTRACT_ID, this.gIncOldFactory);
+    }
+    this.gIncOldFactory = null;
+
+    Services.prompt = this.oldPrompt;
   },
 };
 
 function getAllSelected() {
   return document.getElementById("prefs-privdata").querySelectorAll(
     "#prefs-privdata-history[checked], " +
       "#prefs-privdata-other[checked] + #prefs-privdata-subitems .privdata-subitem-item[checked]");
 }
 
 gTests.push({
+  setUp: SanitizeHelper.setUp,
   tearDown: SanitizeHelper.tearDown,
   desc: "Test sanitizer UI",
   run: function testSanitizeUI() {
+    // We want to be able to simulate that a specific button
+    // of the 'clear private data' prompt was pressed.
+    Services.prompt = {
+      confirmEx: function() {
+        return this.retVal;
+      }
+    };
+
     // Show options flyout
     let promise = waitForEvent(FlyoutPanelsUI.PrefsFlyoutPanel._topmostElement, "PopupChanged", 2000);
     FlyoutPanelsUI.show('PrefsFlyoutPanel');
     yield promise;
 
     // Make sure it's opened
     yield waitForEvent(FlyoutPanelsUI.PrefsFlyoutPanel._topmostElement, "transitionend", 1000);
 
@@ -67,18 +120,26 @@ gTests.push({
     // Select only downloads and passwords
     let callItems = ["downloads", "passwords"];
     for (let checkbox of allSelected) {
       if (callItems.indexOf(checkbox.getAttribute("itemName")) === -1) {
         checkbox.removeAttribute("checked");
       }
     }
 
+    // Simulate clicking "button 1", cancel.
+    Services.prompt.retVal = 1;
     let clearButton = document.getElementById("prefs-clear-data");
     clearButton.doCommand();
+    ok(SanitizeHelper.MockSanitizer.clearCalled.length == 0, "Nothing was cleared");
+
+    // We will simulate that "button 0" (which should be the clear button)
+    // was pressed
+    Services.prompt.retVal = 0;
+    clearButton.doCommand();
 
     let clearNotificationDeck = document.getElementById("clear-notification");
     let clearNotificationDone = document.getElementById("clear-notification-done");
 
     // Wait until command is done.
     yield waitForCondition(function (){
       return clearNotificationDeck.selectedPanel == clearNotificationDone;
     }, 1000);
--- a/browser/metro/base/tests/mochitest/head.js
+++ b/browser/metro/base/tests/mochitest/head.js
@@ -29,19 +29,19 @@ if (!splitPath[splitPath.length-1]) {
 // ../mochitest to make sure we're looking for the libs on the right path
 // even for mochiperf tests.
 splitPath.pop();
 splitPath.push('mochitest');
 
 const mochitestPath = splitPath.join('/') + '/';
 
 [
-  "BookmarksHelper.js",
-  "HistoryHelper.js",
-  "ViewStateHelper.js"
+  "helpers/BookmarksHelper.js",
+  "helpers/HistoryHelper.js",
+  "helpers/ViewStateHelper.js"
 ].forEach(function(lib) {
   Services.scriptloader.loadSubScript(mochitestPath + lib, this);
 }, this);
 
 /*=============================================================================
   Metro ui helpers
 =============================================================================*/
 
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/tests/mochitest/metro.ini
@@ -0,0 +1,74 @@
+[DEFAULT]
+support-files =
+  browser_context_menu_tests_01.html
+  browser_context_menu_tests_02.html
+  browser_context_menu_tests_03.html
+  browser_context_menu_tests_04.html
+  browser_findbar.html
+  browser_form_auto_complete.html
+  browser_onscreen_keyboard.html
+  browser_progress_indicator.xul
+  browser_selection_basic.html
+  browser_selection_caretfocus.html
+  browser_selection_contenteditable.html
+  browser_selection_frame_content.html
+  browser_selection_frame_inputs.html
+  browser_selection_frame_textarea.html
+  browser_selection_inputs.html
+  browser_selection_textarea.html
+  browser_tilegrid.xul
+  head.js
+  helpers/BookmarksHelper.js
+  helpers/HistoryHelper.js
+  helpers/ViewStateHelper.js
+  res/image01.png
+  res/textblock01.html
+  res/textinput01.html
+  res/textarea01.html
+  res/testEngine.xml
+  res/blankpage1.html
+  res/blankpage2.html
+  res/blankpage3.html
+
+[browser_bookmarks.js]
+[browser_canonizeURL.js]
+[browser_circular_progress_indicator.js]
+[browser_crashprompt.js]
+[browser_context_menu_tests.js]
+[browser_context_ui.js]
+[browser_downloads.js]
+[browser_findbar.js]
+[browser_form_auto_complete.js]
+[browser_history.js]
+[browser_inputsource.js]
+[browser_onscreen_keyboard.js]
+[browser_prefs_ui.js]
+[browser_remotetabs.js]
+[browser_snappedState.js]
+[browser_tabs.js]
+[browser_test.js]
+[browser_tiles.js]
+[browser_topsites.js]
+[browser_urlbar.js]
+[browser_urlbar_highlightURLs.js]
+[browser_urlbar_trimURLs.js]
+
+# These tests have known failures in debug builds
+[browser_selection_basic.js]
+skip-if = debug
+[browser_selection_textarea.js]
+skip-if = debug
+[browser_selection_frame_content.js]
+skip-if = debug
+[browser_selection_inputs.js]
+skip-if = debug
+[browser_selection_frame_textarea.js]
+skip-if = debug
+[browser_selection_frame_inputs.js]
+skip-if = debug
+[browser_selection_urlbar.js]
+skip-if = debug
+[browser_selection_contenteditable.js]
+skip-if = debug
+[browser_selection_caretfocus.js]
+skip-if = debug
deleted file mode 100644
--- a/browser/metro/base/tests/mochitest/moz.build
+++ /dev/null
@@ -1,6 +0,0 @@
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_DIRS += ['res']
deleted file mode 100644
--- a/browser/metro/base/tests/mochitest/res/Makefile.in
+++ /dev/null
@@ -1,14 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-MOCHITEST_METRO_FILES = \
-  image01.png \
-  textblock01.html \
-  textinput01.html \
-  textarea01.html \
-  testEngine.xml \
-  blankpage1.html \
-  blankpage2.html \
-  blankpage3.html \
-  $(NULL)
deleted file mode 100644
--- a/browser/metro/base/tests/mochitest/res/moz.build
+++ /dev/null
@@ -1,4 +0,0 @@
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
deleted file mode 100644
--- a/browser/metro/base/tests/moz.build
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_DIRS += ['mochitest']
-TEST_DIRS += ['mochiperf']
-
-XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
--- a/browser/metro/base/tests/unit/test_util_extend.js
+++ b/browser/metro/base/tests/unit/test_util_extend.js
@@ -1,11 +1,12 @@
 "use strict";
 
-load("Util.js");
+Components.utils.import("resource:///modules/ContentUtil.jsm");
+let Util = ContentUtil;
 
 function run_test() {
   do_print("Testing Util.extend");
 
   do_print("Check if function is defined");
   do_check_true(!!Util.extend);
 
   do_print("No parameter or null should return a new object");
--- a/browser/metro/base/tests/unit/test_util_populateFragmentFromString.js
+++ b/browser/metro/base/tests/unit/test_util_populateFragmentFromString.js
@@ -1,19 +1,17 @@
 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
 /* 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";
 
-let Cu = Components.utils;
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource:///modules/ContentUtil.jsm");
-load("Util.js");
+Components.utils.import("resource:///modules/ContentUtil.jsm");
+let Util = ContentUtil;
 
 function empty_node(node) {
   let cnode;
   while((cnode = node.firstChild))
       node.removeChild(cnode);
   return node;
 }
 
@@ -29,18 +27,16 @@ function serializeContents(node) {
 }
 
 function run_test() {
   let doc, body, str, expectedResult, frag;
 
   do_print("Testing Util.populateFragmentFromString");
 
   do_check_true(!!Util.populateFragmentFromString);
-  do_check_true(!!ContentUtil.populateFragmentFromString);
-  do_check_eq(ContentUtil.populateFragmentFromString, Util.populateFragmentFromString);
 
   do_print("Loading blank document");
   doc = do_parse_document("blank.xhtml", "application/xhtml+xml");
 
   // sanity check
   do_check_eq(doc.nodeType, 9);
   do_check_true(doc.documentElement.localName != "parsererror");
 
@@ -82,9 +78,9 @@ function run_test() {
                                     frag, str,
                                     { text: "About the" }
                                   );
 
   empty_node(body);
   body.appendChild(frag);
   expectedResult = "<span>About the</span> &lt;body&gt; tag. &amp;copy; 2000 - Some Corp™"
   do_check_eq(serializeContents(body), expectedResult);
-}
\ No newline at end of file
+}
--- a/browser/metro/components/HelperAppDialog.js
+++ b/browser/metro/components/HelperAppDialog.js
@@ -60,17 +60,16 @@ HelperAppLauncherDialog.prototype = {
                             .rootTreeItem
                             .QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindow)
                             .QueryInterface(Ci.nsIDOMChromeWindow);
      return chromeWin;
   },
 
   _showDownloadInfobar: function do_showDownloadInfobar(aLauncher) {
-    Services.obs.notifyObservers(null, "dl-request", "");
     let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
 
     let runButtonText =
               browserBundle.GetStringFromName("downloadRun");
     let saveButtonText =
               browserBundle.GetStringFromName("downloadSave");
     let cancelButtonText =
               browserBundle.GetStringFromName("downloadCancel");
--- a/browser/metro/locales/en-US/chrome/browser.properties
+++ b/browser/metro/locales/en-US/chrome/browser.properties
@@ -31,16 +31,21 @@ contextAppbar2.delete=Delete
 
 # LOCALIZATION NOTE (contextAppbar2.restore): Undoes a previous deletion.
 # Button with this label only appears immediately after a deletion.
 contextAppbar2.restore=Undo delete
 
 # LOCALIZATION NOTE (contextAppbar2.clear): Unselects pages without modification.
 contextAppbar2.clear=Clear selection
 
+# Clear private data
+clearPrivateData.clearButton=Clear
+clearPrivateData.title=Clear Private Data
+clearPrivateData.message=Clear your private data?
+
 # Settings Charms
 aboutCharm1=About
 optionsCharm=Options
 helpOnlineCharm=Help (online)
 
 # General
 # LOCALIZATION NOTE (browserForSaveLocation): Title for the "Save..." file picker dialog
 browserForSaveLocation=Save Location
--- a/browser/metro/moz.build
+++ b/browser/metro/moz.build
@@ -10,11 +10,8 @@ DIRS += [
     'modules',
     'theme',
     'profile',
     'locales',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['shell']
-
-TEST_DIRS += ['base/tests']
-
--- a/browser/metro/profile/metro.js
+++ b/browser/metro/profile/metro.js
@@ -608,17 +608,16 @@ pref("browser.safebrowsing.provider.0.ge
 // HTML report pages
 pref("browser.safebrowsing.provider.0.reportGenericURL", "http://{moz:locale}.phish-generic.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportErrorURL", "http://{moz:locale}.phish-error.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportPhishURL", "http://{moz:locale}.phish-report.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportMalwareURL", "http://{moz:locale}.malware-report.mozilla.com/?hl={moz:locale}");
 pref("browser.safebrowsing.provider.0.reportMalwareErrorURL", "http://{moz:locale}.malware-error.mozilla.com/?hl={moz:locale}");
 
 // FAQ URLs
-pref("browser.safebrowsing.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/phishing-protection/");
 pref("browser.geolocation.warning.infoURL", "https://www.mozilla.org/%LOCALE%/firefox/geolocation/");
 
 // Name of the about: page contributed by safebrowsing to handle display of error
 // pages on phishing/malware hits.  (bug 399233)
 pref("urlclassifier.alternate_error_page", "blocked");
 
 // The number of random entries to send with a gethash request.
 pref("urlclassifier.gethashnoise", 4);
--- a/browser/metro/theme/browser.css
+++ b/browser/metro/theme/browser.css
@@ -443,38 +443,16 @@ documenttab[selected] .documenttab-selec
  * toolbar portion of the navbar. */
 #navbar {
   visibility: visible;
 }
 #navbar:not([hiding]):not([visible]) > #toolbar-overlay {
   visibility: hidden;
 }
 
-.circularprogressindicator-progressRing {
-  visibility: visible;
-  margin: 0 @toolbar_horizontal_spacing@;
-  pointer-events:none;
-  position: absolute;
-}
-.circularprogressindicator-progressTrack {
-  visibility: visible;
-  margin: 0 @toolbar_horizontal_spacing@;
-  pointer-events: none;
-  position: absolute;
-  width: 40px;
-  height: 40px;
-  background-repeat: no-repeat;
-  background-size: 40px 40px;
-  background-image: url(chrome://browser/skin/images/progresscircle-bg.png);
-}
-.circularprogressindicator-progressRing:not([progress]),
-.circularprogressindicator-progressTrack:not([progress]) {
-  visibility: hidden;
-}
-
 /* Progress meter ---------------------------------------------------------- */
 
 #progress-container {
   display: block;
   position: absolute;
   top: -@progress_height@;
   height: @progress_height@;
   width: 100%;
@@ -760,24 +738,27 @@ documenttab[selected] .documenttab-selec
   visibility: hidden;
   pointer-events: none;
 }
 
 #toolbar[viewstate="snapped"] #toolbar-contextual {
   visibility: collapse;
 }
 
-.circularprogressindicator-progressButton {
-  margin: 0 @toolbar_horizontal_spacing@;
+#download-progress:not([progress]) {
+  visibility: collapse;
+}
+
+#download-progress {
   -moz-image-region: rect(0px, 40px, 40px, 0px) !important;
 }
-.circularprogressindicator-progressButton:hover {
+#download-progress:hover {
   -moz-image-region: rect(40px, 40px, 80px, 0px) !important;
 }
-.circularprogressindicator-progressButton:active {
+#download-progress:active {
   -moz-image-region: rect(80px, 40px, 120px, 0px) !important;
 }
 
 #pin-button {
   list-style-image: url(chrome://browser/skin/images/navbar-pin.png);
 }
 
 #star-button {
new file mode 100644
--- /dev/null
+++ b/browser/metro/theme/circularprogress.css
@@ -0,0 +1,31 @@
+/* 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/. */
+
+%filter substitution
+%include defines.inc
+
+.circularprogressindicator-progressButton,
+.circularprogressindicator-progressRing,
+.circularprogressindicator-progressTrack {
+  margin: 0 @toolbar_horizontal_spacing@;
+}
+
+.circularprogressindicator-progressRing,
+.circularprogressindicator-progressTrack {
+  pointer-events:none;
+  position: absolute;
+}
+
+.circularprogressindicator-progressTrack {
+  width: 40px;
+  height: 40px;
+  background-repeat: no-repeat;
+  background-size: 40px 40px;
+  background-image: url(chrome://browser/skin/images/progresscircle-bg.png);
+}
+
+.circularprogressindicator-progressRing:not([progress]),
+.circularprogressindicator-progressTrack:not([progress]) {
+  visibility: hidden;
+}
--- a/browser/metro/theme/jar.mn
+++ b/browser/metro/theme/jar.mn
@@ -5,16 +5,17 @@
 
 
 chrome.jar:
 % skin browser classic/1.0 %skin/
   skin/aboutPage.css                        (aboutPage.css)
   skin/aboutAddons.css                      (aboutAddons.css)
   skin/about.css                            (about.css)
 * skin/flyoutpanel.css                      (flyoutpanel.css)
+* skin/circularprogress.css                 (circularprogress.css)
 * skin/cssthrobber.css                      (cssthrobber.css)
 * skin/browser.css                          (browser.css)
 * skin/content.css                          (content.css)
   skin/config.css                           (config.css)
 * skin/platform.css                         (platform.css)
 * skin/tiles.css                            (tiles.css)
   skin/touchcontrols.css                    (touchcontrols.css)
   skin/netError.css                         (netError.css)
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1555,16 +1555,21 @@ nsScriptSecurityManager::CheckLoadURIStr
 {
     nsresult rv;
     nsCOMPtr<nsIURI> target;
     rv = NS_NewURI(getter_AddRefs(target), aTargetURIStr,
                    nullptr, nullptr, sIOService);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
+    if (rv == NS_ERROR_DOM_BAD_URI) {
+        // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
+        // return values.
+        return rv;
+    }
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Now start testing fixup -- since aTargetURIStr is a string, not
     // an nsIURI, we may well end up fixing it up before loading.
     // Note: This needs to stay in sync with the nsIURIFixup api.
     nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
     if (!fixup) {
         return rv;
@@ -1579,16 +1584,21 @@ nsScriptSecurityManager::CheckLoadURIStr
     };
 
     for (uint32_t i = 0; i < ArrayLength(flags); ++i) {
         rv = fixup->CreateFixupURI(aTargetURIStr, flags[i], nullptr,
                                    getter_AddRefs(target));
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
+        if (rv == NS_ERROR_DOM_BAD_URI) {
+            // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
+            // return values.
+            return rv;
+        }
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return rv;
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::CheckFunctionAccess(JSContext *aCx, void *aFunObj,
--- a/configure.in
+++ b/configure.in
@@ -9202,24 +9202,21 @@ MOZ_ARG_WITH_STRING(intl-api,
 [  --with-intl-api, --with-intl-api=build, --without-intl-api
     Determine the status of the ECMAScript Internationalization API.  The first
     (or lack of any of these) builds and exposes the API.  The second builds it
     but doesn't use ICU or expose the API to script.  The third doesn't build
     ICU at all.],
     WITH_INTL="--with-intl-api=$withval"
 ])
 if test -z "$WITH_INTL"; then
-if test "$NIGHTLY_BUILD" = "1" -a "$MOZ_BUILD_APP" = "browser" -a -z "$DEVELOPER_OPTIONS"; then
-    # In desktop nightlies the Internationalization API is disabled, but all
-    # code for it is still built.  Bug 853301 will remove this so that it's
-    # built and the API is enabled.
-    WITH_INTL="--with-intl-api=build"
+if test "$MOZ_BUILD_APP" = "browser"; then
+    WITH_INTL="--with-intl-api"
 else
-    # Internationalization isn't built or exposed by default in non-desktop and
-    # non-nightly builds.  Bugs to enable:
+    # Internationalization isn't built or exposed by default in non-desktop
+    # builds.  Bugs to enable:
     #
     #   Android:  bug 864843
     #   B2G:      bug 866301
     WITH_INTL="--without-intl-api"
 fi
 fi
 ac_configure_args="$ac_configure_args $WITH_INTL"
 
--- a/content/base/public/Element.h
+++ b/content/base/public/Element.h
@@ -720,19 +720,19 @@ public:
   {
     return false;
   }
 
   virtual void SetUndoScope(bool aUndoScope, ErrorResult& aError)
   {
   }
 
-  virtual void GetInnerHTML(nsAString& aInnerHTML, ErrorResult& aError);
+  NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
   virtual void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
-  void GetOuterHTML(nsAString& aOuterHTML, ErrorResult& aError);
+  void GetOuterHTML(nsAString& aOuterHTML);
   void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
   void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
                           ErrorResult& aError);
 
   //----------------------------------------
 
   /**
    * Add a script event listener with the given event handler name
@@ -1119,17 +1119,17 @@ private:
    * Get this element's client area rect in app units.
    * @return the frame's client area
    */
   nsRect GetClientAreaRect();
 
   nsIScrollableFrame* GetScrollFrame(nsIFrame **aStyledFrame = nullptr,
                                      bool aFlushLayout = true);
 
-  nsresult GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
+  void GetMarkup(bool aIncludeSelf, nsAString& aMarkup);
 
   // Data members
   nsEventStates mState;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID)
 
 inline bool
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -3102,24 +3102,25 @@ Serialize(Element* aRoot, bool aDescende
 
       if (aDescendentsOnly && current == aRoot) {
         return builder.ToString(aOut);
       }
     }
   }
 }
 
-nsresult
+void
 Element::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
 {
   aMarkup.Truncate();
 
   nsIDocument* doc = OwnerDoc();
   if (IsInHTMLDocument()) {
-    return Serialize(this, !aIncludeSelf, aMarkup) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+    Serialize(this, !aIncludeSelf, aMarkup);
+    return;
   }
 
   nsAutoString contentType;
   doc->GetContentType(contentType);
 
   nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
   if (!docEncoder) {
     docEncoder =
@@ -3130,17 +3131,17 @@ Element::GetMarkup(bool aIncludeSelf, ns
   }
   if (!docEncoder) {
     // This could be some type for which we create a synthetic document.  Try
     // again as XML
     contentType.AssignLiteral("application/xml");
     docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "application/xml");
   }
 
-  NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE_VOID(docEncoder);
 
   uint32_t flags = nsIDocumentEncoder::OutputEncodeBasicEntities |
                    // Output DOM-standard newlines
                    nsIDocumentEncoder::OutputLFLineBreak |
                    // Don't do linebreaking that's not present in
                    // the source
                    nsIDocumentEncoder::OutputRaw |
                    // Only check for mozdirty when necessary (bug 599983)
@@ -3148,29 +3149,29 @@ Element::GetMarkup(bool aIncludeSelf, ns
 
   if (IsEditable()) {
     nsIEditor* editor = GetEditorInternal();
     if (editor && editor->OutputsMozDirty()) {
       flags &= ~nsIDocumentEncoder::OutputIgnoreMozDirty;
     }
   }
 
-  nsresult rv = docEncoder->NativeInit(doc, contentType, flags);
-  NS_ENSURE_SUCCESS(rv, rv);
+  DebugOnly<nsresult> rv = docEncoder->NativeInit(doc, contentType, flags);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   if (aIncludeSelf) {
     docEncoder->SetNativeNode(this);
   } else {
     docEncoder->SetNativeContainerNode(this);
   }
   rv = docEncoder->EncodeToString(aMarkup);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
   if (!aIncludeSelf) {
     doc->SetCachedEncoder(docEncoder.forget());
   }
-  return rv;
 }
 
 /**
  * Fire mutation events for changes caused by parsing directly into a
  * context node.
  *
  * @param aDoc the document of the node
  * @param aDest the destination node that got stuff appended to it
@@ -3192,20 +3193,21 @@ FireMutationEventsForDirectParsing(nsIDo
          child;
          child = child->GetNextSibling()) {
       childNodes.AppendElement(child);
     }
     Element::FireNodeInserted(aDoc, aDest, childNodes);
   }
 }
 
-void
-Element::GetInnerHTML(nsAString& aInnerHTML, ErrorResult& aError)
+NS_IMETHODIMP
+Element::GetInnerHTML(nsAString& aInnerHTML)
 {
-  aError = GetMarkup(false, aInnerHTML);
+  GetMarkup(false, aInnerHTML);
+  return NS_OK;
 }
 
 void
 Element::SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError)
 {
   FragmentOrElement* target = this;
   // Handle template case.
   if (nsNodeUtils::IsTemplateElement(target)) {
@@ -3261,19 +3263,19 @@ Element::SetInnerHTML(const nsAString& a
 
       static_cast<nsINode*>(target)->AppendChild(*fragment, aError);
       mb.NodesAdded();
     }
   }
 }
 
 void
-Element::GetOuterHTML(nsAString& aOuterHTML, ErrorResult& aError)
+Element::GetOuterHTML(nsAString& aOuterHTML)
 {
-  aError = GetMarkup(true, aOuterHTML);
+  GetMarkup(true, aOuterHTML);
 }
 
 void
 Element::SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError)
 {
   nsCOMPtr<nsINode> parent = GetParentNode();
   if (!parent) {
     return;
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -636,21 +636,25 @@ nsCopySupport::FireClipboardEvent(int32_
     if (!content)
       return false;
   }
 
   // It seems to be unsafe to fire an event handler during reflow (bug 393696)
   if (!nsContentUtils::IsSafeToRunScript())
     return false;
 
+  int32_t type = -1;
+  nsCOMPtr<nsIDocShell> docShell = do_GetInterface(piWindow);
+  bool chromeShell = (docShell && NS_SUCCEEDED(docShell->GetItemType(&type)) &&
+                      type == nsIDocShellTreeItem::typeChrome);
+
   // next, fire the cut, copy or paste event
-  // XXXndeakin Bug 844941 - why was a preference added here without a running-in-chrome check?
   bool doDefault = true;
   nsRefPtr<nsDOMDataTransfer> clipboardData;
-  if (Preferences::GetBool("dom.event.clipboardevents.enabled", true)) {
+  if (chromeShell || Preferences::GetBool("dom.event.clipboardevents.enabled", true)) {
     clipboardData = new nsDOMDataTransfer(aType, aType == NS_PASTE, aClipboardType);
 
     nsEventStatus status = nsEventStatus_eIgnore;
     InternalClipboardEvent evt(true, aType);
     evt.clipboardData = clipboardData;
     nsEventDispatcher::Dispatch(content, presShell->GetPresContext(), &evt, nullptr,
                                 &status);
     // If the event was cancelled, don't do the clipboard operation
--- a/content/base/src/nsLineBreaker.cpp
+++ b/content/base/src/nsLineBreaker.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsLineBreaker.h"
 #include "nsContentUtils.h"
 #include "nsILineBreaker.h"
 #include "gfxFont.h" // for the gfxTextRun::CompressedGlyph::FLAG_BREAK_TYPE_* values
 #include "nsHyphenationManager.h"
 #include "nsHyphenator.h"
+#include "mozilla/gfx/2D.h"
 
 nsLineBreaker::nsLineBreaker()
   : mCurrentWordLanguage(nullptr),
     mCurrentWordContainsMixedLang(false),
     mCurrentWordContainsComplexChar(false),
     mAfterBreakableSpace(false), mBreakHere(false),
     mWordBreak(nsILineBreaker::kWordBreak_Normal)
 {
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -15,16 +15,18 @@
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CanvasUtils.h"
 #include "gfxFont.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/CanvasGradient.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasPattern.h"
 #include "mozilla/gfx/Rect.h"
+#include "mozilla/gfx/2D.h"
+#include "gfx2DGlue.h"
 
 class nsXULElement;
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
 }
 
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -1588,17 +1588,17 @@ nsEventStateManager::HandleCrossProcessE
 // is a one-shot that will be cancelled when the user moves enough to fire
 // a drag.
 //
 void
 nsEventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
                                           nsIFrame* inDownFrame,
                                           WidgetGUIEvent* inMouseDownEvent)
 {
-  if (!inMouseDownEvent->mFlags.mIsTrusted)
+  if (!inMouseDownEvent->mFlags.mIsTrusted || IsRemoteTarget(mGestureDownContent))
     return;
 
   // just to be anal (er, safe)
   if (mClickHoldTimer) {
     mClickHoldTimer->Cancel();
     mClickHoldTimer = nullptr;
   }
 
--- a/content/html/content/src/HTMLElement.cpp
+++ b/content/html/content/src/HTMLElement.cpp
@@ -11,19 +11,17 @@ namespace mozilla {
 namespace dom {
 
 class HTMLElement MOZ_FINAL : public nsGenericHTMLElement
 {
 public:
   HTMLElement(already_AddRefed<nsINodeInfo> aNodeInfo);
   virtual ~HTMLElement();
 
-  using nsGenericHTMLElement::GetInnerHTML;
-  virtual void GetInnerHTML(nsAString& aInnerHTML,
-                            mozilla::ErrorResult& aError) MOZ_OVERRIDE;
+  NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo* aNodeInfo,
                          nsINode** aResult) const MOZ_OVERRIDE;
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx,
                              JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 };
@@ -34,33 +32,33 @@ HTMLElement::HTMLElement(already_AddRefe
 }
 
 HTMLElement::~HTMLElement()
 {
 }
 
 NS_IMPL_ELEMENT_CLONE(HTMLElement)
 
-void
-HTMLElement::GetInnerHTML(nsAString& aInnerHTML, ErrorResult& aError)
+NS_IMETHODIMP
+HTMLElement::GetInnerHTML(nsAString& aInnerHTML)
 {
   /**
    * nsGenericHTMLElement::GetInnerHTML escapes < and > characters (at least).
    * .innerHTML should return the HTML code for xmp and plaintext element.
    *
    * This code is a workaround until we implement a HTML5 Serializer
    * with this behavior.
    */
   if (mNodeInfo->Equals(nsGkAtoms::xmp) ||
       mNodeInfo->Equals(nsGkAtoms::plaintext)) {
     nsContentUtils::GetNodeTextContent(this, false, aInnerHTML);
-    return;
+    return NS_OK;
   }
 
-  nsGenericHTMLElement::GetInnerHTML(aInnerHTML, aError);
+  return nsGenericHTMLElement::GetInnerHTML(aInnerHTML);
 }
 
 JSObject*
 HTMLElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
 {
   return dom::HTMLElementBinding::Wrap(aCx, aScope, this);
 }
 
--- a/content/html/content/src/HTMLScriptElement.cpp
+++ b/content/html/content/src/HTMLScriptElement.cpp
@@ -221,20 +221,21 @@ HTMLScriptElement::AfterSetAttr(int32_t 
 {
   if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
     mForceAsync = false;
   }
   return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
                                             aNotify);
 }
 
-void
-HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML, ErrorResult& aError)
+NS_IMETHODIMP
+HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML)
 {
   nsContentUtils::GetNodeTextContent(this, false, aInnerHTML);
+  return NS_OK;
 }
 
 void
 HTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML,
                                 ErrorResult& aError)
 {
   aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
 }
--- a/content/html/content/src/HTMLScriptElement.h
+++ b/content/html/content/src/HTMLScriptElement.h
@@ -25,19 +25,17 @@ public:
 
   HTMLScriptElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                       FromParser aFromParser);
   virtual ~HTMLScriptElement();
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
-  using nsGenericHTMLElement::GetInnerHTML;
-  virtual void GetInnerHTML(nsAString& aInnerHTML,
-                            mozilla::ErrorResult& aError) MOZ_OVERRIDE;
+  NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) MOZ_OVERRIDE;
   using nsGenericHTMLElement::SetInnerHTML;
   virtual void SetInnerHTML(const nsAString& aInnerHTML,
                             mozilla::ErrorResult& aError) MOZ_OVERRIDE;
 
   // nsIDOMHTMLScriptElement
   NS_DECL_NSIDOMHTMLSCRIPTELEMENT
 
   // nsIScriptElement
--- a/content/html/content/src/HTMLStyleElement.cpp
+++ b/content/html/content/src/HTMLStyleElement.cpp
@@ -196,20 +196,21 @@ HTMLStyleElement::UnsetAttr(int32_t aNam
     } else if (aAttribute == nsGkAtoms::scoped) {
       UpdateStyleSheetScopedness(false);
     }
   }
 
   return rv;
 }
 
-void
-HTMLStyleElement::GetInnerHTML(nsAString& aInnerHTML, ErrorResult& aError)
+NS_IMETHODIMP
+HTMLStyleElement::GetInnerHTML(nsAString& aInnerHTML)
 {
   nsContentUtils::GetNodeTextContent(this, false, aInnerHTML);
+  return NS_OK;
 }
 
 void
 HTMLStyleElement::SetInnerHTML(const nsAString& aInnerHTML,
                                ErrorResult& aError)
 {
   SetEnableUpdates(false);
 
--- a/content/html/content/src/HTMLStyleElement.h
+++ b/content/html/content/src/HTMLStyleElement.h
@@ -28,19 +28,17 @@ public:
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // CC
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLStyleElement,
                                            nsGenericHTMLElement)
 
-  using nsGenericHTMLElement::GetInnerHTML;
-  virtual void GetInnerHTML(nsAString& aInnerHTML,
-                            mozilla::ErrorResult& aError) MOZ_OVERRIDE;
+  NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) MOZ_OVERRIDE;
   using nsGenericHTMLElement::SetInnerHTML;
   virtual void SetInnerHTML(const nsAString& aInnerHTML,
                             mozilla::ErrorResult& aError) MOZ_OVERRIDE;
 
   // nsIDOMHTMLStyleElement
   NS_DECL_NSIDOMHTMLSTYLEELEMENT
 
   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -459,19 +459,18 @@ public:
     return NS_OK;
   }
   NS_IMETHOD SetSpellcheck(bool aSpellcheck) MOZ_FINAL {
     mozilla::ErrorResult rv;
     SetSpellcheck(aSpellcheck, rv);
     return rv.ErrorCode();
   }
   NS_IMETHOD GetOuterHTML(nsAString& aOuterHTML) MOZ_FINAL {
-    mozilla::ErrorResult rv;
-    mozilla::dom::Element::GetOuterHTML(aOuterHTML, rv);
-    return rv.ErrorCode();
+    mozilla::dom::Element::GetOuterHTML(aOuterHTML);
+    return NS_OK;
   }
   NS_IMETHOD SetOuterHTML(const nsAString& aOuterHTML) MOZ_FINAL {
     mozilla::ErrorResult rv;
     mozilla::dom::Element::SetOuterHTML(aOuterHTML, rv);
     return rv.ErrorCode();
   }                                                                            \
   NS_IMETHOD InsertAdjacentHTML(const nsAString& position,
                                 const nsAString& text) MOZ_FINAL;
@@ -523,21 +522,18 @@ public:
     mozilla::ErrorResult rv;
     Focus(rv);
     return rv.ErrorCode();
   }
   NS_IMETHOD GetDraggable(bool* aDraggable) MOZ_FINAL {
     *aDraggable = Draggable();
     return NS_OK;
   }
-  using mozilla::dom::Element::GetInnerHTML;
-  NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) MOZ_FINAL {
-    mozilla::ErrorResult rv;
-    GetInnerHTML(aInnerHTML, rv);
-    return rv.ErrorCode();
+  NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) MOZ_OVERRIDE {
+    return mozilla::dom::Element::GetInnerHTML(aInnerHTML);
   }
   using mozilla::dom::Element::SetInnerHTML;
   NS_IMETHOD SetInnerHTML(const nsAString& aInnerHTML) MOZ_FINAL {
     mozilla::ErrorResult rv;
     SetInnerHTML(aInnerHTML, rv);
     return rv.ErrorCode();
   }
 
--- a/content/media/AudioNodeStream.cpp
+++ b/content/media/AudioNodeStream.cpp
@@ -12,23 +12,22 @@
 #include "AudioParamTimeline.h"
 
 using namespace mozilla::dom;
 
 namespace mozilla {
 
 /**
  * An AudioNodeStream produces a single audio track with ID
- * AUDIO_NODE_STREAM_TRACK_ID. This track has rate AudioContext::sIdealAudioRate
+ * AUDIO_TRACK. This track has rate AudioContext::sIdealAudioRate
  * for regular audio contexts, and the rate requested by the web content
  * for offline audio contexts.
  * Each chunk in the track is a single block of WEBAUDIO_BLOCK_SIZE samples.
  * Note: This must be a different value than MEDIA_STREAM_DEST_TRACK_ID
  */
-static const int AUDIO_NODE_STREAM_TRACK_ID = 1;
 
 AudioNodeStream::~AudioNodeStream()
 {
   MOZ_COUNT_DTOR(AudioNodeStream);
 }
 
 void
 AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, MediaStream* aRelativeToStream,
@@ -404,17 +403,17 @@ AudioNodeStream::ProduceOutput(GraphTime
 {
   if (mMarkAsFinishedAfterThisBlock) {
     // This stream was finished the last time that we looked at it, and all
     // of the depending streams have finished their output as well, so now
     // it's time to mark this stream as finished.
     FinishOutput();
   }
 
-  EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate);
+  EnsureTrack(AUDIO_TRACK, mSampleRate);
 
   uint16_t outputCount = std::max(uint16_t(1), mEngine->OutputCount());
   mLastChunks.SetLength(outputCount);
 
   if (mMuted) {
     for (uint16_t i = 0; i < outputCount; ++i) {
       mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
     }
@@ -436,68 +435,68 @@ AudioNodeStream::ProduceOutput(GraphTime
     } else {
       mEngine->ProduceAudioBlocksOnPorts(this, inputChunks, mLastChunks, &finished);
     }
     if (finished) {
       mMarkAsFinishedAfterThisBlock = true;
     }
   }
 
-  if (mDisabledTrackIDs.Contains(AUDIO_NODE_STREAM_TRACK_ID)) {
+  if (mDisabledTrackIDs.Contains(static_cast<TrackID>(AUDIO_TRACK))) {
     for (uint32_t i = 0; i < mLastChunks.Length(); ++i) {
       mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
     }
   }
 
   AdvanceOutputSegment();
 }
 
 void
 AudioNodeStream::AdvanceOutputSegment()
 {
-  StreamBuffer::Track* track = EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate);
+  StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK, mSampleRate);
   AudioSegment* segment = track->Get<AudioSegment>();
 
   if (mKind == MediaStreamGraph::EXTERNAL_STREAM) {
     segment->AppendAndConsumeChunk(&mLastChunks[0]);
   } else {
     segment->AppendNullData(mLastChunks[0].GetDuration());
   }
 
   for (uint32_t j = 0; j < mListeners.Length(); ++j) {
     MediaStreamListener* l = mListeners[j];
     AudioChunk copyChunk = mLastChunks[0];
     AudioSegment tmpSegment;
     tmpSegment.AppendAndConsumeChunk(&copyChunk);
-    l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
+    l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
                                 mSampleRate, segment->GetDuration(), 0,
                                 tmpSegment);
   }
 }
 
 TrackTicks
 AudioNodeStream::GetCurrentPosition()
 {
-  return EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate)->Get<AudioSegment>()->GetDuration();
+  return EnsureTrack(AUDIO_TRACK, mSampleRate)->Get<AudioSegment>()->GetDuration();
 }
 
 void
 AudioNodeStream::FinishOutput()
 {
   if (IsFinishedOnGraphThread()) {
     return;
   }
 
-  StreamBuffer::Track* track = EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate);
+  StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK, mSampleRate);
   track->SetEnded();
   FinishOnGraphThread();
 
   for (uint32_t j = 0; j < mListeners.Length(); ++j) {
     MediaStreamListener* l = mListeners[j];
     AudioSegment emptySegment;
-    l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
+    l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
                                 mSampleRate,
                                 track->GetSegment()->GetDuration(),
                                 MediaStreamListener::TRACK_EVENT_ENDED, emptySegment);
   }
 }
 
 }
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -112,17 +112,17 @@ AudioBuffer::RestoreJSChannelData(JSCont
 void
 AudioBuffer::CopyFromChannel(const Float32Array& aDestination, uint32_t aChannelNumber,
                              uint32_t aStartInChannel, ErrorResult& aRv)
 {
   uint32_t length = aDestination.Length();
   CheckedInt<uint32_t> end = aStartInChannel;
   end += length;
   if (aChannelNumber >= NumberOfChannels() ||
-      !end.isValid() || end.value() >= mLength) {
+      !end.isValid() || end.value() > mLength) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   if (!mSharedChannels && JS_GetTypedArrayLength(mJSChannels[aChannelNumber]) != mLength) {
     // The array was probably neutered
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
@@ -138,17 +138,17 @@ void
 AudioBuffer::CopyToChannel(JSContext* aJSContext, const Float32Array& aSource,
                            uint32_t aChannelNumber, uint32_t aStartInChannel,
                            ErrorResult& aRv)
 {
   uint32_t length = aSource.Length();
   CheckedInt<uint32_t> end = aStartInChannel;
   end += length;
   if (aChannelNumber >= NumberOfChannels() ||
-      !end.isValid() || end.value() >= mLength) {
+      !end.isValid() || end.value() > mLength) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   if (!mSharedChannels && JS_GetTypedArrayLength(mJSChannels[aChannelNumber]) != mLength) {
     // The array was probably neutered
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
--- a/content/media/webaudio/AudioDestinationNode.cpp
+++ b/content/media/webaudio/AudioDestinationNode.cpp
@@ -1,20 +1,25 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "AudioDestinationNode.h"
 #include "mozilla/dom/AudioDestinationNodeBinding.h"
+#include "mozilla/Preferences.h"
+#include "AudioChannelAgent.h"
 #include "AudioNodeEngine.h"
 #include "AudioNodeStream.h"
 #include "MediaStreamGraph.h"
 #include "OfflineAudioCompletionEvent.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIDocShell.h"
+#include "nsIDocument.h"
 
 namespace mozilla {
 namespace dom {
 
 class OfflineDestinationNodeEngine : public AudioNodeEngine
 {
 public:
   typedef AutoFallibleTArray<nsAutoArrayPtr<float>, 2> InputChannels;
@@ -208,17 +213,31 @@ public:
   enum Parameters {
     VOLUME,
   };
 
 private:
   float mVolume;
 };
 
-NS_IMPL_ISUPPORTS_INHERITED0(AudioDestinationNode, AudioNode)
+static bool UseAudioChannelService()
+{
+  return Preferences::GetBool("media.useAudioChannelService");
+}
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED_1(AudioDestinationNode, AudioNode,
+                                     mAudioChannelAgent)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
+  NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
+NS_INTERFACE_MAP_END_INHERITING(AudioNode)
+
+NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode)
+NS_IMPL_RELEASE_INHERITED(AudioDestinationNode, AudioNode)
 
 AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
                                            bool aIsOffline,
                                            uint32_t aNumberOfChannels,
                                            uint32_t aLength,
                                            float aSampleRate)
   : AudioNode(aContext,
               aIsOffline ? aNumberOfChannels : 2,
@@ -230,21 +249,56 @@ AudioDestinationNode::AudioDestinationNo
                             MediaStreamGraph::CreateNonRealtimeInstance() :
                             MediaStreamGraph::GetInstance();
   AudioNodeEngine* engine = aIsOffline ?
                             new OfflineDestinationNodeEngine(this, aNumberOfChannels,
                                                              aLength, aSampleRate) :
                             static_cast<AudioNodeEngine*>(new DestinationNodeEngine(this));
 
   mStream = graph->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM);
+
+  if (!aIsOffline && UseAudioChannelService()) {
+    mAudioChannelAgent = new AudioChannelAgent();
+    mAudioChannelAgent->InitWithWeakCallback(nsIAudioChannelAgent::AUDIO_AGENT_CHANNEL_NORMAL,
+                                             this);
+
+    nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
+    if (target) {
+      target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
+                                     /* useCapture = */ true,
+                                     /* wantsUntrusted = */ false);
+    }
+
+    nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
+    if (docshell) {
+      bool isActive = false;
+      docshell->GetIsActive(&isActive);
+      mAudioChannelAgent->SetVisibilityState(isActive);
+    }
+
+    int32_t state = 0;
+    mAudioChannelAgent->StartPlaying(&state);
+    SetCanPlay(state == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
+  }
 }
 
 void
 AudioDestinationNode::DestroyMediaStream()
 {
+  if (mAudioChannelAgent && !Context()->IsOffline()) {
+    mAudioChannelAgent->StopPlaying();
+    mAudioChannelAgent = nullptr;
+
+    nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
+    NS_ENSURE_TRUE_VOID(target);
+
+    target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
+                                      /* useCapture = */ true);
+  }
+
   if (!mStream)
     return;
 
   MediaStreamGraph* graph = mStream->Graph();
   if (graph->IsNonRealtime()) {
     MediaStreamGraph::DestroyNonRealtimeInstance(graph);
   }
   AudioNode::DestroyMediaStream();
@@ -299,10 +353,43 @@ AudioDestinationNode::WrapObject(JSConte
 
 void
 AudioDestinationNode::StartRendering()
 {
   mOfflineRenderingRef.Take(this);
   mStream->Graph()->StartNonRealtimeProcessing(mFramesToProduce);
 }
 
+void
+AudioDestinationNode::SetCanPlay(bool aCanPlay)
+{
+  mStream->SetTrackEnabled(AudioNodeStream::AUDIO_TRACK, aCanPlay);
+}
+
+NS_IMETHODIMP
+AudioDestinationNode::HandleEvent(nsIDOMEvent* aEvent)
+{
+  nsAutoString type;
+  aEvent->GetType(type);
+
+  if (!type.EqualsLiteral("visibilitychange")) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
+  NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE);
+
+  bool isActive = false;
+  docshell->GetIsActive(&isActive);
+
+  mAudioChannelAgent->SetVisibilityState(isActive);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+AudioDestinationNode::CanPlayChanged(int32_t aCanPlay)
+{
+  SetCanPlay(aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
+  return NS_OK;
+}
+
 }
 }
--- a/content/media/webaudio/AudioDestinationNode.h
+++ b/content/media/webaudio/AudioDestinationNode.h
@@ -3,36 +3,41 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef AudioDestinationNode_h_
 #define AudioDestinationNode_h_
 
 #include "AudioNode.h"
+#include "nsIDOMEventListener.h"
+#include "nsIAudioChannelAgent.h"
 
 namespace mozilla {
 namespace dom {
 
 class AudioContext;
 
 class AudioDestinationNode : public AudioNode
+                           , public nsIDOMEventListener
+                           , public nsIAudioChannelAgentCallback
 {
 public:
   // This node type knows what MediaStreamGraph to use based on
   // whether it's in offline mode.
   AudioDestinationNode(AudioContext* aContext,
                        bool aIsOffline,
                        uint32_t aNumberOfChannels = 0,
                        uint32_t aLength = 0,
                        float aSampleRate = 0.0f);
 
   virtual void DestroyMediaStream() MOZ_OVERRIDE;
 
   NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioDestinationNode, AudioNode)
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   virtual uint16_t NumberOfOutputs() const MOZ_FINAL MOZ_OVERRIDE
   {
     return 0;
   }
@@ -43,18 +48,28 @@ public:
 
   void Mute();
   void Unmute();
 
   void StartRendering();
 
   void OfflineShutdown();
 
+  // nsIDOMEventListener
+  NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
+
+  // nsIAudioChannelAgentCallback
+  NS_IMETHOD CanPlayChanged(int32_t aCanPlay);
+
 private:
+  void SetCanPlay(bool aCanPlay);
+
   SelfReference<AudioDestinationNode> mOfflineRenderingRef;
   uint32_t mFramesToProduce;
+
+  nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
 };
 
 }
 }
 
 #endif
 
--- a/content/media/webaudio/BiquadFilterNode.cpp
+++ b/content/media/webaudio/BiquadFilterNode.cpp
@@ -20,23 +20,24 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_4(Biq
                                      mFrequency, mDetune, mQ, mGain)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BiquadFilterNode)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(BiquadFilterNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(BiquadFilterNode, AudioNode)
 
-void SetParamsOnBiquad(WebCore::Biquad& aBiquad,
-                       float aSampleRate,
-                       BiquadFilterType aType,
-                       double aFrequency,
-                       double aQ,
-                       double aGain,
-                       double aDetune)
+static void
+SetParamsOnBiquad(WebCore::Biquad& aBiquad,
+                  float aSampleRate,
+                  BiquadFilterType aType,
+                  double aFrequency,
+                  double aQ,
+                  double aGain,
+                  double aDetune)
 {
   const double nyquist = aSampleRate * 0.5;
   double normalizedFrequency = aFrequency / nyquist;
 
   if (aDetune) {
     normalizedFrequency *= std::pow(2.0, aDetune / 1200);
   }
 
@@ -153,20 +154,26 @@ public:
 
     TrackTicks pos = aStream->GetCurrentPosition();
 
     double freq = mFrequency.GetValueAtTime(pos);
     double q = mQ.GetValueAtTime(pos);
     double gain = mGain.GetValueAtTime(pos);
     double detune = mDetune.GetValueAtTime(pos);
 
+    float inputBuffer[WEBAUDIO_BLOCK_SIZE];
     for (uint32_t i = 0; i < numberOfChannels; ++i) {
+      auto input = static_cast<const float*>(aInput.mChannelData[i]);
+      if (aInput.mVolume != 1.0) {
+        AudioBlockCopyChannelWithScale(input, aInput.mVolume, inputBuffer);
+        input = inputBuffer;
+      }
       SetParamsOnBiquad(mBiquads[i], aStream->SampleRate(), mType, freq, q, gain, detune);
 
-      mBiquads[i].process(static_cast<const float*>(aInput.mChannelData[i]),
+      mBiquads[i].process(input,
                           static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])),
                           aInput.GetDuration());
     }
   }
 
 private:
   AudioNodeStream* mSource;
   AudioNodeStream* mDestination;
--- a/content/media/webaudio/blink/Biquad.cpp
+++ b/content/media/webaudio/blink/Biquad.cpp
@@ -76,22 +76,16 @@ void Biquad::process(const float* source
     }
 
     // Local variables back to member. Flush denormals here so we
     // don't slow down the inner loop above.
     m_x1 = DenormalDisabler::flushDenormalFloatToZero(x1);
     m_x2 = DenormalDisabler::flushDenormalFloatToZero(x2);
     m_y1 = DenormalDisabler::flushDenormalFloatToZero(y1);
     m_y2 = DenormalDisabler::flushDenormalFloatToZero(y2);
-
-    m_b0 = b0;
-    m_b1 = b1;
-    m_b2 = b2;
-    m_a1 = a1;
-    m_a2 = a2;
 }
 
 void Biquad::reset()
 {
     m_x1 = m_x2 = m_y1 = m_y2 = 0;
 }
 
 void Biquad::setLowpassParams(double cutoff, double resonance)
--- a/content/svg/content/src/SVGContentUtils.cpp
+++ b/content/svg/content/src/SVGContentUtils.cpp
@@ -14,16 +14,17 @@
 #include "nsComputedDOMStyle.h"
 #include "nsFontMetrics.h"
 #include "nsIFrame.h"
 #include "nsIScriptError.h"
 #include "nsLayoutUtils.h"
 #include "SVGAnimationElement.h"
 #include "SVGAnimatedPreserveAspectRatio.h"
 #include "nsContentUtils.h"
+#include "mozilla/gfx/2D.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 SVGSVGElement*
 SVGContentUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
 {
   nsIContent *element = nullptr;
--- a/content/svg/content/src/SVGFEFloodElement.cpp
+++ b/content/svg/content/src/SVGFEFloodElement.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/SVGFEFloodElement.h"
 #include "mozilla/dom/SVGFEFloodElementBinding.h"
 #include "gfxContext.h"
+#include "gfxColor.h"
 
 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEFlood)
 
 namespace mozilla {
 namespace dom {
 
 JSObject*
 SVGFEFloodElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aScope)
--- a/content/svg/content/src/SVGPathData.cpp
+++ b/content/svg/content/src/SVGPathData.cpp
@@ -7,16 +7,17 @@
 #include "gfxPlatform.h"
 #include "nsError.h"
 #include "nsString.h"
 #include "nsSVGPathDataParser.h"
 #include "nsSVGPathGeometryElement.h" // for nsSVGMark
 #include <stdarg.h>
 #include "SVGContentUtils.h"
 #include "SVGPathSegUtils.h"
+#include "gfxContext.h"
 #include <algorithm>
 
 using namespace mozilla;
 
 static bool IsMoveto(uint16_t aSegType)
 {
   return aSegType == PATHSEG_MOVETO_ABS ||
          aSegType == PATHSEG_MOVETO_REL;
new file mode 100644
--- /dev/null
+++ b/dom/base/crashtests/852381.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+
+function boom()
+{
+  var z = document.createElement("legend");
+  document.documentElement.appendChild(z);
+  z.style.display = "table-column-group";
+  window.find("?");
+  z.focus();
+}
+
+</script>
+</head>
+<body onload="boom();"></body>
+</html>
--- a/dom/base/crashtests/crashtests.list
+++ b/dom/base/crashtests/crashtests.list
@@ -36,8 +36,9 @@ load 693811-2.html
 load 693811-3.html
 load 695867.html
 load 697643.html
 load 706283-1.html
 load 708405-1.html
 load 745495.html
 load 886213.html
 load 898906.html
+load 852381.html
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2675,28 +2675,54 @@ nsDOMWindowUtils::CheckAndClearPaintedSt
     return NS_OK;
   }
 
   *aResult = frame->CheckAndClearPaintedState();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDOMWindowUtils::PreventFurtherDialogs()
+nsDOMWindowUtils::EnableDialogs()
 {
-  // Permanently disable further dialogs for this window.
-
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
 
-  static_cast<nsGlobalWindow*>(window.get())->PreventFurtherDialogs(true);
+  static_cast<nsGlobalWindow*>(window.get())->EnableDialogs();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::DisableDialogs()
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+
+  static_cast<nsGlobalWindow*>(window.get())->DisableDialogs();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::AreDialogsEnabled(bool* aResult)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
+  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
+
+  *aResult = static_cast<nsGlobalWindow*>(window.get())->AreDialogsEnabled();
   return NS_OK;
 }
 
 static nsIDOMBlob*
 GetXPConnectNative(JSContext* aCx, JSObject* aObj) {
   nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(
     nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, aObj));
   return blob;
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2539,16 +2539,19 @@ nsFocusManager::DetermineElementToMoveFo
       }
     }
 
     doNavigation = true;
     skipOriginalContentCheck = false;
     ignoreTabIndex = false;
 
     if (aNoParentTraversal) {
+      if (startContent == rootContent)
+        return NS_OK;
+
       startContent = rootContent;
       tabIndex = forward ? 1 : 0;
       continue;
     }
 
     // reached the beginning or end of the document. Traverse up to the parent
     // document and try again.
     nsCOMPtr<nsIDocShellTreeItem> docShellParent;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1025,18 +1025,17 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mSetOpenerWindowCalled(false),
 #endif
 #ifdef MOZ_B2G
     mNetworkUploadObserverEnabled(false),
     mNetworkDownloadObserverEnabled(false),
 #endif
     mCleanedUp(false),
     mDialogAbuseCount(0),
-    mStopAbuseDialogs(false),
-    mDialogsPermanentlyDisabled(false)
+    mAreDialogsEnabled(true)
 {
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
   if (aOuterWindow) {
     // |this| is an inner window, add this inner window to the outer
@@ -2878,50 +2877,60 @@ nsGlobalWindow::PreHandleEvent(nsEventCh
        aVisitor.mEvent->HasDragEventMessage())) {
     mAddActiveEventFuzzTime = false;
   }
 
   return NS_OK;
 }
 
 bool
-nsGlobalWindow::DialogsAreBlocked(bool *aBeingAbused)
-{
-  *aBeingAbused = false;
-
+nsGlobalWindow::ShouldPromptToBlockDialogs()
+{
   nsGlobalWindow *topWindow = GetScriptableTop();
   if (!topWindow) {
-    NS_ASSERTION(!mDocShell, "DialogsAreBlocked() called without a top window?");
+    NS_ASSERTION(!mDocShell, "ShouldPromptToBlockDialogs() called without a top window?");
     return true;
   }
 
   topWindow = topWindow->GetCurrentInnerWindowInternal();
   if (!topWindow) {
     return true;
   }
 
-  if (topWindow->mDialogsPermanentlyDisabled) {
-    return true;
+  return topWindow->DialogsAreBeingAbused();
+}
+
+bool
+nsGlobalWindow::AreDialogsEnabled()
+{
+  nsGlobalWindow *topWindow = GetScriptableTop();
+  if (!topWindow) {
+    NS_ERROR("AreDialogsEnabled() called without a top window?");
+    return false;
+  }
+
+  // TODO: Warn if no top window?
+  topWindow = topWindow->GetCurrentInnerWindowInternal();
+  if (!topWindow) {
+    return false;
   }
 
   // Dialogs are blocked if the content viewer is hidden
   if (mDocShell) {
     nsCOMPtr<nsIContentViewer> cv;
     mDocShell->GetContentViewer(getter_AddRefs(cv));
 
     bool isHidden;
     cv->GetIsHidden(&isHidden);
     if (isHidden) {
-      return true;
-    }
-  }
-
-  *aBeingAbused = topWindow->DialogsAreBeingAbused();
-
-  return topWindow->mStopAbuseDialogs && *aBeingAbused;
+      return false;
+    }
+  }
+
+  return topWindow->mAreDialogsEnabled;
 }
 
 bool
 nsGlobalWindow::DialogsAreBeingAbused()
 {
   NS_ASSERTION(GetScriptableTop() &&
                GetScriptableTop()->GetCurrentInnerWindowInternal() == this,
                "DialogsAreBeingAbused called with invalid window");
@@ -2968,38 +2977,52 @@ nsGlobalWindow::ConfirmDialogIfNeeded()
   bool disableDialog = false;
   nsXPIDLString label, title;
   nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                      "ScriptDialogLabel", label);
   nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                      "ScriptDialogPreventTitle", title);
   promptSvc->Confirm(this, title.get(), label.get(), &disableDialog);
   if (disableDialog) {
-    PreventFurtherDialogs(false);
+    DisableDialogs();
     return false;
   }
 
   return true;
 }
 
 void
-nsGlobalWindow::PreventFurtherDialogs(bool aPermanent)
+nsGlobalWindow::DisableDialogs()
 {
   nsGlobalWindow *topWindow = GetScriptableTop();
   if (!topWindow) {
-    NS_ERROR("PreventFurtherDialogs() called without a top window?");
+    NS_ERROR("DisableDialogs() called without a top window?");
     return;
   }
 
   topWindow = topWindow->GetCurrentInnerWindowInternal();
+  // TODO: Warn if no top window?
   if (topWindow) {
-    topWindow->mStopAbuseDialogs = true;
-    if (aPermanent) {
-      topWindow->mDialogsPermanentlyDisabled = true;
-    }
+    topWindow->mAreDialogsEnabled = false;
+  }
+}
+
+void
+nsGlobalWindow::EnableDialogs()
+{
+  nsGlobalWindow *topWindow = GetScriptableTop();
+  if (!topWindow) {
+    NS_ERROR("EnableDialogs() called without a top window?");
+    return;
+  }
+
+  // TODO: Warn if no top window?
+  topWindow = topWindow->GetCurrentInnerWindowInternal();
+  if (topWindow) {
+    topWindow->mAreDialogsEnabled = true;
   }
 }
 
 nsresult
 nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
 
@@ -5412,18 +5435,17 @@ nsGlobalWindow::CanMoveResizeWindows()
   return true;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Alert(const nsAString& aString)
 {
   FORWARD_TO_OUTER(Alert, (aString), NS_ERROR_NOT_INITIALIZED);
 
-  bool needToPromptForAbuse;
-  if (DialogsAreBlocked(&needToPromptForAbuse)) {
+  if (!AreDialogsEnabled()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Reset popup state while opening a modal dialog, and firing events
   // about the dialog, to prevent the current state from being active
   // the whole time a modal dialog is open.
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
@@ -5455,40 +5477,39 @@ nsGlobalWindow::Alert(const nsAString& a
 
   nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
   if (promptBag)
     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
 
   nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                              GetCurrentInnerWindowInternal()->mDoc :
                              nullptr);
-  if (needToPromptForAbuse) {
+  if (ShouldPromptToBlockDialogs()) {
     bool disallowDialog = false;
     nsXPIDLString label;
     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                        "ScriptDialogLabel", label);
 
     rv = prompt->AlertCheck(title.get(), final.get(), label.get(),
                             &disallowDialog);
     if (disallowDialog)
-      PreventFurtherDialogs(false);
+      DisableDialogs();
   } else {
     rv = prompt->Alert(title.get(), final.get());
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Confirm(const nsAString& aString, bool* aReturn)
 {
   FORWARD_TO_OUTER(Confirm, (aString, aReturn), NS_ERROR_NOT_INITIALIZED);
 
-  bool needToPromptForAbuse;
-  if (DialogsAreBlocked(&needToPromptForAbuse)) {
+  if (!AreDialogsEnabled()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Reset popup state while opening a modal dialog, and firing events
   // about the dialog, to prevent the current state from being active
   // the whole time a modal dialog is open.
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
@@ -5522,44 +5543,43 @@ nsGlobalWindow::Confirm(const nsAString&
 
   nsCOMPtr<nsIWritablePropertyBag2> promptBag = do_QueryInterface(prompt);
   if (promptBag)
     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
 
   nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                              GetCurrentInnerWindowInternal()->mDoc :
                              nullptr);
-  if (needToPromptForAbuse) {
+  if (ShouldPromptToBlockDialogs()) {
     bool disallowDialog = false;
     nsXPIDLString label;
     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                        "ScriptDialogLabel", label);
 
     rv = prompt->ConfirmCheck(title.get(), final.get(), label.get(),
                               &disallowDialog, aReturn);
     if (disallowDialog)
-      PreventFurtherDialogs(false);
+      DisableDialogs();
   } else {
     rv = prompt->Confirm(title.get(), final.get(), aReturn);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::Prompt(const nsAString& aMessage, const nsAString& aInitial,
                        nsAString& aReturn)
 {
   FORWARD_TO_OUTER(Prompt, (aMessage, aInitial, aReturn),
                    NS_ERROR_NOT_INITIALIZED);
 
   SetDOMStringToNull(aReturn);
 
-  bool needToPromptForAbuse;
-  if (DialogsAreBlocked(&needToPromptForAbuse)) {
+  if (!AreDialogsEnabled()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   // Reset popup state while opening a modal dialog, and firing events
   // about the dialog, to prevent the current state from being active
   // the whole time a modal dialog is open.
   nsAutoPopupStatePusher popupStatePusher(openAbused, true);
 
@@ -5594,30 +5614,30 @@ nsGlobalWindow::Prompt(const nsAString& 
   if (promptBag)
     promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"), allowTabModal);
 
   // Pass in the default value, if any.
   PRUnichar *inoutValue = ToNewUnicode(fixedInitial);
   bool disallowDialog = false;
 
   nsXPIDLString label;
-  if (needToPromptForAbuse) {
+  if (ShouldPromptToBlockDialogs()) {
     nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,
                                        "ScriptDialogLabel", label);
   }
 
   nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                              GetCurrentInnerWindowInternal()->mDoc :
                              nullptr);
   bool ok;
   rv = prompt->Prompt(title.get(), fixedMessage.get(),
                       &inoutValue, label.get(), &disallowDialog, &ok);
 
   if (disallowDialog) {
-    PreventFurtherDialogs(false);
+    DisableDialogs();
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAdoptingString outValue(inoutValue);
 
   if (ok && outValue) {
     aReturn.Assign(outValue);
@@ -5857,22 +5877,21 @@ NS_IMETHODIMP
 nsGlobalWindow::Print()
 {
 #ifdef NS_PRINTING
   FORWARD_TO_OUTER(Print, (), NS_ERROR_NOT_INITIALIZED);
 
   if (Preferences::GetBool("dom.disable_window_print", false))
     return NS_ERROR_NOT_AVAILABLE;
 
-  bool needToPromptForAbuse;
-  if (DialogsAreBlocked(&needToPromptForAbuse)) {
+  if (!AreDialogsEnabled()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  if (needToPromptForAbuse && !ConfirmDialogIfNeeded()) {
+  if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint;
   if (NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),
                                 getter_AddRefs(webBrowserPrint)))) {
     nsAutoSyncOperation sync(GetCurrentInnerWindowInternal() ? 
                                GetCurrentInnerWindowInternal()->mDoc :
@@ -7842,22 +7861,21 @@ nsGlobalWindow::ShowModalDialog(const ns
   }
   nsRefPtr<DialogValueHolder> argHolder =
     new DialogValueHolder(nsContentUtils::GetSubjectPrincipal(), aArgs);
 
   // Before bringing up the window/dialog, unsuppress painting and flush
   // pending reflows.
   EnsureReflowFlushAndPaint();
 
-  bool needToPromptForAbuse;
-  if (DialogsAreBlocked(&needToPromptForAbuse)) {
+  if (!AreDialogsEnabled()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  if (needToPromptForAbuse && !ConfirmDialogIfNeeded()) {
+  if (ShouldPromptToBlockDialogs() && !ConfirmDialogIfNeeded()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   nsCOMPtr<nsIDOMWindow> dlgWin;
   nsAutoString options(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));
 
   ConvertDialogOptions(aOptions, options);
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -498,32 +498,37 @@ public:
     if (top) {
       return static_cast<nsGlobalWindow *>(top.get());
     }
     return nullptr;
   }
 
   already_AddRefed<nsIDOMWindow> GetChildWindow(const nsAString& aName);
 
-  // Returns true if dialogs need to be prevented from appearings for this
-  // window. beingAbused returns whether dialogs are being abused.
-  bool DialogsAreBlocked(bool *aBeingAbused);
-
-  // Returns true if we've reached the state in this top level window where we
-  // ask the user if further dialogs should be blocked. This method must only
-  // be called on the scriptable top inner window.
+  // These return true if we've reached the state in this top level window
+  // where we ask the user if further dialogs should be blocked.
+  //
+  // DialogsAreBeingAbused must be called on the scriptable top inner window.
+  //
+  // ShouldPromptToBlockDialogs is implemented in terms of
+  // DialogsAreBeingAbused, and will get the scriptable top inner window
+  // automatically.
+  bool ShouldPromptToBlockDialogs();
   bool DialogsAreBeingAbused();
 
   // Ask the user if further dialogs should be blocked, if dialogs are currently
   // being abused. This is used in the cases where we have no modifiable UI to
   // show, in that case we show a separate dialog to ask this question.
   bool ConfirmDialogIfNeeded();
 
-  // Prevent further dialogs in this (top level) window
-  void PreventFurtherDialogs(bool aPermanent);
+  // These functions are used for controlling and determining whether dialogs
+  // (alert, prompt, confirm) are currently allowed in this window.
+  void EnableDialogs();
+  void DisableDialogs();
+  bool AreDialogsEnabled();
 
   virtual void SetHasAudioAvailableEventListeners();
 
   nsIScriptContext *GetContextInternal()
   {
     if (mOuterWindow) {
       return GetOuterWindowInternal()->mContext;
     }
@@ -1245,25 +1250,19 @@ protected:
   uint32_t                      mDialogAbuseCount;
 
   // This holds the time when the last modal dialog was shown. If more than
   // MAX_DIALOG_LIMIT dialogs are shown within the time span defined by
   // dom.successive_dialog_time_limit, we show a checkbox or confirmation prompt
   // to allow disabling of further dialogs from this window.
   TimeStamp                     mLastDialogQuitTime;
 
-  // This is set to true once the user has opted-in to preventing further
-  // dialogs for this window. Subsequent dialogs may still open if
-  // mDialogAbuseCount gets reset.
-  bool                          mStopAbuseDialogs;
-
-  // This flag gets set when dialogs should be permanently disabled for this
-  // window (e.g. when we are closing the tab and therefore are guaranteed to be
-  // destroying this window).
-  bool                          mDialogsPermanentlyDisabled;
+  // This flag keeps track of whether dialogs are
+  // currently enabled on this window.
+  bool                          mAreDialogsEnabled;
 
   nsTHashtable<nsPtrHashKey<nsDOMEventTargetHelper> > mEventTargetObjects;
 
   nsTArray<uint32_t> mEnabledSensors;
 
 #ifdef MOZ_WEBSPEECH
   // mSpeechSynthesis is only used on inner windows.
   nsRefPtr<mozilla::dom::SpeechSynthesis> mSpeechSynthesis;
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -38,17 +38,17 @@ interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMTouch;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 
-[scriptable, uuid(750a47b6-8bdb-4cad-ba2c-b7d3e66d8021)]
+[scriptable, uuid(928356ff-26b2-434e-a7ce-c1a660162d81)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1298,20 +1298,22 @@ interface nsIDOMWindowUtils : nsISupport
    * margins so that it can remain visible.
    *
    * The caller of this method must have chrome privileges.
    */
   void setContentDocumentFixedPositionMargins(in float aTop, in float aRight,
                                               in float aBottom, in float aLeft);
 
   /**
-   * Prevent this window (and any child windows) from displaying any further
-   * dialogs (e.g. window.alert()).
+   * These are used to control whether dialogs (alert, prompt, confirm) are
+   * allowed.
    */
-  void preventFurtherDialogs();
+  void disableDialogs();
+  void enableDialogs();
+  bool areDialogsEnabled();
 
   const unsigned long AGENT_SHEET = 0;
   const unsigned long USER_SHEET = 1;
   const unsigned long AUTHOR_SHEET = 2;
   /**
    * Synchronously loads a style sheet from |sheetURI| and adds it to the list
    * of additional style sheets of the document.
    *
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -449,25 +449,21 @@ nsGeolocationRequest::Allow()
 
   nsCOMPtr<nsIDOMGeoPosition> lastPosition = gs->GetCachedPosition();
   DOMTimeStamp cachedPositionTime;
   if (lastPosition) {
     lastPosition->GetTimestamp(&cachedPositionTime);
   }
 
   // check to see if we can use a cached value
-  //
-  // either:
-  // a) the user has specified a maximumAge which allows us to return a cached value,
-  // -or-
-  // b) the cached position time is some reasonable value to return to the user (<30s)
+  // if the user has specified a maximumAge, return a cached value.
 
-  uint32_t maximumAge = 30 * PR_MSEC_PER_SEC;
+  uint32_t maximumAge = 0;
   if (mOptions) {
-    if (mOptions->mMaximumAge >= 0) {
+    if (mOptions->mMaximumAge > 0) {
       maximumAge = mOptions->mMaximumAge;
     }
   }
   gs->SetHigherAccuracy(mOptions && mOptions->mEnableHighAccuracy);
 
   bool canUseCache = lastPosition && maximumAge > 0 &&
     (PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
     PRTime(cachedPositionTime));
@@ -1120,18 +1116,16 @@ Geolocation::HighAccuracyRequested()
 
 void
 Geolocation::RemoveRequest(nsGeolocationRequest* aRequest)
 {
   bool requestWasKnown =
     (mPendingCallbacks.RemoveElement(aRequest) !=
      mWatchingCallbacks.RemoveElement(aRequest));
 
-  // request must have been in one of the lists
-  MOZ_ASSERT(requestWasKnown);
   unused << requestWasKnown;
 }
 
 NS_IMETHODIMP
 Geolocation::Update(nsIDOMGeoPosition *aSomewhere)
 {
   if (!WindowOwnerStillExists()) {
     Shutdown();
--- a/dom/tests/mochitest/chrome/chrome.ini
+++ b/dom/tests/mochitest/chrome/chrome.ini
@@ -46,8 +46,9 @@ support-files =
 [test_queryCaretRect.html]
 [test_sandbox_bindings.xul]
 [test_sandbox_eventhandler.xul]
 [test_sandbox_image.xul]
 [test_sandbox_postMessage.html]
 [test_selectAtPoint.html]
 [test_subscript_bindings.xul]
 [test_xray_event_constructor.xul]
+[test_clipboard_events_chrome.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/chrome/test_clipboard_events_chrome.html
@@ -0,0 +1,62 @@
+<html>
+<body onload="runTest()">
+
+<script type="application/javascript"
+        src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript"
+        src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<script>
+// This test checks that the dom.event.clipboardevents.enabled does not apply to chrome shells.
+
+SimpleTest.waitForExplicitFinish();
+function runTest()
+{
+  SpecialPowers.setBoolPref("dom.event.clipboardevents.enabled", false);
+  window.open("data:text/html,<body onload='window.opener.doChecks(this)'><input id='i' value='Sample Text'></body>",
+              "_blank", "chrome,width=200,height=200");
+}
+
+var event_fired = false;
+
+function doChecks(win)
+{
+  var windowFocused = function() {
+    var textbox = win.document.getElementById("i");
+    textbox.value = "Sample Text";
+
+    textbox.oncut = function() { event_fired = true; };
+    textbox.oncopy = function() { event_fired = true; };
+    textbox.onpaste = function() { event_fired = true; };
+
+    textbox.select();
+    textbox.focus();
+
+    textbox.setSelectionRange(1, 4);
+    synthesizeKey("x", {accelKey: 1}, win);
+    is(textbox.value, "Sle Text", "cut changed text when preference is disabled");
+    ok(event_fired, "cut event fired when preference is disabled")
+
+    event_fired = false;
+    textbox.setSelectionRange(4, 6);
+    synthesizeKey("c", {accelKey: 1}, win);
+    is(textbox.value, "Sle Text", "cut changed text when preference is disabled");
+    ok(event_fired, "copy event fired when preference is disabled")
+
+    event_fired = false;
+    textbox.setSelectionRange(1, 4);
+    synthesizeKey("v", {accelKey: 1}, win);
+    is(textbox.value, "STeText", "paste changed text when preference is disabled");
+    ok(event_fired, "paste event fired when preference is disabled")
+
+    SpecialPowers.clearUserPref("dom.event.clipboardevents.enabled");
+    SimpleTest.finish();
+  }
+
+  SimpleTest.waitForFocus(windowFocused, win);
+}
+
+</script>
+
+<p id="display"></p>
+</body></html>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -38,16 +38,17 @@ var ecmaGlobals =
     "Float32Array",
     "Float64Array",
     "Function",
     "Infinity",
     "Int16Array",
     "Int32Array",
     "Int8Array",
     "InternalError",
+    {name: "Intl", desktop: true},
     "Iterator",
     "JSON",
     "Map",
     "Math",
     "NaN",
     "Number",
     "Object",
     {name: "ParallelArray", nightly: true},
@@ -605,46 +606,48 @@ var interfaceNamesInGlobalScope =
 // IMPORTANT: Do not change this list without review from a DOM peer!
 
 function createInterfaceMap(isXBLScope) {
   var version = SpecialPowers.Cc["@mozilla.org/xre/app-info;1"].getService(SpecialPowers.Ci.nsIXULAppInfo).version;
   var isNightly = version.endsWith("a1");
   var isRelease = !version.contains("a");
   var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
   var isB2G = !isDesktop && !navigator.userAgent.contains("Android");
+
   var interfaceMap = {};
-  for (var entry of ecmaGlobals) {
-    if (typeof(entry) === "string") {
-      // Standard ECMAScript global objects are not defined on the XBL scope.
-      interfaceMap[entry] = !isXBLScope;
-    } else if (entry.nightly === isNightly) {
-      interfaceMap[entry.name] = !isXBLScope;
-    } else {
-      interfaceMap[entry.name] = false;
+
+  function addInterfaces(interfaces, shouldExpect)
+  {
+    for (var entry of interfaces) {
+      if (typeof(entry) === "string") {
+        interfaceMap[entry] = shouldExpect;
+      } else if ((entry.nightly === !isNightly) ||
+                 (entry.xbl === !isXBLScope) ||
+                 (entry.desktop === !isDesktop) ||
+                 (entry.b2g === !isB2G) ||
+                 (entry.release === !isRelease)) {
+        interfaceMap[entry.name] = false;
+      } else {
+        interfaceMap[entry.name] = shouldExpect;
+      }
     }
   }
-  for (var entry of interfaceNamesInGlobalScope) {
-    if (typeof(entry) === "string") {
-      interfaceMap[entry] = true;
-    } else if (entry.xbl === !isXBLScope ||
-               entry.desktop === !isDesktop ||
-               entry.b2g === !isB2G ||
-               entry.release === !isRelease) {
-      interfaceMap[entry.name] = false;
-    } else {
-      interfaceMap[entry.name] = true;
-    }
-  }
+
+  // Standard ECMAScript global objects are not defined on the XBL scope, but
+  // everything else exists everywhere.
+  addInterfaces(ecmaGlobals, !isXBLScope);
+  addInterfaces(interfaceNamesInGlobalScope, true);
+
   return interfaceMap;
 }
 
 function runTest(isXBLScope) {
   var interfaceMap = createInterfaceMap(isXBLScope);
   for (var name of Object.getOwnPropertyNames(window)) {
-    // An interfae name should start with an upper case character.
+    // An interface name should start with an upper case character.
     if (!/^(moz)?[A-Z]/.test(name)) {
       continue;
     }
     ok(interfaceMap[name],
        "If this is failing: DANGER, are you sure you want to expose the new interface " + name +
        " to all webpages as a property on the window? Do not make a change to this file without a " +
        " review from a DOM peer for that specific change!!! (or a JS peer for changes to ecmaGlobals)");
     delete interfaceMap[name];
--- a/dom/webidl/Element.webidl
+++ b/dom/webidl/Element.webidl
@@ -170,19 +170,19 @@ partial interface Element {
   [Pref="dom.undo_manager.enabled"]
   readonly attribute UndoManager? undoManager;
   [SetterThrows,Pref="dom.undo_manager.enabled"]
   attribute boolean undoScope;
 };
 
 // http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
 partial interface Element {
-  [Throws,TreatNullAs=EmptyString]
+  [Pure,SetterThrows,TreatNullAs=EmptyString]
   attribute DOMString innerHTML;
-  [Throws,TreatNullAs=EmptyString]
+  [Pure,SetterThrows,TreatNullAs=EmptyString]
   attribute DOMString outerHTML;
   [Throws]
   void insertAdjacentHTML(DOMString position, DOMString text);
 };
 
 // http://www.w3.org/TR/selectors-api/#interface-definitions
 partial interface Element {
   [Throws]
--- a/dom/webidl/Geolocation.webidl
+++ b/dom/webidl/Geolocation.webidl
@@ -8,17 +8,17 @@
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
 dictionary PositionOptions {
   boolean enableHighAccuracy = false;
   long timeout = 0x7fffffff;
-  long maximumAge = 30000; /* non-conformant, should be 0 */
+  long maximumAge = 0;
 };
 
 [NoInterfaceObject]
 interface Geolocation {
   [Throws]
   void getCurrentPosition(PositionCallback successCallback,
                           optional PositionErrorCallback? errorCallback = null,
                           optional PositionOptions options);
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -126,21 +126,16 @@ RemoveGLDrawTarget(DrawTargetSkia* targe
   }
 }
 
 #endif
 
 DrawTargetSkia::DrawTargetSkia()
   : mSnapshot(nullptr)
 {
-#ifdef ANDROID
-  mSoftClipping = false;
-#else
-  mSoftClipping = true;
-#endif
 }
 
 DrawTargetSkia::~DrawTargetSkia()
 {
 #ifdef USE_SKIA_GPU
   RemoveGLDrawTarget(this);
 #endif
 }
@@ -702,19 +697,16 @@ DrawTargetSkia::InitWithGLContextAndGrGL
                                                   GrGLInterface* aGrGLInterface,
                                                   const IntSize &aSize,
                                                   SurfaceFormat aFormat)
 {
   mGLContext = aGLContext;
   mSize = aSize;
   mFormat = aFormat;
 
-  // Always use soft clipping when we're using GL
-  mSoftClipping = true;
-
   mGrGLInterface = aGrGLInterface;
   mGrGLInterface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
 
   GrBackendContext backendContext = reinterpret_cast<GrBackendContext>(aGrGLInterface);
   SkAutoTUnref<GrContext> gr(GrContext::Create(kOpenGL_GrBackend, backendContext));
   mGrContext = gr.get();
 
   GrBackendRenderTargetDesc targetDescriptor;
@@ -786,42 +778,42 @@ DrawTargetSkia::CreatePathBuilder(FillRu
 }
 
 void
 DrawTargetSkia::ClearRect(const Rect &aRect)
 {
   MarkChanged();
   SkPaint paint;
   mCanvas->save();
-  mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, mSoftClipping);
+  mCanvas->clipRect(RectToSkRect(aRect), SkRegion::kIntersect_Op, true);
   paint.setColor(SkColorSetARGB(0, 0, 0, 0));
   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   mCanvas->drawPaint(paint);
   mCanvas->restore();
 }
 
 void
 DrawTargetSkia::PushClip(const Path *aPath)
 {
   if (aPath->GetBackendType() != BACKEND_SKIA) {
     return;
   }
 
   const PathSkia *skiaPath = static_cast<const PathSkia*>(aPath);
   mCanvas->save(SkCanvas::kClip_SaveFlag);
-  mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, mSoftClipping);
+  mCanvas->clipPath(skiaPath->GetPath(), SkRegion::kIntersect_Op, true);
 }
 
 void
 DrawTargetSkia::PushClipRect(const Rect& aRect)
 {
   SkRect rect = RectToSkRect(aRect);
 
   mCanvas->save(SkCanvas::kClip_SaveFlag);
-  mCanvas->clipRect(rect, SkRegion::kIntersect_Op, mSoftClipping);
+  mCanvas->clipRect(rect, SkRegion::kIntersect_Op, true);
 }
 
 void
 DrawTargetSkia::PopClip()
 {
   mCanvas->restore();
 }
 
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -130,13 +130,12 @@ private:
   RefPtr<GenericRefCountedBase> mGLContext;
   SkRefPtr<GrGLInterface> mGrGLInterface;
   SkRefPtr<GrContext> mGrContext;
 #endif
 
   IntSize mSize;
   SkRefPtr<SkCanvas> mCanvas;
   SourceSurfaceSkia* mSnapshot;
-  bool mSoftClipping;
 };
 
 }
 }
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -18,22 +18,24 @@
 #include "GLTextureImage.h"
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "prenv.h"
 #include "prlink.h"
 #include "SurfaceStream.h"
 #include "GfxTexturesReporter.h"
 #include "TextureGarbageBin.h"
+#include "gfx2DGlue.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 
 #ifdef XP_MACOSX
 #include <CoreServices/CoreServices.h>
+#include "gfxColor.h"
 #endif
 
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
 using namespace mozilla::gfx;
 
@@ -109,16 +111,17 @@ static const char *sExtensionNames[] = {
     "GL_ARB_instanced_arrays",
     "GL_NV_instanced_arrays",
     "GL_ANGLE_instanced_arrays",
     "GL_EXT_occlusion_query_boolean",
     "GL_ARB_occlusion_query2",
     "GL_EXT_transform_feedback",
     "GL_NV_transform_feedback",
     "GL_ANGLE_depth_texture",
+    "GL_KHR_debug",
     nullptr
 };
 
 static bool
 ParseGLVersion(GLContext* gl, unsigned int* version)
 {
     GLenum error = gl->fGetError();
     if (error != LOCAL_GL_NO_ERROR) {
@@ -967,16 +970,49 @@ GLContext::InitWithPrefix(const char *pr
             if (!LoadSymbols(queryObjectsSymbols, trygl, prefix)) {
                 NS_ERROR("GL supports query objects iv getter without supplying its function.");
 
                 MarkUnsupported(GLFeature::get_query_object_iv);
                 mSymbols.fGetQueryObjectiv = nullptr;
             }
         }
 
+        if (IsExtensionSupported(KHR_debug)) {
+            SymLoadStruct extSymbols[] = {
+                { (PRFuncPtr*) &mSymbols.fDebugMessageControl,  { "DebugMessageControl",  "DebugMessageControlKHR",  nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDebugMessageInsert,   { "DebugMessageInsert",   "DebugMessageInsertKHR",   nullptr } },
+                { (PRFuncPtr*) &mSymbols.fDebugMessageCallback, { "DebugMessageCallback", "DebugMessageCallbackKHR", nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetDebugMessageLog,   { "GetDebugMessageLog",   "GetDebugMessageLogKHR",   nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetPointerv,          { "GetPointerv",          "GetPointervKHR",          nullptr } },
+                { (PRFuncPtr*) &mSymbols.fPushDebugGroup,       { "PushDebugGroup",       "PushDebugGroupKHR",       nullptr } },
+                { (PRFuncPtr*) &mSymbols.fPopDebugGroup,        { "PopDebugGroup",        "PopDebugGroupKHR",        nullptr } },
+                { (PRFuncPtr*) &mSymbols.fObjectLabel,          { "ObjectLabel",          "ObjectLabelKHR",          nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetObjectLabel,       { "GetObjectLabel",       "GetObjectLabelKHR",       nullptr } },
+                { (PRFuncPtr*) &mSymbols.fObjectPtrLabel,       { "ObjectPtrLabel",       "ObjectPtrLabelKHR",       nullptr } },
+                { (PRFuncPtr*) &mSymbols.fGetObjectPtrLabel,    { "GetObjectPtrLabel",    "GetObjectPtrLabelKHR",    nullptr } },
+                { nullptr, { nullptr } },
+            };
+
+            if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
+                NS_ERROR("GL supports KHR_debug without supplying its functions.");
+
+                MarkExtensionUnsupported(KHR_debug);
+                mSymbols.fDebugMessageControl  = nullptr;
+                mSymbols.fDebugMessageInsert   = nullptr;
+                mSymbols.fDebugMessageCallback = nullptr;
+                mSymbols.fGetDebugMessageLog   = nullptr;
+                mSymbols.fGetPointerv          = nullptr;
+                mSymbols.fPushDebugGroup       = nullptr;
+                mSymbols.fPopDebugGroup        = nullptr;
+                mSymbols.fObjectLabel          = nullptr;
+                mSymbols.fGetObjectLabel       = nullptr;
+                mSymbols.fObjectPtrLabel       = nullptr;
+                mSymbols.fGetObjectPtrLabel    = nullptr;
+            }
+        }
 
         // Load developer symbols, don't fail if we can't find them.
         SymLoadStruct auxSymbols[] = {
                 { (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fGetTexLevelParameteriv, { "GetTexLevelParameteriv", nullptr } },
                 { nullptr, { nullptr } },
         };
         bool warnOnFailures = DebugMode();
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -390,16 +390,17 @@ public:
         ARB_instanced_arrays,
         NV_instanced_arrays,
         ANGLE_instanced_arrays,
         EXT_occlusion_query_boolean,
         ARB_occlusion_query2,
         EXT_transform_feedback,
         NV_transform_feedback,
         ANGLE_depth_texture,
+        KHR_debug,
         Extensions_Max,
         Extensions_End
     };
 
     bool IsExtensionSupported(GLExtensions aKnownExtension) const {
         return mAvailableExtensions[aKnownExtension];
     }
 
@@ -891,16 +892,37 @@ public:
     }
 
     void fCullFace(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fCullFace(mode);
         AFTER_GL_CALL;
     }
 
+    void fDebugMessageCallback(GLDEBUGPROC callback, const GLvoid* userParam) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDebugMessageCallback);
+        mSymbols.fDebugMessageCallback(callback, userParam);
+        AFTER_GL_CALL;
+    }
+
+    void fDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, realGLboolean enabled) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDebugMessageControl);
+        mSymbols.fDebugMessageControl(source, type, severity, count, ids, enabled);
+        AFTER_GL_CALL;
+    }
+
+    void fDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fDebugMessageInsert);
+        mSymbols.fDebugMessageInsert(source, type, id, severity, length, buf);
+        AFTER_GL_CALL;
+    }
+
     void fDetachShader(GLuint program, GLuint shader) {
         BEFORE_GL_CALL;
         mSymbols.fDetachShader(program, shader);
         AFTER_GL_CALL;
     }
 
     void fDepthFunc(GLenum func) {
         BEFORE_GL_CALL;
@@ -1089,16 +1111,45 @@ public:
     }
 
     void fGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) {
         BEFORE_GL_CALL;
         mSymbols.fGetBufferParameteriv(target, pname, params);
         AFTER_GL_CALL;
     }
 
+    GLuint fGetDebugMessageLog(GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetDebugMessageLog);
+        GLuint ret = mSymbols.fGetDebugMessageLog(count, bufsize, sources, types, ids, severities, lengths, messageLog);
+        AFTER_GL_CALL;
+        return ret;
+    }
+
+    void fGetPointerv(GLenum pname, GLvoid** params) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetPointerv);
+        mSymbols.fGetPointerv(pname, params);
+        AFTER_GL_CALL;
+    }
+
+    void fGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetObjectLabel);
+        mSymbols.fGetObjectLabel(identifier, name, bufSize, length, label);
+        AFTER_GL_CALL;
+    }
+
+    void fGetObjectPtrLabel(GLvoid* ptr, GLsizei bufSize, GLsizei* length, GLchar* label) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fGetObjectPtrLabel);
+        mSymbols.fGetObjectPtrLabel(ptr, bufSize, length, label);
+        AFTER_GL_CALL;
+    }
+
     void fGenerateMipmap(GLenum target) {
         BEFORE_GL_CALL;
         mSymbols.fGenerateMipmap(target);
         AFTER_GL_CALL;
     }
 
     void fGetProgramiv(GLuint program, GLenum pname, GLint* param) {
         BEFORE_GL_CALL;
@@ -1249,16 +1300,30 @@ public:
     }
 
     void fLinkProgram(GLuint program) {
         BEFORE_GL_CALL;
         mSymbols.fLinkProgram(program);
         AFTER_GL_CALL;
     }
 
+    void fObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar* label) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fObjectLabel);
+        mSymbols.fObjectLabel(identifier, name, length, label);
+        AFTER_GL_CALL;
+    }
+
+    void fObjectPtrLabel(GLvoid* ptr, GLsizei length, const GLchar* label) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fObjectPtrLabel);
+        mSymbols.fObjectPtrLabel(ptr, length, label);
+        AFTER_GL_CALL;
+    }
+
     void fPixelStorei(GLenum pname, GLint param) {
         BEFORE_GL_CALL;
         mSymbols.fPixelStorei(pname, param);
         AFTER_GL_CALL;
     }
 
     void fPointParameterf(GLenum pname, GLfloat param) {
         BEFORE_GL_CALL;
@@ -1267,16 +1332,30 @@ public:
     }
 
     void fPolygonOffset(GLfloat factor, GLfloat bias) {
         BEFORE_GL_CALL;
         mSymbols.fPolygonOffset(factor, bias);
         AFTER_GL_CALL;
     }
 
+    void fPopDebugGroup() {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fPopDebugGroup);
+        mSymbols.fPopDebugGroup();
+        AFTER_GL_CALL;
+    }
+
+    void fPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar* message) {
+        BEFORE_GL_CALL;
+        ASSERT_SYMBOL_PRESENT(fPushDebugGroup);
+        mSymbols.fPushDebugGroup(source, id, length, message);
+        AFTER_GL_CALL;
+    }
+
     void fReadBuffer(GLenum mode) {
         BEFORE_GL_CALL;
         mSymbols.fReadBuffer(mode);
         AFTER_GL_CALL;
     }
 
 private:
     void raw_fReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -437,14 +437,38 @@ struct GLContextSymbols
     PFNGLGETTRANSFORMFEEDBACKVARYING fGetTransformFeedbackVarying;
 
     typedef void (GLAPIENTRY * PFNGLGETINTEGERI_V) (GLenum param, GLuint index, GLint* values);
     PFNGLGETINTEGERI_V fGetIntegeri_v;
 
     // EXT_transform_feedback only
     typedef void (GLAPIENTRY * PFNGLBINDBUFFEROFFSET) (GLenum target, GLuint index, GLuint buffer, GLintptr offset);
     PFNGLBINDBUFFEROFFSET fBindBufferOffset;
+
+    // KHR_debug
+    typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECONTROL) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, realGLboolean enabled);
+    PFNGLDEBUGMESSAGECONTROL fDebugMessageControl;
+    typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEINSERT) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf);
+    PFNGLDEBUGMESSAGEINSERT fDebugMessageInsert;
+    typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACK) (GLDEBUGPROC callback, const GLvoid* userParam);
+    PFNGLDEBUGMESSAGECALLBACK fDebugMessageCallback;
+    typedef GLuint (GLAPIENTRY * PFNGLDEBUGMESSAGELOG) (GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog);
+    PFNGLDEBUGMESSAGELOG fGetDebugMessageLog;
+    typedef void (GLAPIENTRY * PFNGLGETPOINTERV) (GLenum pname, GLvoid** params);
+    PFNGLGETPOINTERV fGetPointerv;
+    typedef void (GLAPIENTRY * PFNGLPUSHDEBUGGROUP) (GLenum source, GLuint id, GLsizei length, const GLchar* message);
+    PFNGLPUSHDEBUGGROUP fPushDebugGroup;
+    typedef void (GLAPIENTRY * PFNGLPOPDEBUGGROUP) (void);
+    PFNGLPOPDEBUGGROUP fPopDebugGroup;
+    typedef void (GLAPIENTRY * PFNGLOBJECTLABEL) (GLenum identifier, GLuint name, GLsizei length, const GLchar* label);
+    PFNGLOBJECTLABEL fObjectLabel;
+    typedef void (GLAPIENTRY * PFNGLGETOBJECTLABEL) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label);
+    PFNGLGETOBJECTLABEL fGetObjectLabel;
+    typedef void (GLAPIENTRY * PFNGLOBJECTPTRLABEL) (GLvoid* ptr, GLsizei length, const GLchar* label);
+    PFNGLOBJECTPTRLABEL fObjectPtrLabel;
+    typedef void (GLAPIENTRY * PFNGLGETOBJECTPTRLABEL) (GLvoid* ptr, GLsizei bufSize, GLsizei* length, GLchar* label);
+    PFNGLGETOBJECTPTRLABEL fGetObjectPtrLabel;
 };
 
 }
 }
 
 #endif /* GLCONTEXTSYMBOLS_H_ */
--- a/gfx/gl/GLTypes.h
+++ b/gfx/gl/GLTypes.h
@@ -3,16 +3,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #if !defined(GLTYPES_H_)
 #define GLTYPES_H_
 
 #include <stddef.h>
 #include <stdint.h>
 
+#ifndef GLAPIENTRY
+# ifdef WIN32
+#  include <windef.h>
+#  define GLAPIENTRY APIENTRY
+#  define GLAPI
+# else
+#  define GLAPIENTRY
+#  define GLAPI
+# endif
+#endif
+
 typedef int8_t realGLboolean;
 
 #if !defined(__gltypes_h_) && !defined(__gl_h_)
 #define __gltypes_h_
 #define __gl_h_
 
 typedef uint32_t GLenum;
 typedef uint32_t GLbitfield;
@@ -44,16 +55,25 @@ typedef intptr_t GLintptr;
 // ARB_sync
 typedef struct __GLsync* GLsync;
 typedef int64_t GLint64;
 typedef uint64_t GLuint64;
 
 // OES_EGL_image (GLES)
 typedef void* GLeglImage;
 
+// KHR_debug
+typedef void (GLAPIENTRY *GLDEBUGPROC)(GLenum source,
+                                       GLenum type,
+                                       GLuint id,
+                                       GLenum severity,
+                                       GLsizei length,
+                                       const GLchar* message,
+                                       const GLvoid* userParam);
+
 // EGL types
 typedef void* EGLImage;
 typedef int EGLint;
 typedef unsigned int EGLBoolean;
 typedef unsigned int EGLenum;
 typedef void *EGLConfig;
 typedef void *EGLContext;
 typedef void *EGLDisplay;
@@ -66,19 +86,9 @@ typedef uint64_t EGLTime;
 
 #define EGL_NO_CONTEXT       ((EGLContext)0)
 #define EGL_NO_DISPLAY       ((EGLDisplay)0)
 #define EGL_NO_SURFACE       ((EGLSurface)0)
 #define EGL_NO_CONFIG        ((EGLConfig)nullptr)
 #define EGL_NO_SYNC          ((EGLSync)0)
 #define EGL_NO_IMAGE         ((EGLImage)0)
 
-#ifndef GLAPIENTRY
-# ifdef WIN32
-#  define GLAPIENTRY APIENTRY
-#  define GLAPI
-# else
-#  define GLAPIENTRY
-#  define GLAPI
-# endif
 #endif
-
-#endif
--- a/gfx/layers/ThebesLayerBuffer.cpp
+++ b/gfx/layers/ThebesLayerBuffer.cpp
@@ -25,16 +25,17 @@
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Matrix.h"         // for Matrix
 #include "mozilla/gfx/Point.h"          // for Point, IntPoint
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for ExtendMode::EXTEND_CLAMP, etc
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowableLayer
 #include "mozilla/layers/TextureClient.h"  // for DeprecatedTextureClient
 #include "nsSize.h"                     // for nsIntSize
+#include "gfx2DGlue.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 nsIntRect
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -25,16 +25,17 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "prenv.h"                      // for PR_GetEnv
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
+#include "gfx2DGlue.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace layers {
 
 /* static */ TemporaryRef<ContentClient>
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxContext::AddRef, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "gfxReusableSharedImageSurfaceWrapper.h"
 #include "nsMathUtils.h"               // for NS_roundf
+#include "gfx2DGlue.h"
 
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
 #include "cairo.h"
 #include <sstream>
 using mozilla::layers::Layer;
 static void DrawDebugOverlay(gfxASurface* imgSurf, int x, int y)
 {
   gfxContext c(imgSurf);
--- a/gfx/src/nsFont.cpp
+++ b/gfx/src/nsFont.cpp
@@ -10,16 +10,17 @@
 #include "gfxFontUtils.h"               // for TRUETYPE_TAG
 #include "nsCRT.h"                      // for nsCRT
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupports.h"
 #include "nsMemory.h"                   // for NS_ARRAY_LENGTH
 #include "nsUnicharUtils.h"
 #include "nscore.h"                     // for PRUnichar
 #include "prtypes.h"                    // for PR_STATIC_ASSERT
+#include "mozilla/gfx/2D.h"
 
 nsFont::nsFont(const char* aName, uint8_t aStyle, uint8_t aVariant,
                uint16_t aWeight, int16_t aStretch, uint8_t aDecoration,
                nscoord aSize)
 {
   NS_ASSERTION(aName && IsASCII(nsDependentCString(aName)),
                "Must only pass ASCII names here");
   name.AssignASCII(aName);
--- a/gfx/thebes/gfx2DGlue.h
+++ b/gfx/thebes/gfx2DGlue.h
@@ -9,16 +9,17 @@
 #include "gfxPlatform.h"
 #include "gfxRect.h"
 #include "gfxMatrix.h"
 #include "gfx3DMatrix.h"
 #include "gfxContext.h"
 #include "mozilla/gfx/Matrix.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/gfx/2D.h"
+#include "gfxColor.h"
 
 namespace mozilla {
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 class ScaledFont;
 }
 }
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -42,17 +42,16 @@
 
 #include <stdio.h>
 #include <limits.h>
 
 #include "imgIEncoder.h"
 #include "nsComponentManagerUtils.h"
 #include "nsISupportsUtils.h"
 #include "nsCOMPtr.h"
-#include "nsIConsoleService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsIClipboardHelper.h"
 
 using namespace mozilla;
 
 static cairo_user_data_key_t gfxasurface_pointer_key;
 
--- a/gfx/thebes/gfxAlphaRecovery.h
+++ b/gfx/thebes/gfxAlphaRecovery.h
@@ -1,21 +1,22 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _GFXALPHARECOVERY_H_
 #define _GFXALPHARECOVERY_H_
 
-#include "gfxContext.h"
-#include "gfxImageSurface.h"
 #include "mozilla/SSE.h"
+#include "gfxTypes.h"
+#include "nsRect.h"
 
 struct nsIntRect;
+class gfxImageSurface;
 
 class gfxAlphaRecovery {
 public:
     struct Analysis {
         bool uniformColor;
         bool uniformAlpha;
         gfxFloat alpha;
         gfxFloat r, g, b;
--- a/gfx/thebes/gfxAlphaRecoverySSE2.cpp
+++ b/gfx/thebes/gfxAlphaRecoverySSE2.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "mozilla/SSE.h"
 #include "gfxAlphaRecovery.h"
+#include "gfxImageSurface.h"
+#include "nsRect.h"
 #include <emmintrin.h>
 
 // This file should only be compiled on x86 and x64 systems.  Additionally,
 // you'll need to compile it with -msse2 if you're using GCC on x86.
 
 #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
 __declspec(align(16)) static uint32_t greenMaski[] =
     { 0x0000ff00, 0x0000ff00, 0x0000ff00, 0x0000ff00 };
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -12,16 +12,17 @@
 
 #include "gfxFT2FontList.h"
 #include "gfxImageSurface.h"
 #include "mozilla/dom/ContentChild.h"
 #include "nsXULAppAPI.h"
 #include "nsIScreen.h"
 #include "nsIScreenManager.h"
 #include "nsILocaleService.h"
+#include "nsServiceManagerUtils.h"
 
 #include "cairo.h"
 
 #include "ft2build.h"
 #include FT_FREETYPE_H
 #include FT_MODULE_H
 
 using namespace mozilla;
--- a/gfx/thebes/gfxBaseSharedMemorySurface.cpp
+++ b/gfx/thebes/gfxBaseSharedMemorySurface.cpp
@@ -1,10 +1,11 @@
 // vim:set ts=4 sts=4 sw=4 et cin:
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "gfxSharedImageSurface.h"
+#include "gfxBaseSharedMemorySurface.h"
+#include "cairo.h"
 
 const cairo_user_data_key_t SHM_KEY = {0};
 
--- a/gfx/thebes/gfxBaseSharedMemorySurface.h
+++ b/gfx/thebes/gfxBaseSharedMemorySurface.h
@@ -4,22 +4,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_SHARED_MEMORYSURFACE_H
 #define GFX_SHARED_MEMORYSURFACE_H
 
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/SharedMemory.h"
-#include "cairo.h"
- 
+
 #include "gfxASurface.h"
 #include "gfxImageSurface.h"
 #include "pratom.h"
 
+typedef struct _cairo_user_data_key cairo_user_data_key_t;
+
 struct SharedImageInfo {
     int32_t width;
     int32_t height;
     int32_t format;
     int32_t readCount;
 };
 
 inline SharedImageInfo*
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "gfxBlur.h"
+#include "gfxContext.h"
+#include "gfxImageSurface.h"
 
 #include "mozilla/gfx/Blur.h"
 
 using namespace mozilla::gfx;
 
 gfxAlphaBoxBlur::gfxAlphaBoxBlur()
  : mBlur(nullptr)
 {
--- a/gfx/thebes/gfxBlur.h
+++ b/gfx/thebes/gfxBlur.h
@@ -1,19 +1,24 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_BLUR_H
 #define GFX_BLUR_H
 
-#include "gfxContext.h"
-#include "gfxImageSurface.h"
 #include "gfxTypes.h"
+#include "nsSize.h"
+#include "nsAutoPtr.h"
+#include "gfxPoint.h"
+
+class gfxContext;
+class gfxImageSurface;
+struct gfxRect;
 
 namespace mozilla {
   namespace gfx {
     class AlphaBoxBlur;
   }
 }
 
 /**
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -4,29 +4,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef _MSC_VER
 #define _USE_MATH_DEFINES
 #endif
 #include <math.h>
 
 #include "mozilla/Alignment.h"
-#include "mozilla/Constants.h"
 
 #include "cairo.h"
 
 #include "gfxContext.h"
 
 #include "gfxColor.h"
 #include "gfxMatrix.h"
 #include "gfxASurface.h"
 #include "gfxPattern.h"
 #include "gfxPlatform.h"
 #include "gfxTeeSurface.h"
 #include "GeckoProfiler.h"
+#include "gfx2DGlue.h"
 #include <algorithm>
 
 #if CAIRO_HAS_DWRITE_FONT
 #include "gfxWindowsPlatform.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -4,24 +4,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_CONTEXT_H
 #define GFX_CONTEXT_H
 
 #include "gfxTypes.h"
 
 #include "gfxASurface.h"
-#include "gfxColor.h"
 #include "gfxPoint.h"
 #include "gfxRect.h"
 #include "gfxMatrix.h"
 #include "gfxPattern.h"
 #include "gfxPath.h"
-#include "nsISupportsImpl.h"
 #include "nsTArray.h"
+#include "nsAutoPtr.h"
 
 #include "mozilla/gfx/2D.h"
 
 typedef struct _cairo cairo_t;
 struct GlyphBufferAzure;
 template <typename T> class FallibleTArray;
 
 /**
--- a/gfx/thebes/gfxCoreTextShaper.cpp
+++ b/gfx/thebes/gfxCoreTextShaper.cpp
@@ -1,37 +1,19 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "mozilla/Util.h"
-
-#include "nsAlgorithm.h"
-#include "nsString.h"
-#include "nsBidiUtils.h"
-
-#include "gfxTypes.h"
-
-#include "nsPromiseFlatString.h"
-
-#include "gfxContext.h"
-#include "gfxPlatform.h"
-#include "gfxPlatformMac.h"
 #include "gfxCoreTextShaper.h"
 #include "gfxMacFont.h"
-
-#include "gfxFontTest.h"
 #include "gfxFontUtils.h"
+#include "mozilla/gfx/2D.h"
 
-#include "gfxQuartzSurface.h"
-#include "gfxMacPlatformFontList.h"
-#include "gfxUserFontSet.h"
-
-#include "nsUnicodeRange.h"
 #include <algorithm>
 
 using namespace mozilla;
 
 // standard font descriptors that we construct the first time they're needed
 CTFontDescriptorRef gfxCoreTextShaper::sDefaultFeaturesDescriptor = nullptr;
 CTFontDescriptorRef gfxCoreTextShaper::sDisableLigaturesDescriptor = nullptr;
 
--- a/gfx/thebes/gfxCoreTextShaper.h
+++ b/gfx/thebes/gfxCoreTextShaper.h
@@ -1,23 +1,19 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_CORETEXTSHAPER_H
 #define GFX_CORETEXTSHAPER_H
 
-#include "gfxTypes.h"
 #include "gfxFont.h"
-#include "gfxFontUtils.h"
-#include "gfxPlatform.h"
-#include "gfxMacPlatformFontList.h"
 
-#include <Carbon/Carbon.h>
+#include <ApplicationServices/ApplicationServices.h>
 
 class gfxMacFont;
 
 class gfxCoreTextShaper : public gfxFontShaper {
 public:
     gfxCoreTextShaper(gfxMacFont *aFont);
 
     virtual ~gfxCoreTextShaper();
--- a/gfx/thebes/gfxDrawable.cpp
+++ b/gfx/thebes/gfxDrawable.cpp
@@ -2,17 +2,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxDrawable.h"
 #include "gfxASurface.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
-#include "mozilla/arm.h"
 #ifdef MOZ_X11
 #include "cairo.h"
 #include "gfxXlibSurface.h"
 #endif
 
 gfxSurfaceDrawable::gfxSurfaceDrawable(gfxASurface* aSurface,
                                        const gfxIntSize aSize,
                                        const gfxMatrix aTransform)
@@ -74,17 +73,17 @@ PreparePatternForUntiledDrawing(gfxPatte
             // enable EXTEND_PAD provided that we're running on a recent
             // enough X server.
             if (static_cast<gfxXlibSurface*>(currentTarget)->IsPadSlow()) {
                 bool isDownscale =
                     aDeviceToImage.xx >= 1.0 && aDeviceToImage.yy >= 1.0 &&
                     aDeviceToImage.xy == 0.0 && aDeviceToImage.yx == 0.0;
 
                 GraphicsFilter filter =
-                    isDownscale ? aDefaultFilter : GraphicsFilter::FILTER_FAST;
+                    isDownscale ? aDefaultFilter : (const GraphicsFilter)GraphicsFilter::FILTER_FAST;
                 aPattern->SetFilter(filter);
 
                 // Use the default EXTEND_NONE
                 break;
             }
             // else fall through to EXTEND_PAD and the default filter.
         }
 #endif
--- a/gfx/thebes/gfxDrawable.h
+++ b/gfx/thebes/gfxDrawable.h
@@ -1,21 +1,18 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_DRAWABLE_H
 #define GFX_DRAWABLE_H
 
-#include "nsISupportsImpl.h"
 #include "nsAutoPtr.h"
-#include "gfxTypes.h"
 #include "gfxRect.h"
-#include "gfxColor.h"
 #include "gfxMatrix.h"
 #include "GraphicsFilter.h"
 
 class gfxASurface;
 class gfxImageSurface;
 class gfxContext;
 class gfxPattern;
 
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -2,16 +2,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 "gfxFT2FontBase.h"
 #include "gfxFT2Utils.h"
 #include "harfbuzz/hb.h"
 #include "mozilla/Likely.h"
+#include "gfxFontConstants.h"
 
 using namespace mozilla::gfx;
 
 gfxFT2FontBase::gfxFT2FontBase(cairo_scaled_font_t *aScaledFont,
                                gfxFontEntry *aFontEntry,
                                const gfxFontStyle *aFontStyle)
     : gfxFont(aFontEntry, aFontStyle, kAntialiasDefault, aScaledFont),
       mSpaceGlyph(0),
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -47,16 +47,17 @@
 #include "nsTArray.h"
 #include "nsUnicharUtils.h"
 
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIMemory.h"
+#include "gfxFontConstants.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/scache/StartupCache.h"
 #include <sys/stat.h>
 
 #ifdef XP_WIN
 #include "nsIWindowsRegKey.h"
 #include <windows.h>
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -7,27 +7,25 @@
 #include "mozilla/MathAlgorithms.h"
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 #include "prlog.h"
 
 #include "nsServiceManagerUtils.h"
-#include "nsReadableUtils.h"
 #include "nsExpirationTracker.h"
 #include "nsILanguageAtomService.h"
 #include "nsITimer.h"
 
 #include "gfxFont.h"
 #include "gfxPlatform.h"
 #include "nsGkAtoms.h"
 
 #include "gfxTypes.h"
-#include "nsAlgorithm.h"
 #include "gfxContext.h"
 #include "gfxFontMissingGlyphs.h"
 #include "gfxUserFontSet.h"
 #include "gfxPlatformFontList.h"
 #include "gfxScriptItemizer.h"
 #include "nsUnicodeProperties.h"
 #include "nsMathUtils.h"
 #include "nsBidiUtils.h"
@@ -35,26 +33,28 @@
 #include "nsStyleConsts.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "gfxSVGGlyphs.h"
+#include "gfx2DGlue.h"
 
 #include "cairo.h"
 #include "gfxFontTest.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "graphite2/Font.h"
 
 #include "nsCRT.h"
 #include "GeckoProfiler.h"
+#include "gfxFontConstants.h"
 
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 using mozilla::services::GetObserverService;
 
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -1,43 +1,39 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_FONT_H
 #define GFX_FONT_H
 
-#include "nsAlgorithm.h"
 #include "gfxTypes.h"
 #include "nsString.h"
 #include "gfxPoint.h"
 #include "gfxFontUtils.h"
 #include "nsTArray.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 #include "gfxSkipChars.h"
 #include "gfxRect.h"
 #include "nsExpirationTracker.h"
-#include "gfxFontConstants.h"
 #include "gfxPlatform.h"
 #include "nsIAtom.h"
-#include "nsISupportsImpl.h"
-#include "gfxPattern.h"
 #include "mozilla/HashFunctions.h"
 #include "nsIMemoryReporter.h"
 #include "nsIObserver.h"
 #include "gfxFontFeatures.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/gfx/Types.h"
 #include "mozilla/Attributes.h"
 #include <algorithm>
-#include "nsUnicodeProperties.h"
+#include "DrawMode.h"
+#include "nsUnicodeScriptCodes.h"
+#include "nsDataHashtable.h"
 #include "harfbuzz/hb.h"
-#include "DrawMode.h"
 
 typedef struct _cairo_scaled_font cairo_scaled_font_t;
 typedef struct gr_face            gr_face;
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
@@ -57,16 +53,22 @@ class nsILanguageAtomService;
 
 #define FONT_MAX_SIZE                  2000.0
 
 #define NO_FONT_LANGUAGE_OVERRIDE      0
 
 struct FontListSizes;
 struct gfxTextRunDrawCallbacks;
 
+namespace mozilla {
+namespace gfx {
+class GlyphRenderingOptions;
+}
+}
+
 struct gfxFontStyle {
     gfxFontStyle();
     gfxFontStyle(uint8_t aStyle, uint16_t aWeight, int16_t aStretch,
                  gfxFloat aSize, nsIAtom *aLanguage,
                  float aSizeAdjust, bool aSystemFont,
                  bool aPrinterFont,
                  const nsString& aLanguageOverride);
     gfxFontStyle(const gfxFontStyle& aStyle);
--- a/gfx/thebes/gfxFontFeatures.h
+++ b/gfx/thebes/gfxFontFeatures.h
@@ -2,17 +2,16 @@
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_FONT_FEATURES_H
 #define GFX_FONT_FEATURES_H
 
-#include "gfxTypes.h"
 #include "nsTHashtable.h"
 #include "nsTArray.h"
 #include "nsString.h"
 
 // An OpenType feature tag and value pair
 struct gfxFontFeature {
     uint32_t mTag; // see http://www.microsoft.com/typography/otspec/featuretags.htm
     uint32_t mValue; // 0 = off, 1 = on, larger values may be used as parameters
--- a/gfx/thebes/gfxFontMissingGlyphs.cpp
+++ b/gfx/thebes/gfxFontMissingGlyphs.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "gfxFontMissingGlyphs.h"
 #include "nsDeviceContext.h"
+#include "gfxContext.h"
+#include "gfxColor.h"
 
 #define CHAR_BITS(b00, b01, b02, b10, b11, b12, b20, b21, b22, b30, b31, b32, b40, b41, b42) \
   ((b00 << 0) | (b01 << 1) | (b02 << 2) | (b10 << 3) | (b11 << 4) | (b12 << 5) | \
    (b20 << 6) | (b21 << 7) | (b22 << 8) | (b30 << 9) | (b31 << 10) | (b32 << 11) | \
    (b40 << 12) | (b41 << 13) | (b42 << 14))
 
 static const uint16_t glyphMicroFont[16] = {
   CHAR_BITS(0, 1, 0,
--- a/gfx/thebes/gfxFontMissingGlyphs.h
+++ b/gfx/thebes/gfxFontMissingGlyphs.h
@@ -2,19 +2,20 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_FONTMISSINGGLYPHS_H
 #define GFX_FONTMISSINGGLYPHS_H
 
 #include "gfxTypes.h"
-#include "gfxContext.h"
 #include "gfxRect.h"
 
+class gfxContext;
+
 /**
  * This class should not be instantiated. It's just a container
  * for some helper functions.
  */
 class gfxFontMissingGlyphs {
 public:
     /**
      * Draw hexboxes for a missing glyph.
--- a/gfx/thebes/gfxFontTest.h
+++ b/gfx/thebes/gfxFontTest.h
@@ -6,19 +6,16 @@
 #ifndef GFX_FONT_TEST_H
 #define GFX_FONT_TEST_H
 
 #include "nsString.h"
 #include "nsTArray.h"
 
 #include "cairo/cairo.h"
 
-#include "gfxFont.h"
-#include "gfxUserFontSet.h"
-
 struct gfxFontTestItem {
     gfxFontTestItem(const nsCString& fontName,
                     cairo_glyph_t *cglyphs, int nglyphs)
         : platformFont(fontName)
     {
         glyphs = new cairo_glyph_t[nglyphs];
         memcpy (glyphs, cglyphs, sizeof(cairo_glyph_t) * nglyphs);
         num_glyphs = nglyphs;
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -1,39 +1,34 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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/. */
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
+#include "prlog.h"
 #endif
-#include "prlog.h"
 
 #include "mozilla/Util.h"
 
 #include "gfxFontUtils.h"
 
 #include "nsServiceManagerUtils.h"
 
 #include "mozilla/Preferences.h"
 
 #include "nsIUUIDGenerator.h"
-#include "nsMemory.h"
 #include "nsICharsetConverterManager.h"
 
 #include "harfbuzz/hb.h"
 
 #include "plbase64.h"
 #include "prlog.h"
 
-#ifdef XP_MACOSX
-#include <CoreFoundation/CoreFoundation.h>
-#endif
-
 #ifdef PR_LOGGING
 
 #define LOG(log, args) PR_LOG(gfxPlatform::GetLog(log), \
                                PR_LOG_DEBUG, args)
 
 #endif // PR_LOGGING
 
 #define UNICODE_BMP_LIMIT 0x10000
@@ -1424,9 +1419,9 @@ bool
 gfxFontUtils::IsCffFont(const uint8_t* aFontData)
 {
     // this is only called after aFontData has passed basic validation,
     // so we know there is enough data present to allow us to read the version!
     const SFNTHeader *sfntHeader = reinterpret_cast<const SFNTHeader*>(aFontData);
     return (sfntHeader->sfntVersion == TRUETYPE_TAG('O','T','T','O'));
 }
 
-#endif
\ No newline at end of file
+#endif
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -1,24 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_FONT_UTILS_H
 #define GFX_FONT_UTILS_H
 
-#include "gfxTypes.h"
 #include "gfxPlatform.h"
-
-#include "nsAlgorithm.h"
-#include "prcpucfg.h"
-
-#include "nsDataHashtable.h"
-
 #include "nsITimer.h"
 #include "nsCOMPtr.h"
 #include "nsComponentManagerUtils.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Likely.h"
 #include "mozilla/Endian.h"
 #include "mozilla/MemoryReporting.h"
--- a/gfx/thebes/gfxFontconfigUtils.cpp
+++ b/gfx/thebes/gfxFontconfigUtils.cpp
@@ -14,16 +14,18 @@
 
 #include "nsServiceManagerUtils.h"
 #include "nsILanguageAtomService.h"
 #include "nsTArray.h"
 #include "mozilla/Preferences.h"
 
 #include "nsIAtom.h"
 #include "nsCRT.h"
+#include "gfxFontConstants.h"
+#include "mozilla/gfx/2D.h"
 
 using namespace mozilla;
 
 /* static */ gfxFontconfigUtils* gfxFontconfigUtils::sUtils = nullptr;
 static nsILanguageAtomService* gLangService = nullptr;
 
 /* static */ void
 gfxFontconfigUtils::Shutdown() {
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -11,16 +11,17 @@
 #include "gfxUniscribeShaper.h"
 #include "gfxHarfBuzzShaper.h"
 #include <algorithm>
 #include "gfxGraphiteShaper.h"
 #include "gfxWindowsPlatform.h"
 #include "gfxContext.h"
 #include "mozilla/Preferences.h"
 #include "nsUnicodeProperties.h"
+#include "gfxFontConstants.h"
 
 #include "cairo-win32.h"
 
 #define ROUND(x) floor((x) + 0.5)
 
 using namespace mozilla;
 using namespace mozilla::unicode;
 
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -21,16 +21,17 @@
 #include "nsTArray.h"
 #include "nsUnicharUtils.h"
 
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIWindowsRegKey.h"
+#include "gfxFontConstants.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Telemetry.h"
 
 #include <usp10.h>
 
 using namespace mozilla;
 
--- a/gfx/thebes/gfxGraphiteShaper.cpp
+++ b/gfx/thebes/gfxGraphiteShaper.cpp
@@ -1,34 +1,22 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "gfxGraphiteShaper.h"
 #include "nsString.h"
-#include "nsBidiUtils.h"
-#include "nsMathUtils.h"
-
-#include "gfxTypes.h"
-
 #include "gfxContext.h"
-#include "gfxPlatform.h"
-#include "gfxGraphiteShaper.h"
-#include "gfxFontUtils.h"
 
 #include "graphite2/Font.h"
 #include "graphite2/Segment.h"
 
 #include "harfbuzz/hb.h"
 
-#include "cairo.h"
-
-#include "nsUnicodeRange.h"
-#include "nsCRT.h"
-
 #define FloatToFixed(f) (65536 * (f))
 #define FixedToFloat(f) ((f) * (1.0 / 65536.0))
 // Right shifts of negative (signed) integers are undefined, as are overflows
 // when converting unsigned to negative signed integers.
 // (If speed were an issue we could make some 2's complement assumptions.)
 #define FixedToIntRound(f) ((f) > 0 ?  ((32768 + (f)) >> 16) \
                                     : -((32767 - (f)) >> 16))
 
--- a/gfx/thebes/gfxGraphiteShaper.h
+++ b/gfx/thebes/gfxGraphiteShaper.h
@@ -1,20 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_GRAPHITESHAPER_H
 #define GFX_GRAPHITESHAPER_H
 
-#include "gfxTypes.h"
 #include "gfxFont.h"
-#include "nsDataHashtable.h"
-#include "nsHashKeys.h"
 
 struct gr_face;
 struct gr_font;
 struct gr_segment;
 
 class gfxGraphiteShaper : public gfxFontShaper {
 public:
     gfxGraphiteShaper(gfxFont *aFont);
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp
+++ b/gfx/thebes/gfxHarfBuzzShaper.cpp
@@ -1,34 +1,24 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsAlgorithm.h"
 #include "nsString.h"
-#include "nsBidiUtils.h"
-#include "nsMathUtils.h"
-
-#include "gfxTypes.h"
-
 #include "gfxContext.h"
-#include "gfxPlatform.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxFontUtils.h"
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeScriptCodes.h"
 #include "nsUnicodeNormalizer.h"
 
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 
-#include "cairo.h"
-
-#include "nsCRT.h"
 #include <algorithm>
 
 #define FloatToFixed(f) (65536 * (f))
 #define FixedToFloat(f) ((f) * (1.0 / 65536.0))
 // Right shifts of negative (signed) integers are undefined, as are overflows
 // when converting unsigned to negative signed integers.
 // (If speed were an issue we could make some 2's complement assumptions.)
 #define FixedToIntRound(f) ((f) > 0 ?  ((32768 + (f)) >> 16) \
--- a/gfx/thebes/gfxHarfBuzzShaper.h
+++ b/gfx/thebes/gfxHarfBuzzShaper.h
@@ -1,20 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_HARFBUZZSHAPER_H
 #define GFX_HARFBUZZSHAPER_H
 
-#include "gfxTypes.h"
 #include "gfxFont.h"
-#include "nsDataHashtable.h"
-#include "nsPoint.h"
 
 #include "harfbuzz/hb.h"
 
 class gfxHarfBuzzShaper : public gfxFontShaper {
 public:
     gfxHarfBuzzShaper(gfxFont *aFont);
     virtual ~gfxHarfBuzzShaper();
 
--- a/gfx/thebes/gfxImageSurface.cpp
+++ b/gfx/thebes/gfxImageSurface.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "mozilla/MemoryReporting.h"
+#if defined(HAVE_POSIX_MEMALIGN)
 #include "gfxAlphaRecovery.h"
+#endif
 #include "gfxImageSurface.h"
 
 #include "cairo.h"
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
 #include <algorithm>
 
 using namespace mozilla::gfx;
--- a/gfx/thebes/gfxImageSurface.h
+++ b/gfx/thebes/gfxImageSurface.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_IMAGESURFACE_H
 #define GFX_IMAGESURFACE_H
 
 #include "mozilla/MemoryReporting.h"
 #include "gfxASurface.h"
 #include "nsAutoPtr.h"
-#include "gfxPoint.h"
+#include "nsSize.h"
 
 // ARGB -- raw buffer.. wont be changed.. good for storing data.
 
 class gfxSubimageSurface;
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -9,16 +9,18 @@
 
 #include "gfxCoreTextShaper.h"
 #include "gfxHarfBuzzShaper.h"
 #include <algorithm>
 #include "gfxGraphiteShaper.h"
 #include "gfxPlatformMac.h"
 #include "gfxContext.h"
 #include "gfxFontUtils.h"
+#include "gfxMacPlatformFontList.h"
+#include "gfxFontConstants.h"
 
 #include "cairo-quartz.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                        bool aNeedsBold)
--- a/gfx/thebes/gfxMacFont.h
+++ b/gfx/thebes/gfxMacFont.h
@@ -3,20 +3,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_MACFONT_H
 #define GFX_MACFONT_H
 
 #include "mozilla/MemoryReporting.h"
 #include "gfxFont.h"
-#include "gfxMacPlatformFontList.h"
-#include "mozilla/gfx/2D.h"
+#include "cairo.h"
+#include <ApplicationServices/ApplicationServices.h>
 
-#include "cairo.h"
+class MacOSFontEntry;
 
 class gfxMacFont : public gfxFont
 {
 public:
     gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
                bool aNeedsBold);
 
     virtual ~gfxMacFont();
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -57,20 +57,22 @@
 
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
 
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsISimpleEnumerator.h"
 #include "nsCharTraits.h"
+#include "gfxFontConstants.h"
 
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/gfx/2D.h"
 
 #include <unistd.h>
 #include <time.h>
 
 using namespace mozilla;
 
 class nsAutoreleasePool {
 public:
--- a/gfx/thebes/gfxMatrix.h
+++ b/gfx/thebes/gfxMatrix.h
@@ -4,17 +4,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_MATRIX_H
 #define GFX_MATRIX_H
 
 #include "gfxPoint.h"
 #include "gfxTypes.h"
 #include "gfxRect.h"
-#include "nsMathUtils.h"
 
 // XX - I don't think this class should use gfxFloat at all,
 // but should use 'double' and be called gfxDoubleMatrix;
 // we can then typedef that to gfxMatrix where we typedef
 // double to be gfxFloat.
 
 /**
  * A matrix that represents an affine transformation. Projective
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -24,16 +24,17 @@
 #include "harfbuzz/hb.h"
 #include "harfbuzz/hb-ot.h"
 #include "gfxHarfBuzzShaper.h"
 #include "gfxGraphiteShaper.h"
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeScriptCodes.h"
 #include "gfxFontconfigUtils.h"
 #include "gfxUserFontSet.h"
+#include "gfxFontConstants.h"
 
 #include <cairo.h>
 #include <cairo-ft.h>
 
 #include <fontconfig/fcfreetype.h>
 #include <pango/pango.h>
 
 #include FT_TRUETYPE_TABLES_H
--- a/gfx/thebes/gfxPattern.cpp
+++ b/gfx/thebes/gfxPattern.cpp
@@ -2,16 +2,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 "gfxTypes.h"
 #include "gfxPattern.h"
 #include "gfxASurface.h"
 #include "gfxPlatform.h"
+#include "gfx2DGlue.h"
 
 #include "cairo.h"
 
 #include <vector>
 
 using namespace mozilla::gfx;
 
 gfxPattern::gfxPattern(cairo_pattern_t *aPattern)
--- a/gfx/thebes/gfxPattern.h
+++ b/gfx/thebes/gfxPattern.h
@@ -3,26 +3,26 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_PATTERN_H
 #define GFX_PATTERN_H
 
 #include "gfxTypes.h"
 
-#include "gfxColor.h"
 #include "gfxMatrix.h"
-#include "nsISupportsImpl.h"
-#include "nsAutoPtr.h"
 #include "mozilla/Alignment.h"
 #include "mozilla/gfx/2D.h"
 #include "GraphicsFilter.h"
+#include "nsISupportsImpl.h"
+#include "nsAutoPtr.h"
 
 class gfxContext;
 class gfxASurface;
+struct gfxRGBA;
 typedef struct _cairo_pattern cairo_pattern_t;
 
 
 class gfxPattern {
     NS_INLINE_DECL_REFCOUNTING(gfxPattern)
 
 public:
     gfxPattern(cairo_pattern_t *aPattern);
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -7,17 +7,16 @@
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 
 #include "prlog.h"
-#include "prenv.h"
 
 #include "gfxPlatform.h"
 
 #include "nsXULAppAPI.h"
 
 #if defined(XP_WIN)
 #include "gfxWindowsPlatform.h"
 #include "gfxD2DSurface.h"
@@ -33,27 +32,25 @@
 #elif defined(ANDROID)
 #include "gfxAndroidPlatform.h"
 #endif
 
 #include "nsGkAtoms.h"
 #include "gfxPlatformFontList.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
-#include "gfxUserFontSet.h"
 #include "nsUnicodeProperties.h"
 #include "harfbuzz/hb.h"
 #include "gfxGraphiteShaper.h"
+#include "gfx2DGlue.h"
 
 #include "nsUnicodeRange.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArray.h"
-#include "nsUnicharUtilCIID.h"
 #include "nsILocaleService.h"
-#include "nsReadableUtils.h"
 
 #include "nsWeakReference.h"
 
 #include "cairo.h"
 #include "qcms.h"
 
 #include "plstr.h"
 #include "nsCRT.h"
@@ -63,22 +60,16 @@
 #ifdef MOZ_WIDGET_ANDROID
 #include "TexturePoolOGL.h"
 #endif
 
 #ifdef USE_SKIA
 #include "skia/SkGraphics.h"
 #endif
 
-#ifdef USE_SKIA_GPU
-#include "skia/GrContext.h"
-#include "skia/GrGLInterface.h"
-#include "GLContextSkia.h"
-#endif
-
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsIGfxInfo.h"
 
 using namespace mozilla;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -4,28 +4,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_PLATFORM_H
 #define GFX_PLATFORM_H
 
 #include "prlog.h"
 #include "nsTArray.h"
 #include "nsString.h"
-#include "nsIObserver.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 
 #include "gfxTypes.h"
-#include "gfxColor.h"
 #include "nsRect.h"
 
 #include "qcms.h"
 
-#include "mozilla/gfx/2D.h"
-#include "gfx2DGlue.h"
 #include "mozilla/RefPtr.h"
 #include "GfxInfoCollector.h"
 
 #include "mozilla/layers/CompositorTypes.h"
 
 #ifdef XP_OS2
 #undef OS2EMX_PLAIN_CHAR
 #endif
@@ -37,21 +33,29 @@ class gfxFontGroup;
 struct gfxFontStyle;
 class gfxUserFontSet;
 class gfxFontEntry;
 class gfxProxyFontEntry;
 class gfxPlatformFontList;
 class gfxTextRun;
 class nsIURI;
 class nsIAtom;
+class nsIObserver;
+struct gfxRGBA;
 
 namespace mozilla {
 namespace gl {
 class GLContext;
 }
+namespace gfx {
+class DrawTarget;
+class SourceSurface;
+class ScaledFont;
+class DrawEventRecorder;
+}
 }
 
 extern cairo_user_data_key_t kDrawTarget;
 
 // pref lang id's for font prefs
 // !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
 // !!! don't use as bit mask, this may grow larger !!!
 
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -15,16 +15,17 @@
 #include "nsUnicodeProperties.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
+#include "mozilla/gfx/2D.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 
 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
                                PR_LOG_DEBUG, args)
 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -4,30 +4,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "gfxPlatformMac.h"
 
 #include "gfxImageSurface.h"
 #include "gfxQuartzSurface.h"
 #include "gfxQuartzImageSurface.h"
 #include "mozilla/gfx/2D.h"
-#include "mozilla/gfx/QuartzSupport.h"
 
 #include "gfxMacPlatformFontList.h"
 #include "gfxMacFont.h"
 #include "gfxCoreTextShaper.h"
 #include "gfxUserFontSet.h"
 
-#include "nsCRT.h"
 #include "nsTArray.h"
-#include "nsUnicodeRange.h"
-
 #include "mozilla/Preferences.h"
-
 #include "qcms.h"
+#include "gfx2DGlue.h"
 
 #include <dlfcn.h>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 // cribbed from CTFontManager.h
 enum {
--- a/gfx/thebes/gfxPlatformMac.h
+++ b/gfx/thebes/gfxPlatformMac.h
@@ -1,27 +1,24 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_PLATFORM_MAC_H
 #define GFX_PLATFORM_MAC_H
 
-#include "nsTArray.h"
+#include "nsTArrayForwardDeclare.h"
 #include "gfxPlatform.h"
 
 #define MAC_OS_X_VERSION_10_6_HEX 0x00001060
 #define MAC_OS_X_VERSION_10_7_HEX 0x00001070
 
 #define MAC_OS_X_MAJOR_VERSION_MASK 0xFFFFFFF0U
 
-class gfxTextRun;
-class gfxFontFamily;
-
 namespace mozilla { namespace gfx { class DrawTarget; }}
 
 class gfxPlatformMac : public gfxPlatform {
 public:
     gfxPlatformMac();
     virtual ~gfxPlatformMac();
 
     static gfxPlatformMac *GetPlatform() {
--- a/gfx/thebes/gfxQuartzImageSurface.cpp
+++ b/gfx/thebes/gfxQuartzImageSurface.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "gfxQuartzImageSurface.h"
+#include "gfxImageSurface.h"
 
-#include "cairo-quartz.h"
 #include "cairo-quartz-image.h"
 
 gfxQuartzImageSurface::gfxQuartzImageSurface(gfxImageSurface *imageSurface)
 {
     if (imageSurface->CairoSurface() == nullptr)
         return;
 
     cairo_surface_t *surf = cairo_quartz_image_surface_create (imageSurface->CairoSurface());
--- a/gfx/thebes/gfxQuartzImageSurface.h
+++ b/gfx/thebes/gfxQuartzImageSurface.h
@@ -2,17 +2,19 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_QUARTZIMAGESURFACE_H
 #define GFX_QUARTZIMAGESURFACE_H
 
 #include "gfxASurface.h"
-#include "gfxImageSurface.h"
+#include "nsSize.h"
+
+class gfxImageSurface;
 
 class gfxQuartzImageSurface : public gfxASurface {
 public:
     gfxQuartzImageSurface(gfxImageSurface *imageSurface);
     gfxQuartzImageSurface(cairo_surface_t *csurf);
 
     virtual ~gfxQuartzImageSurface();
 
--- a/gfx/thebes/gfxQuartzNativeDrawing.cpp
+++ b/gfx/thebes/gfxQuartzNativeDrawing.cpp
@@ -1,15 +1,13 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "nsMathUtils.h"
-
 #include "gfxQuartzNativeDrawing.h"
 #include "gfxQuartzSurface.h"
 #include "cairo-quartz.h"
 
 // see cairo-quartz-surface.c for the complete list of these
 enum {
     kPrivateCGCompositeSourceOver = 2
 };
--- a/gfx/thebes/gfxQuartzNativeDrawing.h
+++ b/gfx/thebes/gfxQuartzNativeDrawing.h
@@ -6,16 +6,17 @@
 #ifndef _GFXQUARTZNATIVEDRAWING_H_
 #define _GFXQUARTZNATIVEDRAWING_H_
 
 #include "mozilla/Attributes.h"
 
 #include "gfxContext.h"
 #include "gfxQuartzSurface.h"
 #include "mozilla/gfx/BorrowedContext.h"
+#include "nsAutoPtr.h"
 
 class gfxQuartzNativeDrawing {
 public:
 
     /* Create native Quartz drawing for a rectangle bounded by
      * nativeRect.
      *
      * Typical usage looks like:
--- a/gfx/thebes/gfxQuartzSurface.cpp
+++ b/gfx/thebes/gfxQuartzSurface.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "gfxQuartzSurface.h"
 #include "gfxContext.h"
+#include "gfxImageSurface.h"
 
 #include "cairo-quartz.h"
 
 void
 gfxQuartzSurface::MakeInvalid()
 {
     mSize = gfxIntSize(-1, -1);    
 }
--- a/gfx/thebes/gfxQuartzSurface.h
+++ b/gfx/thebes/gfxQuartzSurface.h
@@ -2,21 +2,23 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_QUARTZSURFACE_H
 #define GFX_QUARTZSURFACE_H
 
 #include "gfxASurface.h"
-#include "gfxImageSurface.h"
+#include "nsSize.h"
+#include "gfxPoint.h"
 
 #include <Carbon/Carbon.h>
 
 class gfxContext;
+class gfxImageSurface;
 
 class gfxQuartzSurface : public gfxASurface {
 public:
     gfxQuartzSurface(const gfxSize& size, gfxImageFormat format, bool aForPrinting = false);
     gfxQuartzSurface(CGContextRef context, const gfxSize& size, bool aForPrinting = false);
     gfxQuartzSurface(CGContextRef context, const gfxIntSize& size, bool aForPrinting = false);
     gfxQuartzSurface(cairo_surface_t *csurf, bool aForPrinting = false);
     gfxQuartzSurface(unsigned char *data, const gfxSize& size, long stride, gfxImageFormat format, bool aForPrinting = false);
--- a/gfx/thebes/gfxRect.h
+++ b/gfx/thebes/gfxRect.h
@@ -1,20 +1,18 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_RECT_H
 #define GFX_RECT_H
 
-#include "nsAlgorithm.h"
 #include "gfxTypes.h"
 #include "gfxPoint.h"
-#include "gfxCore.h"
 #include "nsDebug.h"
 #include "nsRect.h"
 #include "mozilla/gfx/BaseMargin.h"
 #include "mozilla/gfx/BaseRect.h"
 #include "mozilla/Assertions.h"
 
 struct gfxMargin : public mozilla::gfx::BaseMargin<gfxFloat, gfxMargin> {
   typedef mozilla::gfx::BaseMargin<gfxFloat, gfxMargin> Super;
--- a/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.cpp
+++ b/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.cpp
@@ -1,14 +1,15 @@
 /* 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 "gfxReusableSharedImageSurfaceWrapper.h"
 #include "gfxSharedImageSurface.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
 
 using mozilla::ipc::Shmem;
 using mozilla::layers::ISurfaceAllocator;
 
 gfxReusableSharedImageSurfaceWrapper::gfxReusableSharedImageSurfaceWrapper(ISurfaceAllocator* aAllocator,
                                                                            gfxSharedImageSurface* aSurface)
   : mAllocator(aAllocator)
   , mSurface(aSurface)
--- a/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.h
+++ b/gfx/thebes/gfxReusableSharedImageSurfaceWrapper.h
@@ -1,20 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFXSHMCOWSURFACEWRAPPER
 #define GFXSHMCOWSURFACEWRAPPER
 
 #include "gfxReusableSurfaceWrapper.h"
-#include "mozilla/layers/ISurfaceAllocator.h"
 
 class gfxSharedImageSurface;
 
+namespace mozilla {
+namespace ipc {
+class Shmem;
+}
+namespace layers {
+class ISurfaceAllocator;
+}
+}
+
 /**
  * A cross-process capable implementation of gfxReusableSurfaceWrapper based
  * on gfxSharedImageSurface.
  */
 class gfxReusableSharedImageSurfaceWrapper : public gfxReusableSurfaceWrapper {
 public:
   gfxReusableSharedImageSurfaceWrapper(mozilla::layers::ISurfaceAllocator* aAllocator,
                                        gfxSharedImageSurface* aSurface);
--- a/gfx/thebes/gfxSVGGlyphs.cpp
+++ b/gfx/thebes/gfxSVGGlyphs.cpp
@@ -1,43 +1,38 @@
 /* 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 "gfxSVGGlyphs.h"
 
-#include "nscore.h"
 #include "nsError.h"
-#include "nsAutoPtr.h"
-#include "nsIParser.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMNodeList.h"
 #include "nsString.h"
 #include "nsIDocument.h"
 #include "nsICategoryManager.h"
 #include "nsIDocumentLoaderFactory.h"
 #include "nsIContentViewer.h"
 #include "nsIStreamListener.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIPresShell.h"
-#include "nsQueryFrame.h"
-#include "nsIContentSink.h"
-#include "nsXMLContentSink.h"
 #include "nsNetUtil.h"
 #include "nsIInputStream.h"
 #include "nsStringStream.h"
 #include "nsStreamUtils.h"
 #include "nsIPrincipal.h"
 #include "mozilla/dom/Element.h"
 #include "nsSVGUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsContentUtils.h"
 #include "gfxFont.h"
 #include "nsSMILAnimationController.h"
+#include "gfxContext.h"
+#include "gfxColor.h"
 #include "harfbuzz/hb.h"
 
 #define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml")
 #define UTF8_CHARSET NS_LITERAL_CSTRING("utf-8")
 
 using namespace mozilla;
 
 typedef mozilla::dom::Element Element;
--- a/gfx/thebes/gfxSVGGlyphs.h
+++ b/gfx/thebes/gfxSVGGlyphs.h
@@ -2,30 +2,36 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_SVG_GLYPHS_WRAPPER_H
 #define GFX_SVG_GLYPHS_WRAPPER_H
 
 #include "gfxFontUtils.h"
 #include "nsString.h"
-#include "nsIDocument.h"
 #include "nsAutoPtr.h"
-#include "nsIContentViewer.h"
-#include "nsIPresShell.h"
 #include "nsClassHashtable.h"
 #include "nsBaseHashtable.h"
 #include "nsHashKeys.h"
 #include "gfxPattern.h"
-#include "gfxFont.h"
 #include "mozilla/gfx/UserData.h"
 #include "nsRefreshDriver.h"
- 
+#include "DrawMode.h"
+
+class nsIDocument;
+class nsIContentViewer;
+class nsIPresShell;
 class gfxSVGGlyphs;
+class gfxTextContextPaint;
 
+namespace mozilla {
+namespace dom {
+class Element;
+}
+}
 
 /**
  * Wraps an SVG document contained in the SVG table of an OpenType font.
  * There may be multiple SVG documents in an SVG table which we lazily parse
  *   so we have an instance of this class for every document in the SVG table
  *   which contains a glyph ID which has been used
  * Finds and looks up elements contained in the SVG document which have glyph
  *   mappings to be drawn by gfxSVGGlyphs
--- a/gfx/thebes/gfxScriptItemizer.cpp
+++ b/gfx/thebes/gfxScriptItemizer.cpp
@@ -44,18 +44,18 @@
  * copyright holder.
  *
  * All trademarks and registered trademarks mentioned herein are the property
  * of their respective owners. 
  */
 
 #include "gfxScriptItemizer.h"
 #include "nsUnicodeProperties.h"
-
 #include "nsCharTraits.h"
+#include "harfbuzz/hb.h"
 
 #define MOD(sp) ((sp) % PAREN_STACK_DEPTH)
 #define LIMIT_INC(sp) (((sp) < PAREN_STACK_DEPTH)? (sp) + 1 : PAREN_STACK_DEPTH)
 #define INC(sp,count) (MOD((sp) + (count)))
 #define INC1(sp) (INC(sp, 1))
 #define DEC(sp,count) (MOD((sp) + PAREN_STACK_DEPTH - (count)))
 #define DEC1(sp) (DEC(sp, 1))
 #define STACK_IS_EMPTY() (pushCount <= 0)
--- a/gfx/thebes/gfxScriptItemizer.h
+++ b/gfx/thebes/gfxScriptItemizer.h
@@ -47,17 +47,16 @@
  * of their respective owners. 
  */
 
 #ifndef GFX_SCRIPTITEMIZER_H
 #define GFX_SCRIPTITEMIZER_H
 
 #include <stdint.h>
 #include "prtypes.h"
-#include "harfbuzz/hb.h"
 #include "nsUnicodeScriptCodes.h"
 
 #define PAREN_STACK_DEPTH 32
 
 class gfxScriptItemizer
 {
 public:
     gfxScriptItemizer(const PRUnichar *src, uint32_t length);
--- a/gfx/thebes/gfxSkipChars.h
+++ b/gfx/thebes/gfxSkipChars.h
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_SKIP_CHARS_H
 #define GFX_SKIP_CHARS_H
 
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
-#include "gfxTypes.h"
 
 /*
  * gfxSkipChars is a data structure representing a list of characters that
  * have been skipped. The initial string is called the "original string"
  * and after skipping some characters, the result is called the "skipped string".
  * gfxSkipChars provides efficient ways to translate between offsets in the
  * original string and the skipped string. It is used by textrun code to keep
  * track of offsets before and after text transformations such as whitespace
--- a/gfx/thebes/gfxTeeSurface.cpp
+++ b/gfx/thebes/gfxTeeSurface.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "gfxTeeSurface.h"
 #include "nsAutoPtr.h"
+#include "nsTArray.h"
 
 #include "cairo-tee.h"
 
 gfxTeeSurface::gfxTeeSurface(cairo_surface_t *csurf)
 {
     Init(csurf, true);
 }
 
--- a/gfx/thebes/gfxTeeSurface.h
+++ b/gfx/thebes/gfxTeeSurface.h
@@ -2,19 +2,21 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_TEESURFACE_H
 #define GFX_TEESURFACE_H
 
 #include "gfxASurface.h"
-#include "nsTArray.h"
+#include "nsTArrayForwardDeclare.h"
 #include "nsSize.h"
 
+template<class T> class nsRefPtr;
+
 /**
  * Wraps a cairo_tee_surface. The first surface in the surface list is the
  * primary surface, which answers all surface queries (including size).
  * All drawing is performed on all the surfaces.
  *
  * The device transform of a tee surface is applied before drawing to the
  * underlying surfaces --- which also applies the device transforms of the
  * underlying surfaces.
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -5,24 +5,24 @@
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif /* MOZ_LOGGING */
 #include "prlog.h"
 
 #include "gfxUserFontSet.h"
 #include "gfxPlatform.h"
-#include "nsReadableUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsNetUtil.h"
 #include "nsICacheService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIPrincipal.h"
+#include "gfxFontConstants.h"
 #include "mozilla/Services.h"
-#include "mozilla/Telemetry.h"
+#include "mozilla/gfx/2D.h"
 
 #include "opentype-sanitiser.h"
 #include "ots-memory-stream.h"
 
 using namespace mozilla;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo *
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -1,30 +1,25 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_USER_FONT_SET_H
 #define GFX_USER_FONT_SET_H
 
-#include "gfxTypes.h"
 #include "gfxFont.h"
-#include "gfxFontUtils.h"
 #include "nsRefPtrHashtable.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIURI.h"
-#include "nsIFile.h"
 #include "nsIPrincipal.h"
-#include "nsISupportsImpl.h"
 #include "nsIScriptError.h"
 #include "nsURIHashKey.h"
 
-class gfxMixedFontFamily;
 class nsFontFaceLoader;
 
 //#define DEBUG_USERFONT_CACHE
 
 // parsed CSS @font-face rule information
 // lifetime: from when @font-face rule processed until font is loaded
 struct gfxFontFaceSrc {
     bool                   mIsLocal;       // url or local
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -3,18 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_UTILS_H
 #define GFX_UTILS_H
 
 #include "gfxTypes.h"
 #include "GraphicsFilter.h"
-#include "gfxImageSurface.h"
-#include "mozilla/gfx/2D.h"
 #include "imgIContainer.h"
 
 class gfxDrawable;
 class nsIntRegion;
 struct nsIntRect;
 
 namespace mozilla {
 namespace layers {
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -35,16 +35,17 @@
 #include "gfxDWriteFontList.h"
 #include "gfxDWriteFonts.h"
 #include "gfxDWriteCommon.h"
 #include <dwrite.h>
 #endif
 
 #include "gfxUserFontSet.h"
 #include "nsWindowsHelpers.h"
+#include "gfx2DGlue.h"
 
 #include <string>
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 #ifdef CAIRO_HAS_D2D_SURFACE
--- a/gfx/thebes/nsUnicodeRange.cpp
+++ b/gfx/thebes/nsUnicodeRange.cpp
@@ -1,16 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsUnicodeRange.h"
-#include "nsIAtom.h"
 #include "nsGkAtoms.h"
+#include "mozilla/NullPtr.h"
 
 // This table depends on unicode range definitions. 
 // Each item's index must correspond unicode range value
 // eg. x-cyrillic = LangGroupTable[kRangeCyrillic]
 static nsIAtom **gUnicodeRangeToLangGroupAtomTable[] =
 {
   &nsGkAtoms::x_cyrillic,
   &nsGkAtoms::el_,
--- a/gfx/thebes/nsUnicodeRange.h
+++ b/gfx/thebes/nsUnicodeRange.h
@@ -1,14 +1,14 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nscore.h"
+#include <stdint.h>
 
 class nsIAtom;
 
 // The following constants define unicode subranges
 // values below kRangeNum must be continuous so that we can map to 
 // lang group directly.
 // all ranges we care about should be defined under 32, that allows 
 // us to store range using bits of a uint32_t
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -17,16 +17,17 @@
 #include "gfxImageSurface.h"
 #if defined(XP_WIN)
 #include "gfxWindowsSurface.h"
 #elif defined(XP_MACOSX)
 #include "gfxQuartzImageSurface.h"
 #endif
 #include "nsAutoPtr.h"
 #include "imgIContainer.h"
+#include "gfxColor.h"
 
 class imgFrame
 {
 public:
   imgFrame();
   ~imgFrame();
 
   nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, gfxImageFormat aFormat, uint8_t aPaletteDepth = 0);
--- a/intl/unicharutil/src/nsCategoryImp.cpp
+++ b/intl/unicharutil/src/nsCategoryImp.cpp
@@ -3,31 +3,30 @@
  * 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 "nscore.h"
 #include "nsISupports.h"
 #include "nsCategoryImp.h"
 #include "nsUnicodeProperties.h"
 
-static nsCategoryImp gCategoryImp;
-
 NS_IMPL_QUERY_INTERFACE1(nsCategoryImp, nsIUGenCategory)
 
 NS_IMETHODIMP_(nsrefcnt) nsCategoryImp::AddRef(void)
 {
   return nsrefcnt(1);
 }
 
 NS_IMETHODIMP_(nsrefcnt) nsCategoryImp::Release(void)
 {
   return nsrefcnt(1);
 }
 
 nsCategoryImp* nsCategoryImp::GetInstance()
 {
-  return &gCategoryImp;
+  static nsCategoryImp categoryImp;
+  return &categoryImp;
 }
 
 nsIUGenCategory::nsUGenCategory nsCategoryImp::Get(uint32_t aChar)
 {
   return mozilla::unicode::GetGenCategory(aChar);
 }
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -324,16 +324,20 @@ class HashSet
     //   if (HS::Ptr p = h.lookup(3)) {
     //     assert(*p == 3);   // p acts like a pointer to int
     //   }
     //
     // Also see the definition of Ptr in HashTable above.
     typedef typename Impl::Ptr Ptr;
     Ptr lookup(const Lookup &l) const                 { return impl.lookup(l); }
 
+    // Like lookup, but does not assert if two threads call lookup at the same
+    // time. Only use this method when none of the threads will modify the map.
+    Ptr readonlyThreadsafeLookup(const Lookup &l) const { return impl.readonlyThreadsafeLookup(l); }
+
     // Assuming |p.found()|, remove |*p|.
     void remove(Ptr p)                                { impl.remove(p); }
 
     // Like |lookup(l)|, but on miss, |p = lookupForAdd(l)| allows efficient
     // insertion of T value |t| (where |HashPolicy::match(t,l) == true|) using
     // |add(p,t)|. After |add(p,t)|, |p| points to the new element. E.g.:
     //
     //   typedef HashSet<int> HS;
--- a/js/src/assembler/assembler/X86Assembler.h
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -648,17 +648,18 @@ public:
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, dst);
             m_formatter.immediate32(imm);
         }
     }
 
     void andl_im(int imm, int offset, RegisterID base)
     {
-        FIXME_INSN_PRINTING;
+        spew("andl       $0x%x, %s0x%x(%s)",
+             imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, base, offset);
             m_formatter.immediate8(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, base, offset);
             m_formatter.immediate32(imm);
         }
     }
@@ -701,17 +702,17 @@ public:
         } else {
             m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_AND, dst);
             m_formatter.immediate32(imm);
         }
     }
 #else
     void andl_im(int imm, const void* addr)
     {
-        FIXME_INSN_PRINTING;
+        spew("andl       $0x%x, %p", imm, addr);
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_AND, addr);
             m_formatter.immediate8(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_AND, addr);
             m_formatter.immediate32(imm);
         }
     }
@@ -785,17 +786,18 @@ public:
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, dst);
             m_formatter.immediate32(imm);
         }
     }
 
     void orl_im(int imm, int offset, RegisterID base)
     {
-        FIXME_INSN_PRINTING;
+        spew("orl        $0x%x, %s0x%x(%s)",
+             imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, GROUP1_OP_OR, base, offset);
             m_formatter.immediate8(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_OR, base, offset);
             m_formatter.immediate32(imm);
         }
     }
@@ -1587,17 +1589,17 @@ public:
     {
         spew("movl       %s, %d(%s,%s,%d)",
              nameIReg(4, src), offset, nameIReg(base), nameIReg(index), 1<<scale);
         m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset);
     }
 
     void movl_mEAX(const void* addr)
     {
-        FIXME_INSN_PRINTING;
+        spew("movl       %p, %%eax", addr);
         m_formatter.oneByteOp(OP_MOV_EAXOv);
 #if WTF_CPU_X86_64
         m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
 #else
         m_formatter.immediate32(reinterpret_cast<int>(addr));
 #endif
     }
 
@@ -1614,35 +1616,37 @@ public:
         m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset);
     }
 
     void movl_mr(const void* base, RegisterID index, int scale, RegisterID dst)
     {
         int32_t disp = addressImmediate(base);
 
         spew("movl       %d(,%s,%d), %s",
-             disp, nameIReg(index), scale, nameIReg(dst));
+             disp, nameIReg(index), 1<<scale, nameIReg(dst));
         m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, index, scale, disp);
     }
 
     void movl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
     {
         spew("movl       %d(%s,%s,%d), %s",
              offset, nameIReg(base), nameIReg(index), 1<<scale, nameIReg(4, dst));
         m_formatter.oneByteOp(OP_MOV_GvEv, dst, base, index, scale, offset);
     }
 
     void movl_mr(const void* addr, RegisterID dst)
     {
+        if (dst == X86Registers::eax) {
+            movl_mEAX(addr);
+            return;
+        }
+
         spew("movl       %p, %s",
              addr, nameIReg(4, dst));
-        if (dst == X86Registers::eax)
-            movl_mEAX(addr);
-        else
-            m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
+        m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr);
     }
 
     void movl_i32r(int imm, RegisterID dst)
     {
         spew("movl       $0x%x, %s",
              imm, nameIReg(4, dst));
         m_formatter.oneByteOp(OP_MOV_EAXIv, dst);
         m_formatter.immediate32(imm);
@@ -1695,17 +1699,17 @@ public:
         spew("movl       $0x%x, %d(%s,%s,%d)",
              imm, offset, nameIReg(base), nameIReg(index), 1<<scale);
         m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset);
         m_formatter.immediate32(imm);
     }
 
     void movl_EAXm(const void* addr)
     {
-        FIXME_INSN_PRINTING;
+        spew("movl       %%eax, %p", addr);
         m_formatter.oneByteOp(OP_MOV_OvEAX);
 #if WTF_CPU_X86_64
         m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
 #else
         m_formatter.immediate32(reinterpret_cast<int>(addr));
 #endif
     }
 
@@ -1744,24 +1748,24 @@ public:
         if (src == X86Registers::eax)
             movq_EAXm(addr);
         else
             m_formatter.oneByteOp64(OP_MOV_EvGv, src, addr);
     }
 
     void movq_mEAX(const void* addr)
     {
-        FIXME_INSN_PRINTING;
+        spew("movq       %p, %%rax", addr);
         m_formatter.oneByteOp64(OP_MOV_EAXOv);
         m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
     }
 
     void movq_EAXm(const void* addr)
     {
-        FIXME_INSN_PRINTING;
+        spew("movq       %%rax, %p", addr);
         m_formatter.oneByteOp64(OP_MOV_OvEAX);
         m_formatter.immediate64(reinterpret_cast<int64_t>(addr));
     }
 
     void movq_mr(int offset, RegisterID base, RegisterID dst)
     {
         spew("movq       %s0x%x(%s), %s",
              PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst));
@@ -1869,22 +1873,24 @@ public:
         spew("movl       \?(%%rip), %s",
              nameIReg(dst));
         m_formatter.oneByteRipOp64(OP_MOV_GvEv, dst, 0);
         return JmpSrc(m_formatter.size());
     }
 #endif
     void movl_rm(RegisterID src, const void* addr)
     {
+        if (src == X86Registers::eax) {
+            movl_EAXm(addr);
+            return;
+        }
+
         spew("movl       %s, %p",
              nameIReg(4, src), addr);
-        if (src == X86Registers::eax)
-            movl_EAXm(addr);
-        else
-            m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
+        m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
     }
 
     void movl_i32m(int imm, const void* addr)
     {
         spew("movl       %d, %p", imm, addr);
         m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, addr);
         m_formatter.immediate32(imm);
     }
@@ -2103,17 +2109,17 @@ public:
 
     // Comparison of EAX against a 32-bit immediate. The immediate is patched
     // in as if it were a jump target. The intention is to toggle the first
     // byte of the instruction between a CMP and a JMP to produce a pseudo-NOP.
     JmpSrc cmp_eax()
     {
         m_formatter.oneByteOp(OP_CMP_EAXIv);
         JmpSrc r = m_formatter.immediateRel32();
-        spew("cmp        eax, ((%d))", r.m_offset);
+        spew("cmpl       %%eax, ((%d))", r.m_offset);
         return r;
     }
 
     JmpSrc jmp()
     {
         m_formatter.oneByteOp(OP_JMP_rel32);
         JmpSrc r = m_formatter.immediateRel32();
         spew("jmp        ((%d))", r.m_offset);
@@ -2397,17 +2403,20 @@ public:
              nameFPReg(src), nameIReg(4, dst));
         m_formatter.prefix(PRE_SSE_F3);
         m_formatter.twoByteOp(OP2_CVTTSD2SI_GdWsd, dst, (RegisterID)src);
     }
 
 #if WTF_CPU_X86_64
     void cvttsd2sq_rr(XMMRegisterID src, RegisterID dst)
     {
-        spew("cvttsd2sq  %s, %s",
+        // We call this instruction cvttsd2sq to differentiate the 64-bit
+        // version from the 32-bit version, but in assembler it's just
+        // called cvttsd2si and it's disambiguated by the register name.
+        spew("cvttsd2si  %s, %s",
              nameFPReg(src), nameIReg(dst));
         m_formatter.prefix(PRE_SSE_F2);
         m_formatter.twoByteOp64(OP2_CVTTSD2SI_GdWsd, dst, (RegisterID)src);
     }
 #endif
 
     void unpcklps_rr(XMMRegisterID src, XMMRegisterID dst)
     {
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -147,21 +147,24 @@ MarkStringUnbarriered(JSTracer *trc, JSS
 // Note that some subclasses (e.g. ObjectImpl) specialize some of these
 // methods.
 template <typename T>
 class BarrieredCell : public gc::Cell
 {
   public:
     JS_ALWAYS_INLINE JS::Zone *zone() const { return tenuredZone(); }
     JS_ALWAYS_INLINE JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
-    bool isInsideZone(JS::Zone *zone_) const { return tenuredIsInsideZone(zone_); }
+    JS_ALWAYS_INLINE JS::Zone *zoneFromAnyThread() const { return tenuredZoneFromAnyThread(); }
+    JS_ALWAYS_INLINE JS::shadow::Zone *shadowZoneFromAnyThread() const {
+        return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
+    }
 
     static JS_ALWAYS_INLINE void readBarrier(T *thing) {
 #ifdef JSGC_INCREMENTAL
-        JS::shadow::Zone *shadowZone = thing->shadowZone();
+        JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread();
         if (shadowZone->needsBarrier()) {
             MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
             T *tmp = thing;
             js::gc::MarkUnbarriered<T>(shadowZone->barrierTracer(), &tmp, "read barrier");
             JS_ASSERT(tmp == thing);
         }
 #endif
     }
@@ -176,17 +179,17 @@ class BarrieredCell : public gc::Cell
 
     static JS_ALWAYS_INLINE bool isNullLike(T *thing) { return !thing; }
 
     static JS_ALWAYS_INLINE void writeBarrierPre(T *thing) {
 #ifdef JSGC_INCREMENTAL
         if (isNullLike(thing) || !thing->shadowRuntimeFromAnyThread()->needsBarrier())
             return;
 
-        JS::shadow::Zone *shadowZone = thing->shadowZone();
+        JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread();
         if (shadowZone->needsBarrier()) {
             MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
             T *tmp = thing;
             js::gc::MarkUnbarriered<T>(shadowZone->barrierTracer(), &tmp, "write barrier");
             JS_ASSERT(tmp == thing);
         }
 #endif
     }
@@ -220,16 +223,41 @@ JS_ALWAYS_INLINE JS::Zone *
 ZoneOfValue(const JS::Value &value)
 {
     JS_ASSERT(value.isMarkable());
     if (value.isObject())
         return ZoneOfObject(value.toObject());
     return static_cast<js::gc::Cell *>(value.toGCThing())->tenuredZone();
 }
 
+JS::Zone *
+ZoneOfObjectFromAnyThread(const JSObject &obj);
+
+static inline JS::shadow::Zone *
+ShadowZoneOfObjectFromAnyThread(JSObject *obj)
+{
+    return JS::shadow::Zone::asShadowZone(ZoneOfObjectFromAnyThread(*obj));
+}
+
+static inline JS::shadow::Zone *
+ShadowZoneOfStringFromAnyThread(JSString *str)
+{
+    return JS::shadow::Zone::asShadowZone(
+        reinterpret_cast<const js::gc::Cell *>(str)->tenuredZoneFromAnyThread());
+}
+
+JS_ALWAYS_INLINE JS::Zone *
+ZoneOfValueFromAnyThread(const JS::Value &value)
+{
+    JS_ASSERT(value.isMarkable());
+    if (value.isObject())
+        return ZoneOfObjectFromAnyThread(value.toObject());
+    return static_cast<js::gc::Cell *>(value.toGCThing())->tenuredZoneFromAnyThread();
+}
+
 /*
  * This is a post barrier for HashTables whose key is a GC pointer. Any
  * insertion into a HashTable not marked as part of the runtime, with a GC
  * pointer as a key, must call this immediately after each insertion.
  */
 template <class Map, class Key>
 inline void
 HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
@@ -562,17 +590,17 @@ class EncapsulatedValue : public ValueOp
 
     JSGCTraceKind gcKind() const { return value.gcKind(); }
 
     uint64_t asRawBits() const { return value.asRawBits(); }
 
     static void writeBarrierPre(const Value &v) {
 #ifdef JSGC_INCREMENTAL
         if (v.isMarkable() && shadowRuntimeFromAnyThread(v)->needsBarrier())
-            writeBarrierPre(ZoneOfValue(v), v);
+            writeBarrierPre(ZoneOfValueFromAnyThread(v), v);
 #endif
     }
 
     static void writeBarrierPre(Zone *zone, const Value &v) {
 #ifdef JSGC_INCREMENTAL
         JS::shadow::Zone *shadowZone = JS::shadow::Zone::asShadowZone(zone);
         if (shadowZone->needsBarrier()) {
             JS_ASSERT_IF(v.isMarkable(), shadowRuntimeFromMainThread(v)->needsBarrier());
@@ -945,24 +973,24 @@ class EncapsulatedId
     void unsafeSet(jsid newId) { value = newId; }
     operator jsid() const { return value; }
 
   protected:
     void pre() {
 #ifdef JSGC_INCREMENTAL
         if (JSID_IS_OBJECT(value)) {
             JSObject *obj = JSID_TO_OBJECT(value);
-            JS::shadow::Zone *shadowZone = ShadowZoneOfObject(obj);
+            JS::shadow::Zone *shadowZone = ShadowZoneOfObjectFromAnyThread(obj);
             if (shadowZone->needsBarrier()) {
                 js::gc::MarkObjectUnbarriered(shadowZone->barrierTracer(), &obj, "write barrier");
                 JS_ASSERT(obj == JSID_TO_OBJECT(value));
             }
         } else if (JSID_IS_STRING(value)) {
             JSString *str = JSID_TO_STRING(value);
-            JS::shadow::Zone *shadowZone = ShadowZoneOfString(str);
+            JS::shadow::Zone *shadowZone = ShadowZoneOfStringFromAnyThread(str);
             if (shadowZone->needsBarrier()) {
                 js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &str, "write barrier");
                 JS_ASSERT(str == JSID_TO_STRING(value));
             }
         }
 #endif
     }
 };
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -96,16 +96,17 @@ struct Cell
     inline AllocKind tenuredGetAllocKind() const;
     MOZ_ALWAYS_INLINE bool isMarked(uint32_t color = BLACK) const;
     MOZ_ALWAYS_INLINE bool markIfUnmarked(uint32_t color = BLACK) const;
     MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
 
     inline JSRuntime *runtimeFromMainThread() const;
     inline JS::shadow::Runtime *shadowRuntimeFromMainThread() const;
     inline JS::Zone *tenuredZone() const;
+    inline JS::Zone *tenuredZoneFromAnyThread() const;
     inline bool tenuredIsInsideZone(JS::Zone *zone) const;
 
     // Note: Unrestricted access to the runtime of a GC thing from an arbitrary
     // thread can easily lead to races. Use this method very carefully.
     inline JSRuntime *runtimeFromAnyThread() const;
     inline JS::shadow::Runtime *shadowRuntimeFromAnyThread() const;
 
 #ifdef DEBUG
@@ -1017,16 +1018,23 @@ JS::Zone *
 Cell::tenuredZone() const
 {
     JS::Zone *zone = arenaHeader()->zone;
     JS_ASSERT(CurrentThreadCanAccessZone(zone));
     JS_ASSERT(isTenured());
     return zone;
 }
 
+JS::Zone *
+Cell::tenuredZoneFromAnyThread() const
+{
+    JS_ASSERT(isTenured());
+    return arenaHeader()->zone;
+}
+
 bool
 Cell::tenuredIsInsideZone(JS::Zone *zone) const
 {
     JS_ASSERT(isTenured());
     return zone == arenaHeader()->zone;
 }
 
 #ifdef DEBUG
--- a/js/src/gc/Iteration.cpp
+++ b/js/src/gc/Iteration.cpp
@@ -100,13 +100,12 @@ js::IterateGrayObjects(Zone *zone, GCThi
 
 JS_PUBLIC_API(void)
 JS_IterateCompartments(JSRuntime *rt, void *data,
                        JSIterateCompartmentCallback compartmentCallback)
 {
     JS_ASSERT(!rt->isHeapBusy());
 
     AutoTraceSession session(rt);
-    rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
 
     for (CompartmentsIter c(rt); !c.done(); c.next())
         (*compartmentCallback)(rt, data, c);
 }
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -234,9 +234,15 @@ Zone::discardJitCode(FreeOp *fop)
 }
 
 JS::Zone *
 js::ZoneOfObject(const JSObject &obj)
 {
     return obj.zone();
 }
 
+JS::Zone *
+js::ZoneOfObjectFromAnyThread(const JSObject &obj)
+{
+    return obj.zoneFromAnyThread();
+}
 
+
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/bug923867.js
@@ -0,0 +1,8 @@
+(function(a) {
+    "use asm"
+    var Infinity = a.Infinity
+    function f() {
+        Infinity - (2 ? (1. / .0) : +0)
+    }
+    return f
+})(this)()
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug924538.js
@@ -0,0 +1,9 @@
+// Don't die a float32-related death.
+function testFloat32SetElemIC(a) {
+  for (var i = 0; i < a.length; i++) {
+    var r = Math.fround(Math.random());
+    a[i] = r;
+  }
+}
+testFloat32SetElemIC(new Array(2048));
+testFloat32SetElemIC(new Uint8ClampedArray(2048));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/createthis.js
@@ -0,0 +1,19 @@
+load(libdir + "parallelarray-helpers.js");
+
+function FooStatic(i) {
+  this.i = i;
+}
+
+function testCreateThisWithTemplate() {
+  assertArraySeqParResultsEq(
+    range(0, minItemsTestingThreshold),
+    "map",
+    function (i) {
+      var o = new FooStatic(i);
+      return o.i;
+    });
+}
+
+if (getBuildConfiguration().parallelJS) {
+  testCreateThisWithTemplate();
+}
--- a/js/src/jit/C1Spewer.cpp
+++ b/js/src/jit/C1Spewer.cpp
@@ -109,24 +109,25 @@ DumpLIR(FILE *fp, LInstruction *ins)
     ins->print(fp);
     fprintf(fp, " <|@\n");
 }
 
 void
 C1Spewer::spewIntervals(FILE *fp, LinearScanAllocator *regalloc, LInstruction *ins, size_t &nextId)
 {
     for (size_t k = 0; k < ins->numDefs(); k++) {
-        VirtualRegister *vreg = &regalloc->vregs[ins->getDef(k)->virtualRegister()];
+        uint32_t id = ins->getDef(k)->virtualRegister();
+        VirtualRegister *vreg = &regalloc->vregs[id];
 
         for (size_t i = 0; i < vreg->numIntervals(); i++) {
             LiveInterval *live = vreg->getInterval(i);
             if (live->numRanges()) {
-                fprintf(fp, "%d object \"", (i == 0) ? vreg->id() : int32_t(nextId++));
+                fprintf(fp, "%d object \"", (i == 0) ? id : int32_t(nextId++));
                 fprintf(fp, "%s", live->getAllocation()->toString());
-                fprintf(fp, "\" %d -1", vreg->id());
+                fprintf(fp, "\" %d -1", id);
                 for (size_t j = 0; j < live->numRanges(); j++) {
                     fprintf(fp, " [%d, %d[", live->getRange(j)->from.pos(),
                             live->getRange(j)->to.pos());
                 }
                 for (UsePositionIterator usePos(live->usesBegin()); usePos != live->usesEnd(); usePos++)
                     fprintf(fp, " %d M", usePos->pos.pos());
                 fprintf(fp, " \"\"\n");
             }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -931,17 +931,17 @@ CodeGenerator::visitInterruptCheckImplic
 bool
 CodeGenerator::visitTableSwitch(LTableSwitch *ins)
 {
     MTableSwitch *mir = ins->mir();
     Label *defaultcase = mir->getDefault()->lir()->label();
     const LAllocation *temp;
 
     if (ins->index()->isDouble()) {
-        temp = ins->tempInt();
+        temp = ins->tempInt()->output();
 
         // The input is a double, so try and convert it to an integer.
         // If it does not fit in an integer, take the default case.
         masm.convertDoubleToInt32(ToFloatRegister(ins->index()), ToRegister(temp), defaultcase, false);
     } else {
         temp = ins->index();
     }
 
@@ -3208,17 +3208,17 @@ CodeGenerator::visitNewDenseArrayPar(LNe
     // Invoke a C helper to allocate the elements.  For convenience,
     // this helper also returns the array back to us, or nullptr, which
     // obviates the need to preserve the register across the call.  In
     // reality, we should probably just have the C helper also
     // *allocate* the array, but that would require that it initialize
     // the various fields of the object, and I didn't want to
     // duplicate the code in initGCThing() that already does such an
     // admirable job.
-    masm.setupUnalignedABICall(3, CallTempReg3);
+    masm.setupUnalignedABICall(3, tempReg0);
     masm.passABIArg(sliceReg);
     masm.passABIArg(tempReg2);
     masm.passABIArg(lengthReg);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ExtendArrayPar));
 
     Register resultReg = ToRegister(lir->output());
     JS_ASSERT(resultReg == ReturnReg);
     OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutOutOfMemory, lir);
@@ -3271,76 +3271,66 @@ CodeGenerator::visitNewPar(LNewPar *lir)
 }
 
 class OutOfLineNewGCThingPar : public OutOfLineCodeBase<CodeGenerator>
 {
 public:
     LInstruction *lir;
     gc::AllocKind allocKind;
     Register objReg;
-
-    OutOfLineNewGCThingPar(LInstruction *lir, gc::AllocKind allocKind, Register objReg)
-      : lir(lir), allocKind(allocKind), objReg(objReg)
+    Register sliceReg;
+
+    OutOfLineNewGCThingPar(LInstruction *lir, gc::AllocKind allocKind, Register objReg,
+                           Register sliceReg)
+      : lir(lir), allocKind(allocKind), objReg(objReg), sliceReg(sliceReg)
     {}
 
     bool accept(CodeGenerator *codegen) {
         return codegen->visitOutOfLineNewGCThingPar(this);
     }
 };
 
 bool
 CodeGenerator::emitAllocateGCThingPar(LInstruction *lir, const Register &objReg,
                                       const Register &sliceReg, const Register &tempReg1,
                                       const Register &tempReg2, JSObject *templateObj)
 {
     gc::AllocKind allocKind = templateObj->tenuredGetAllocKind();
-    OutOfLineNewGCThingPar *ool = new OutOfLineNewGCThingPar(lir, allocKind, objReg);
+    OutOfLineNewGCThingPar *ool = new OutOfLineNewGCThingPar(lir, allocKind, objReg, sliceReg);
     if (!ool || !addOutOfLineCode(ool))
         return false;
 
-    masm.newGCThingPar(objReg, sliceReg, tempReg1, tempReg2,
-                            templateObj, ool->entry());
+    masm.newGCThingPar(objReg, sliceReg, tempReg1, tempReg2, templateObj, ool->entry());
     masm.bind(ool->rejoin());
     masm.initGCThing(objReg, templateObj);
     return true;
 }
 
 bool
 CodeGenerator::visitOutOfLineNewGCThingPar(OutOfLineNewGCThingPar *ool)
 {
     // As a fallback for allocation in par. exec. mode, we invoke the
     // C helper NewGCThingPar(), which calls into the GC code.  If it
     // returns nullptr, we bail.  If returns non-nullptr, we rejoin the
     // original instruction.
-
-    // This saves all caller-save registers, regardless of whether
-    // they are live.  This is wasteful but a simplification, given
-    // that for some of the LIR that this is used with
-    // (e.g., LLambdaPar) there are values in those registers
-    // that must not be clobbered but which are not technically
-    // considered live.
-    RegisterSet saveSet(RegisterSet::Volatile());
-
-    // Also preserve the temps we're about to overwrite,
-    // but don't bother to save the objReg.
-    saveSet.addUnchecked(CallTempReg0);
-    saveSet.addUnchecked(CallTempReg1);
-    saveSet.takeUnchecked(AnyRegister(ool->objReg));
-
-    masm.PushRegsInMask(saveSet);
-    masm.move32(Imm32(ool->allocKind), CallTempReg0);
-    masm.setupUnalignedABICall(1, CallTempReg1);
-    masm.passABIArg(CallTempReg0);
+    Register out = ool->objReg;
+
+    saveVolatile(out);
+    masm.setupUnalignedABICall(2, out);
+    masm.passABIArg(ool->sliceReg);
+    masm.move32(Imm32(ool->allocKind), out);
+    masm.passABIArg(out);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewGCThingPar));
-    masm.movePtr(ReturnReg, ool->objReg);
-    masm.PopRegsInMask(saveSet);
+    masm.storeCallResult(out);
+    restoreVolatile(out);
+
     OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutOutOfMemory, ool->lir);
     if (!bail)
         return false;
-    masm.branchTestPtr(Assembler::Zero, ool->objReg, ool->objReg, bail->entry());
+    masm.branchTestPtr(Assembler::Zero, out, out, bail->entry());
     masm.jump(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::visitAbortPar(LAbortPar *lir)
 {
     OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutUnsupported, lir);
@@ -3470,17 +3460,17 @@ CodeGenerator::visitCreateThisWithProto(
 typedef JSObject *(*NewGCThingFn)(JSContext *cx, gc::AllocKind allocKind, size_t thingSize,
                                   gc::InitialHeap initialHeap);
 static const VMFunction NewGCThingInfo =
     FunctionInfo<NewGCThingFn>(js::jit::NewGCThing);
 
 bool
 CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
 {
-    JSObject *templateObject = lir->mir()->getTemplateObject();
+    JSObject *templateObject = lir->mir()->templateObject();
     gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
     int thingSize = (int)gc::Arena::thingSize(allocKind);
     gc::InitialHeap initialHeap = templateObject->type()->initialHeapForJITAlloc();
     Register objReg = ToRegister(lir->output());
 
     OutOfLineCode *ool = oolCallVM(NewGCThingInfo, lir,
                                    (ArgList(), Imm32(allocKind), Imm32(thingSize), Imm32(initialHeap)),
                                    StoreRegisterTo(objReg));
@@ -4844,17 +4834,21 @@ CodeGenerator::visitStoreElementHoleV(LS
         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
                                    bool strict);
-static const VMFunction SetObjectElementInfo = FunctionInfo<SetObjectElementFn>(SetObjectElement);
+typedef ParallelResult (*SetElementParFn)(ForkJoinSlice *, HandleObject, HandleValue,
+                                          HandleValue, bool);
+static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
+    FunctionInfo<SetObjectElementFn>(SetObjectElement),
+    FunctionInfo<SetElementParFn>(SetElementPar));
 
 bool
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
 {
     Register object, elements;
     LInstruction *ins = ool->ins();
     const LAllocation *index;
     MIRType valueType;
@@ -4874,35 +4868,27 @@ CodeGenerator::visitOutOfLineStoreElemen
         index = store->index();
         valueType = store->mir()->value()->type();
         if (store->value()->isConstant())
             value = ConstantOrRegister(*store->value()->toConstant());
         else
             value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
     }
 
-    // We can bump the initialized length inline if index ==
-    // initializedLength and index < capacity.  Otherwise, we have to
-    // consider fallback options.  In fallback cases, we branch to one
-    // of two labels because (at least in parallel mode) we can
-    // recover from index < capacity but not index !=
-    // initializedLength.
-    Label indexNotInitLen;
-    Label indexWouldExceedCapacity;
-
     // If index == initializedLength, try to bump the initialized length inline.
     // If index > initializedLength, call a stub. Note that this relies on the
     // condition flags sticking from the incoming branch.
-    masm.j(Assembler::NotEqual, &indexNotInitLen);
+    Label callStub;
+    masm.j(Assembler::NotEqual, &callStub);
 
     Int32Key key = ToInt32Key(index);
 
     // Check array capacity.
     masm.branchKey(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
-                   key, &indexWouldExceedCapacity);
+                   key, &callStub);
 
     // Update initialized length. The capacity guard above ensures this won't overflow,
     // due to NELEMENTS_LIMIT.
     masm.bumpKey(&key, 1);
     masm.storeKey(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
 
     // Update length if length < initializedLength.
     Label dontUpdate;
@@ -4920,99 +4906,32 @@ CodeGenerator::visitOutOfLineStoreElemen
         storeElementTyped(ins->toStoreElementHoleT()->value(), valueType, MIRType_None, elements,
                           index);
         masm.jump(ool->rejoin());
     } else {
         // Jump to the inline path where we will store the value.
         masm.jump(ool->rejoinStore());
     }
 
-    switch (gen->info().executionMode()) {
-      case SequentialExecution:
-        masm.bind(&indexNotInitLen);
-        masm.bind(&indexWouldExceedCapacity);
-        saveLive(ins);
-
-        pushArg(Imm32(current->mir()->strict()));
-        pushArg(value);
-        if (index->isConstant())
-            pushArg(*index->toConstant());
-        else
-            pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(index)));
-        pushArg(object);
-        if (!callVM(SetObjectElementInfo, ins))
-            return false;
-
-        restoreLive(ins);
-        masm.jump(ool->rejoin());
-        return true;
-
-      case ParallelExecution: {
-        //////////////////////////////////////////////////////////////
-        // If the problem is that we do not have sufficient capacity,
-        // try to reallocate the elements array and then branch back
-        // to perform the actual write.  Note that we do not want to
-        // force the reg alloc to assign any particular register, so
-        // we make space on the stack and pass the arguments that way.
-        // (Also, outside of the VM call mechanism, it's very hard to
-        // pass in a Value to a C function!).
-        masm.bind(&indexWouldExceedCapacity);
-
-        OutOfLineAbortPar *bail = oolAbortPar(ParallelBailoutOutOfMemory, ins);
-        if (!bail)
-            return false;
-
-        // The use of registers here is somewhat subtle.  We need to
-        // save and restore the volatile registers but we also need to
-        // preserve the ReturnReg. Normally we'd just add a constraint
-        // to the regalloc, but since this is the slow path of a hot
-        // instruction we don't want to do that.  So instead we push
-        // the volatile registers but we don't save the register
-        // `object`.  We will copy the ReturnReg into `object`.  The
-        // function we are calling (`PushPar`) agrees to either return
-        // `object` unchanged or nullptr.  This way after we restore
-        // the registers, we can examine `object` to know whether an
-        // error occurred.
-        RegisterSet saveSet(ins->safepoint()->liveRegs());
-        saveSet.takeUnchecked(object);
-
-        masm.PushRegsInMask(saveSet);
-        masm.reserveStack(sizeof(PushParArgs));
-        masm.storePtr(object, Address(StackPointer, offsetof(PushParArgs, object)));
-        masm.storeConstantOrRegister(value, Address(StackPointer,
-                                                    offsetof(PushParArgs, value)));
-        masm.movePtr(StackPointer, CallTempReg0);
-        masm.setupUnalignedABICall(1, CallTempReg1);
-        masm.passABIArg(CallTempReg0);
-        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PushPar));
-        masm.freeStack(sizeof(PushParArgs));
-        masm.movePtr(ReturnReg, object);
-        masm.PopRegsInMask(saveSet);
-        masm.branchTestPtr(Assembler::Zero, object, object, bail->entry());
-        masm.jump(ool->rejoin());
-
-        //////////////////////////////////////////////////////////////
-        // If the problem is that we are trying to write an index that
-        // is not the initialized length, that would result in a
-        // sparse array, and since we don't want to think about that
-        // case right now, we just bail out.
-        masm.bind(&indexNotInitLen);
-        OutOfLineAbortPar *bail1 = oolAbortPar(ParallelBailoutUnsupportedSparseArray, ins);
-        if (!bail1)
-            return false;
-        masm.jump(bail1->entry());
-        return true;
-      }
-
-      default:
-        MOZ_ASSUME_UNREACHABLE("No such execution mode");
-    }
-
-    JS_ASSERT(false);
-    return false;
+    masm.bind(&callStub);
+    saveLive(ins);
+
+    pushArg(Imm32(current->mir()->strict()));
+    pushArg(value);
+    if (index->isConstant())
+        pushArg(*index->toConstant());
+    else
+        pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(index)));
+    pushArg(object);
+    if (!callVM(SetObjectElementInfo, ins))
+        return false;
+
+    restoreLive(ins);
+    masm.jump(ool->rejoin());
+    return true;
 }
 
 typedef bool (*ArrayPopShiftFn)(JSContext *, HandleObject, MutableHandleValue);
 static const VMFunction ArrayPopDenseInfo = FunctionInfo<ArrayPopShiftFn>(jit::ArrayPopDense);
 static const VMFunction ArrayShiftDenseInfo = FunctionInfo<ArrayPopShiftFn>(jit::ArrayShiftDense);
 
 bool
 CodeGenerator::emitArrayPopShift(LInstruction *lir, const MArrayPopShift *mir, Register obj,
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -23,20 +23,16 @@ StartArgSlot(JSScript *script, JSFunctio
 }
 
 inline unsigned
 CountArgSlots(JSScript *script, JSFunction *fun)
 {
     return StartArgSlot(script, fun) + (fun ? fun->nargs + 1 : 0);
 }
 
-// Not as part of the enum so we don't get warnings about unhandled enum
-// values.
-static const unsigned NumExecutionModes = ParallelExecution + 1;
-
 // Contains information about the compilation source for IR being generated.
 class CompileInfo
 {
   public:
     CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing,
                 ExecutionMode executionMode)
       : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing),
         executionMode_(executionMode)
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -1959,17 +1959,17 @@ SetPropertyIC::attachNativeExisting(JSCo
         // Obtain and guard on the TypeObject of the object.
         types::TypeObject *type = obj->getType(cx);
         masm.branchPtr(Assembler::NotEqual,
                        Address(object(), JSObject::offsetOfType()),
                        ImmGCPtr(type), &failures);
 
         if (checkTypeset) {
             TypedOrValueRegister valReg = value().reg();
-            types::HeapTypeSet *propTypes = type->maybeGetProperty(cx, NameToId(name()));
+            types::HeapTypeSet *propTypes = type->maybeGetProperty(NameToId(name()));
             JS_ASSERT(propTypes);
             JS_ASSERT(!propTypes->unknown());
 
             Register scratchReg = object();
             masm.push(scratchReg);
 
             masm.guardTypeSet(valReg, propTypes, scratchReg, &barrierFailure);
             masm.pop(object());
@@ -2607,17 +2607,17 @@ IsPropertySetInlineable(JSContext *cx, c
         return false;
 
     if (!pshape->writable())
         return false;
 
     bool shouldCheck = false;
     types::TypeObject *type = obj->getType(cx);
     if (cache.needsTypeBarrier() && !type->unknownProperties()) {
-        types::HeapTypeSet *propTypes = type->maybeGetProperty(cx, id);
+        types::HeapTypeSet *propTypes = type->maybeGetProperty(id);
         if (!propTypes)
             return false;
         if (!propTypes->unknown()) {
             shouldCheck = true;
             ConstantOrRegister val = cache.value();
             if (val.constant()) {
                 // If the input is a constant, then don't bother if the barrier will always fail.
                 if (!propTypes->hasType(types::GetValueType(cache.value().value())))
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -1849,16 +1849,21 @@ MacroAssembler::convertTypedOrValueToInt
         if (src.typedReg().gpr() != output)
             move32(src.typedReg().gpr(), output);
         if (src.type() == MIRType_Int32 && behavior == IntConversion_ClampToUint8)
             clampIntToUint8(output);
         break;
       case MIRType_Double:
         convertDoubleToInt(src.typedReg().fpu(), output, temp, nullptr, fail, behavior);
         break;
+      case MIRType_Float32:
+        // Conversion to Double simplifies implementation at the expense of performance.
+        convertFloatToDouble(src.typedReg().fpu(), temp);
+        convertDoubleToInt(temp, output, temp, nullptr, fail, behavior);
+        break;
       case MIRType_String:
       case MIRType_Object:
         jump(fail);
         break;
       default:
         MOZ_ASSUME_UNREACHABLE("Bad MIRType");
     }
 }
--- a/js/src/jit/JSONSpewer.cpp
+++ b/js/src/jit/JSONSpewer.cpp
@@ -398,20 +398,21 @@ JSONSpewer::spewIntervals(LinearScanAllo
     for (size_t bno = 0; bno < regalloc->graph.numBlocks(); bno++) {
         beginObject();
         integerProperty("number", bno);
         beginListProperty("vregs");
 
         LBlock *lir = regalloc->graph.getBlock(bno);
         for (LInstructionIterator ins = lir->begin(); ins != lir->end(); ins++) {
             for (size_t k = 0; k < ins->numDefs(); k++) {
-                VirtualRegister *vreg = &regalloc->vregs[ins->getDef(k)->virtualRegister()];
+                uint32_t id = ins->getDef(k)->virtualRegister();
+                VirtualRegister *vreg = &regalloc->vregs[id];
 
                 beginObject();
-                integerProperty("vreg", vreg->id());
+                integerProperty("vreg", id);
                 beginListProperty("intervals");
 
                 for (size_t i = 0; i < vreg->numIntervals(); i++) {
                     LiveInterval *live = vreg->getInterval(i);
 
                     if (live->numRanges()) {
                         beginObject();
                         property("allocation");
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -349,22 +349,22 @@ class LNewPar : public LInstructionHelpe
     MNewPar *mir() const {
         return mir_->toNewPar();
     }
 
     const LAllocation *forkJoinSlice() {
         return getOperand(0);
     }
 
-    const LAllocation *getTemp0() {
-        return getTemp(0)->output();
-    }
-
-    const LAllocation *getTemp1() {
-        return getTemp(1)->output();
+    const LDefinition *getTemp0() {
+        return getTemp(0);
+    }
+
+    const LDefinition *getTemp1() {
+        return getTemp(1);
     }
 };
 
 class LNewDenseArrayPar : public LCallInstructionHelper<1, 2, 3>
 {
   public:
     LIR_HEADER(NewDenseArrayPar);
 
@@ -385,26 +385,26 @@ class LNewDenseArrayPar : public LCallIn
     const LAllocation *forkJoinSlice() {
         return getOperand(0);
     }
 
     const LAllocation *length() {
         return getOperand(1);
     }
 
-    const LAllocation *getTemp0() {
-        return getTemp(0)->output();
-    }
-
-    const LAllocation *getTemp1() {
-        return getTemp(1)->output();
-    }
-
-    const LAllocation *getTemp2() {
-        return getTemp(2)->output();
+    const LDefinition *getTemp0() {
+        return getTemp(0);
+    }
+
+    const LDefinition *getTemp1() {
+        return getTemp(1);
+    }
+
+    const LDefinition *getTemp2() {
+        return getTemp(2);
     }
 };
 
 // Allocates a new DeclEnvObject.
 //
 // This instruction generates two possible instruction sets:
 //   (1) An inline allocation of the call object is attempted.
 //   (2) Otherwise, a callVM create a new object.
@@ -487,22 +487,22 @@ public:
         // the LConstantIndex::Bogus() generated above instead.
         return slots() && ! slots()->isConstant();
     }
 
     const MNewCallObjectPar *mir() const {
         return mir_->toNewCallObjectPar();
     }
 
-    const LAllocation *getTemp0() {
-        return getTemp(0)->output();
-    }
-
-    const LAllocation *getTemp1() {
-        return getTemp(1)->output();
+    const LDefinition *getTemp0() {
+        return getTemp(0);
+    }
+
+    const LDefinition *getTemp1() {
+        return getTemp(1);
     }
 };
 
 class LNewDerivedTypedObject : public LCallInstructionHelper<1, 3, 0>
 {
   public:
     LIR_HEADER(NewDerivedTypedObject);
 
@@ -1054,21 +1054,21 @@ class LCallGeneric : public LJSCallInstr
         setOperand(0, func);
         setTemp(0, nargsreg);
         setTemp(1, tmpobjreg);
     }
 
     const LAllocation *getFunction() {
         return getOperand(0);
     }
-    const LAllocation *getNargsReg() {
-        return getTemp(0)->output();
-    }
-    const LAllocation *getTempObject() {
-        return getTemp(1)->output();
+    const LDefinition *getNargsReg() {
+        return getTemp(0);
+    }
+    const LDefinition *getTempObject() {
+        return getTemp(1);
     }
 };
 
 // Generates a hardcoded callsite for a known, non-native target.
 class LCallKnown : public LJSCallInstructionHelper<BOX_PIECES, 1, 1>
 {
   public:
     LIR_HEADER(CallKnown)
@@ -1078,18 +1078,18 @@ class LCallKnown : public LJSCallInstruc
     {
         setOperand(0, func);
         setTemp(0, tmpobjreg);
     }
 
     const LAllocation *getFunction() {
         return getOperand(0);
     }
-    const LAllocation *getTempObject() {
-        return getTemp(0)->output();
+    const LDefinition *getTempObject() {
+        return getTemp(0);
     }
 };
 
 // Generates a hardcoded callsite for a known, native target.
 class LCallNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4>
 {
   public:
     LIR_HEADER(CallNative)
@@ -1103,27 +1103,27 @@ class LCallNative : public LJSCallInstru
         setTemp(0, argContext);
         setTemp(1, argUintN);
         setTemp(2, argVp);
 
         // Temporary registers.
         setTemp(3, tmpreg);
     }
 
-    const LAllocation *getArgContextReg() {
-        return getTemp(0)->output();
-    }
-    const LAllocation *getArgUintNReg() {
-        return getTemp(1)->output();
-    }
-    const LAllocation *getArgVpReg() {
-        return getTemp(2)->output();
-    }
-    const LAllocation *getTempReg() {
-        return getTemp(3)->output();
+    const LDefinition *getArgContextReg() {
+        return getTemp(0);
+    }
+    const LDefinition *getArgUintNReg() {
+        return getTemp(1);
+    }
+    const LDefinition *getArgVpReg() {
+        return getTemp(2);
+    }
+    const LDefinition *getTempReg() {
+        return getTemp(3);
     }
 };
 
 // Generates a hardcoded callsite for a known, DOM-native target.
 class LCallDOMNative : public LJSCallInstructionHelper<BOX_PIECES, 0, 4>
 {
   public:
     LIR_HEADER(CallDOMNative)
@@ -1134,27 +1134,27 @@ class LCallDOMNative : public LJSCallIns
       : JSCallHelper(argslot)
     {
         setTemp(0, argJSContext);
         setTemp(1, argObj);
         setTemp(2, argPrivate);
         setTemp(3, argArgs);
     }
 
-    const LAllocation *getArgJSContext() {
-        return getTemp(0)->output();
-    }
-    const LAllocation *getArgObj() {
-        return getTemp(1)->output();
-    }
-    const LAllocation *getArgPrivate() {
-        return getTemp(2)->output();
-    }
-    const LAllocation *getArgArgs() {
-        return getTemp(3)->output();
+    const LDefinition *getArgJSContext() {
+        return getTemp(0);
+    }
+    const LDefinition *getArgObj() {
+        return getTemp(1);
+    }
+    const LDefinition *getArgPrivate() {
+        return getTemp(2);
+    }
+    const LDefinition *getArgArgs() {
+        return getTemp(3);
     }
 };
 
 class LBail : public LInstructionHelper<0, 0, 0>
 {
   public:
     LIR_HEADER(Bail)
 };
@@ -1168,27 +1168,27 @@ class LDOMPropertyInstructionHelper : pu
     {
         this->setOperand(0, ObjectReg);
         this->setTemp(0, JSContextReg);
         this->setTemp(1, PrivReg);
         this->setTemp(2, ValueReg);
     }
 
   public:
-    const LAllocation *getJSContextReg() {
-        return this->getTemp(0)->output();
+    const LDefinition *getJSContextReg() {
+        return this->getTemp(0);
     }
     const LAllocation *getObjectReg() {
         return this->getOperand(0);
     }
-    const LAllocation *getPrivReg() {
-        return this->getTemp(1)->output();
-    }
-    const LAllocation *getValueReg() {
-        return this->getTemp(2)->output();
+    const LDefinition *getPrivReg() {
+        return this->getTemp(1);
+    }
+    const LDefinition *getValueReg() {
+        return this->getTemp(2);
     }
 };
 
 
 class LGetDOMProperty : public LDOMPropertyInstructionHelper<BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(GetDOMProperty)
@@ -1252,21 +1252,21 @@ class LApplyArgsGeneric : public LCallIn
     const LAllocation *getFunction() {
         return getOperand(0);
     }
     const LAllocation *getArgc() {
         return getOperand(1);
     }
     static const size_t ThisIndex = 2;
 
-    const LAllocation *getTempObject() {
-        return getTemp(0)->output();
-    }
-    const LAllocation *getTempCopy() {
-        return getTemp(1)->output();
+    const LDefinition *getTempObject() {
+        return getTemp(0);
+    }
+    const LDefinition *getTempCopy() {
+        return getTemp(1);
     }
 };
 
 class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3>
 {
   public:
     LIR_HEADER(GetDynamicName)
 
@@ -1445,18 +1445,18 @@ class LTestVAndBranch : public LControlI
     }
 
     const char *extraName() const {
         return mir()->operandMightEmulateUndefined() ? "MightEmulateUndefined" : nullptr;
     }
 
     static const size_t Input = 0;
 
-    const LAllocation *tempFloat() {
-        return getTemp(0)->output();
+    const LDefinition *tempFloat() {
+        return getTemp(0);
     }
 
     const LDefinition *temp1() {
         return getTemp(1);
     }
 
     const LDefinition *temp2() {
         return getTemp(2);
@@ -1965,18 +1965,18 @@ class LNotV : public LInstructionHelper<
     static const size_t Input = 0;
     LNotV(const LDefinition &temp0, const LDefinition &temp1, const LDefinition &temp2)
     {
         setTemp(0, temp0);
         setTemp(1, temp1);
         setTemp(2, temp2);
     }
 
-    const LAllocation *tempFloat() {
-        return getTemp(0)->output();
+    const LDefinition *tempFloat() {
+        return getTemp(0);
     }
 
     const LDefinition *temp1() {
         return getTemp(1);
     }
 
     const LDefinition *temp2() {
         return getTemp(2);
@@ -2917,21 +2917,21 @@ class LLambdaPar : public LInstructionHe
         return getOperand(0);
     }
     const LAllocation *scopeChain() {
         return getOperand(1);
     }
     const MLambdaPar *mir() const {
         return mir_->toLambdaPar();
     }
-    const LAllocation *getTemp0() {
-        return getTemp(0)->output();
-    }
-    const LAllocation *getTemp1() {
-        return getTemp(1)->output();
+    const LDefinition *getTemp0() {
+        return getTemp(0);
+    }
+    const LDefinition *getTemp1() {
+        return getTemp(1);
     }
 };
 
 // Determines the implicit |this| value for function calls.
 class LImplicitThis : public LInstructionHelper<BOX_PIECES, 1, 0>
 {
   public:
     LIR_HEADER(ImplicitThis)
@@ -4210,18 +4210,18 @@ class LForkJoinSlice : public LCallInstr
 {
   public:
     LIR_HEADER(ForkJoinSlice);
 
     LForkJoinSlice(const LDefinition &temp1) {
         setTemp(0, temp1);
     }
 
-    const LAllocation *getTempReg() {
-        return getTemp(0)->output();
+    const LDefinition *getTempReg() {
+        return getTemp(0);
     }
 };
 
 class LCallGetProperty : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(CallGetProperty)
 
@@ -4689,18 +4689,18 @@ class LGuardThreadLocalObject : public L
     const LAllocation *forkJoinSlice() {
         return getOperand(0);
     }
 
     const LAllocation *object() {
         return getOperand(1);
     }
 
-    const LAllocation *getTempReg() {
-        return getTemp(0)->output();
+    const LDefinition *getTempReg() {
+        return getTemp(0);
     }
 };
 
 // Guard that a value is in a TypeSet.
 class LTypeBarrierV : public LInstructionHelper<0, BOX_PIECES, 1>
 {
   public:
     LIR_HEADER(TypeBarrierV)
@@ -4832,18 +4832,18 @@ class LGuardClass : public LInstructionH
 
     LGuardClass(const LAllocation &in, const LDefinition &temp) {
         setOperand(0, in);
         setTemp(0, temp);
     }
     const MGuardClass *mir() const {
         return mir_->toGuardClass();
     }
-    const LAllocation *tempInt() {
-        return getTemp(0)->output();
+    const LDefinition *tempInt() {
+        return getTemp(0);
     }
 };
 
 class MPhi;
 
 // Phi is a pseudo-instruction that emits no code, and is an annotation for the
 // register allocator. Like its equivalent in MIR, phis are collected at the
 // top of blocks and are meant to be executed in parallel, choosing the input
--- a/js/src/jit/LiveRangeAllocator.cpp
+++ b/js/src/jit/LiveRangeAllocator.cpp
@@ -423,34 +423,33 @@ LiveRangeAllocator<VREG>::init()
         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_t reg = def->virtualRegister();
-                    if (!vregs[reg].init(reg, block, *ins, def, /* isTemp */ false))
+                    if (!vregs[def].init(block, *ins, def, /* isTemp */ false))
                         return false;
                 }
             }
 
             for (size_t j = 0; j < ins->numTemps(); j++) {
                 LDefinition *def = ins->getTemp(j);
                 if (def->isBogusTemp())
                     continue;
-                if (!vregs[def].init(def->virtualRegister(), block, *ins, def, /* isTemp */ true))
+                if (!vregs[def].init(block, *ins, def, /* isTemp */ true))
                     return false;
             }
         }
         for (size_t j = 0; j < block->numPhis(); j++) {
             LPhi *phi = block->getPhi(j);
             LDefinition *def = phi->getDef(0);
-            if (!vregs[def].init(phi->id(), block, phi, def, /* isTemp */ false))
+            if (!vregs[def].init(block, phi, def, /* isTemp */ false))
                 return false;
         }
     }
 
     return true;
 }
 
 static void
--- a/js/src/jit/LiveRangeAllocator.h
+++ b/js/src/jit/LiveRangeAllocator.h
@@ -366,44 +366,39 @@ class LiveInterval
 
 /*
  * Represents all of the register allocation state associated with a virtual
  * register, including all associated intervals and pointers to relevant LIR
  * structures.
  */
 class VirtualRegister
 {
-    uint32_t id_;
     LBlock *block_;
     LInstruction *ins_;
     LDefinition *def_;
     Vector<LiveInterval *, 1, IonAllocPolicy> intervals_;
 
     // Whether def_ is a temp or an output.
     bool isTemp_ : 1;
 
     void operator=(const VirtualRegister &) MOZ_DELETE;
     VirtualRegister(const VirtualRegister &) MOZ_DELETE;
 
   public:
-    bool init(uint32_t id, LBlock *block, LInstruction *ins, LDefinition *def, bool isTemp) {
+    bool init(LBlock *block, LInstruction *ins, LDefinition *def, bool isTemp) {
         JS_ASSERT(block && !block_);
-        id_ = id;
         block_ = block;
         ins_ = ins;
         def_ = def;
         isTemp_ = isTemp;
         LiveInterval *initial = new LiveInterval(def->virtualRegister(), 0);
         if (!initial)
             return false;
         return intervals_.append(initial);
     }
-    uint32_t id() const {
-        return id_;
-    }
     LBlock *block() {
         return block_;
     }
     LInstruction *ins() {
         return ins_;
     }
     LDefinition *def() const {
         return def_;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -2409,17 +2409,17 @@ class MCreateThisWithTemplate
     }
 
   public:
     INSTRUCTION_HEADER(CreateThisWithTemplate);
     static MCreateThisWithTemplate *New(JSObject *templateObject)
     {
         return new MCreateThisWithTemplate(templateObject);
     }
-    JSObject *getTemplateObject() const {
+    JSObject *templateObject() const {
         return templateObject_;
     }
 
     // Although creation of |this| modifies global state, it is safely repeatable.
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -25,31 +25,30 @@ jit::ForkJoinSlicePar()
 {
     return ForkJoinSlice::Current();
 }
 
 // NewGCThingPar() is called in place of NewGCThing() when executing
 // parallel code.  It uses the ArenaLists for the current thread and
 // allocates from there.
 JSObject *
-jit::NewGCThingPar(gc::AllocKind allocKind)
+jit::NewGCThingPar(ForkJoinSlice *slice, gc::AllocKind allocKind)
 {
-    ForkJoinSlice *slice = ForkJoinSlice::Current();
+    JS_ASSERT(ForkJoinSlice::Current() == slice);
     uint32_t thingSize = (uint32_t)gc::Arena::thingSize(allocKind);
     return gc::NewGCThing<JSObject, NoGC>(slice, allocKind, thingSize, gc::DefaultHeap);
 }
 
 // Check that the object was created by the current thread
 // (and hence is writable).
 bool
 jit::IsThreadLocalObject(ForkJoinSlice *slice, JSObject *object)
 {
     JS_ASSERT(ForkJoinSlice::Current() == slice);
-    return !IsInsideNursery(slice->runtime(), object) &&
-           slice->allocator()->arenas.containsArena(slice->runtime(), object->arenaHeader());
+    return slice->isThreadLocal(object);
 }
 
 #ifdef DEBUG
 static void
 printTrace(const char *prefix, struct IonLIRTraceData *cached)
 {
     fprintf(stderr, "%s / Block %3u / LIR %3u / Mode %u / LIR %s\n",
             prefix,
@@ -146,40 +145,45 @@ jit::CheckInterruptPar(ForkJoinSlice *sl
         // thread.  Either way we have nothing useful to contribute so
         // we might as well leave our bailout case unset.
         return false;
     }
     return true;
 }
 
 JSObject *
-jit::PushPar(PushParArgs *args)
-{
-    // It is awkward to have the MIR pass the current slice in, so
-    // just fetch it from TLS.  Extending the array is kind of the
-    // slow path anyhow as it reallocates the elements vector.
-    ForkJoinSlice *slice = js::ForkJoinSlice::Current();
-    JSObject::EnsureDenseResult res =
-        args->object->parExtendDenseElements(slice, &args->value, 1);
-    if (res != JSObject::ED_OK)
-        return nullptr;
-    return args->object;
-}
-
-JSObject *
 jit::ExtendArrayPar(ForkJoinSlice *slice, JSObject *array, uint32_t length)
 {
     JSObject::EnsureDenseResult res =
-        array->parExtendDenseElements(slice, nullptr, length);
+        array->ensureDenseElementsPreservePackedFlag(slice, 0, length);
     if (res != JSObject::ED_OK)
         return nullptr;
     return array;
 }
 
 ParallelResult
+jit::SetElementPar(ForkJoinSlice *slice, HandleObject obj, HandleValue index, HandleValue value,
+                   bool strict)
+{
+    RootedId id(slice);
+    if (!ValueToIdPure(index, id.address()))
+        return TP_RETRY_SEQUENTIALLY;
+
+    // SetObjectElementOperation, the sequential version, has several checks
+    // for certain deoptimizing behaviors, such as marking having written to
+    // holes and non-indexed element accesses. We don't do that here, as we
+    // can't modify any TI state anyways. If we need to add a new type, we
+    // would bail out.
+    RootedValue v(slice, value);
+    if (!baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict))
+        return TP_RETRY_SEQUENTIALLY;
+    return TP_SUCCESS;
+}
+
+ParallelResult
 jit::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
                       MutableHandleString out)
 {
     JSString *str = ConcatStrings<NoGC>(slice, left, right);
     if (!str)
         return TP_RETRY_SEQUENTIALLY;
     out.set(str);
     return TP_SUCCESS;
@@ -552,17 +556,20 @@ jit::InitRestParameterPar(ForkJoinSlice 
     // In parallel execution, we should always have succeeded in allocation
     // before this point. We can do the allocation here like in the sequential
     // path, but duplicating the initGCThing logic is too tedious.
     JS_ASSERT(res);
     JS_ASSERT(res->is<ArrayObject>());
     JS_ASSERT(!res->getDenseInitializedLength());
     JS_ASSERT(res->type() == templateObj->type());
 
-    if (length) {
-        JSObject::EnsureDenseResult edr = res->parExtendDenseElements(slice, rest, length);
+    if (length > 0) {
+        JSObject::EnsureDenseResult edr =
+            res->ensureDenseElementsPreservePackedFlag(slice, 0, length);
         if (edr != JSObject::ED_OK)
             return TP_FATAL;
+        res->initDenseElements(0, rest, length);
+        res->as<ArrayObject>().setLengthInt32(length);
     }
 
     out.set(res);
     return TP_SUCCESS;
 }
--- a/js/src/jit/ParallelFunctions.h
+++ b/js/src/jit/ParallelFunctions.h
@@ -9,39 +9,30 @@
 
 #include "gc/Heap.h"
 #include "vm/ForkJoin.h"
 
 namespace js {
 namespace jit {
 
 ForkJoinSlice *ForkJoinSlicePar();
-JSObject *NewGCThingPar(gc::AllocKind allocKind);
-bool IsThreadLocalObject(ForkJoinSlice *context, JSObject *object);
+JSObject *NewGCThingPar(ForkJoinSlice *slice, gc::AllocKind allocKind);
+bool IsThreadLocalObject(ForkJoinSlice *slice, JSObject *object);
 bool CheckOverRecursedPar(ForkJoinSlice *slice);
-bool CheckInterruptPar(ForkJoinSlice *context);
-
-// We pass the arguments to PushPar in a structure because, in code
-// gen, it is convenient to store them on the stack to avoid
-// constraining the reg alloc for the slow path.
-struct PushParArgs {
-    JSObject *object;
-    Value value;
-};
-
-// Extends the given object with the given value (like `Array.push`).
-// Returns nullptr on failure or else `args->object`, which is convenient
-// during code generation.
-JSObject *PushPar(PushParArgs *args);
+bool CheckInterruptPar(ForkJoinSlice *slice);
 
 // Extends the given array with `length` new holes.  Returns nullptr on
 // failure or else `array`, which is convenient during code
 // generation.
 JSObject *ExtendArrayPar(ForkJoinSlice *slice, JSObject *array, uint32_t length);
 
+// Set properties and elements on thread local objects.
+ParallelResult SetElementPar(ForkJoinSlice *slice, HandleObject obj, HandleValue index,
+                             HandleValue value, bool strict);
+
 // String related parallel functions. These tend to call existing VM functions
 // that take a ThreadSafeContext.
 ParallelResult ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
                                 MutableHandleString out);
 ParallelResult IntToStringPar(ForkJoinSlice *slice, int i, MutableHandleString out);
 ParallelResult DoubleToStringPar(ForkJoinSlice *slice, double d, MutableHandleString out);
 ParallelResult StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out);
 
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -118,17 +118,17 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(OsrValue)
     UNSAFE_OP(OsrScopeChain)
     UNSAFE_OP(OsrArgumentsObject)
     UNSAFE_OP(ReturnFromCtor)
     CUSTOM_OP(CheckOverRecursed)
     UNSAFE_OP(DefVar)
     UNSAFE_OP(DefFun)
     UNSAFE_OP(CreateThis)
-    UNSAFE_OP(CreateThisWithTemplate)
+    CUSTOM_OP(CreateThisWithTemplate)
     UNSAFE_OP(CreateThisWithProto)
     UNSAFE_OP(CreateArgumentsObject)
     UNSAFE_OP(GetArgumentsObjectArg)
     UNSAFE_OP(SetArgumentsObjectArg)
     UNSAFE_OP(ComputeThis)
     SAFE_OP(PrepareCall)
     SAFE_OP(PassArg)
     CUSTOM_OP(Call)
@@ -497,20 +497,25 @@ ParallelSafetyVisitor::convertToBailout(
 // Memory allocation
 //
 // Simple memory allocation opcodes---those which ultimately compile
 // down to a (possibly inlined) invocation of NewGCThing()---are
 // replaced with MNewPar, which is supplied with the thread context.
 // These allocations will take place using per-helper-thread arenas.
 
 bool
+ParallelSafetyVisitor::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
+{
+    return replaceWithNewPar(ins, ins->templateObject());
+}
+
+bool
 ParallelSafetyVisitor::visitNewParallelArray(MNewParallelArray *ins)
 {
-    replace(ins, new MNewPar(forkJoinSlice(), ins->templateObject()));
-    return true;
+    return replaceWithNewPar(ins, ins->templateObject());
 }
 
 bool
 ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins)
 {
     replace(ins, MNewCallObjectPar::New(forkJoinSlice(), ins));
     return true;
 }
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -436,16 +436,20 @@ Range::add(const Range *lhs, const Range
         h = NoInt32UpperBound;
 
     // The exponent is at most one greater than the greater of the operands'
     // exponents, except for NaN and infinity cases.
     uint16_t e = Max(lhs->max_exponent_, rhs->max_exponent_);
     if (e <= Range::MaxFiniteExponent)
         ++e;
 
+    // Infinity + -Infinity is NaN.
+    if (lhs->canBeInfiniteOrNaN() && rhs->canBeInfiniteOrNaN())
+        e = Range::IncludesInfinityAndNaN;
+
     return new Range(l, h, lhs->canHaveFractionalPart() || rhs->canHaveFractionalPart(), e);
 }
 
 Range *
 Range::sub(const Range *lhs, const Range *rhs)
 {
     int64_t l = (int64_t) lhs->lower_ - (int64_t) rhs->upper_;
     if (!lhs->hasInt32LowerBound() || !rhs->hasInt32UpperBound())
@@ -456,16 +460,20 @@ Range::sub(const Range *lhs, const Range
         h = NoInt32UpperBound;
 
     // The exponent is at most one greater than the greater of the operands'
     // exponents, except for NaN and infinity cases.
     uint16_t e = Max(lhs->max_exponent_, rhs->max_exponent_);
     if (e <= Range::MaxFiniteExponent)
         ++e;
 
+    // Infinity - Infinity is NaN.
+    if (lhs->canBeInfiniteOrNaN() && rhs->canBeInfiniteOrNaN())
+        e = Range::IncludesInfinityAndNaN;
+
     return new Range(l, h, lhs->canHaveFractionalPart() || rhs->canHaveFractionalPart(), e);
 }
 
 Range *
 Range::and_(const Range *lhs, const Range *rhs)
 {
     JS_ASSERT(lhs->isInt32());
     JS_ASSERT(rhs->isInt32());
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -161,17 +161,17 @@ SetConst(JSContext *cx, HandlePropertyNa
 bool
 InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value)
 {
     // Copy the incoming value. This may be overwritten; the return value is discarded.
     RootedValue rval(cx, value);
     RootedId id(cx, NameToId(name));
 
     if (name == cx->names().proto)
-        return baseops::SetPropertyHelper(cx, obj, obj, id, 0, &rval, false);
+        return baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, 0, &rval, false);
     return DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr, JSPROP_ENUMERATE, 0, 0, 0);
 }
 
 template<bool Equal>
 bool
 LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     if (!js::LooselyEqual(cx, lhs, rhs, res))
@@ -433,17 +433,18 @@ SetProperty(JSContext *cx, HandleObject 
         Shape *shape = obj->nativeLookup(cx, name);
         JS_ASSERT(shape && shape->hasSlot());
         JSObject::nativeSetSlotWithType(cx, obj, shape, value);
         return true;
     }
 
     if (JS_LIKELY(!obj->getOps()->setProperty)) {
         unsigned defineHow = (op == JSOP_SETNAME || op == JSOP_SETGNAME) ? DNP_UNQUALIFIED : 0;
-        return baseops::SetPropertyHelper(cx, obj, obj, id, defineHow, &v, strict);
+        return baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, defineHow, &v,
+                                                               strict);
     }
 
     return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
 }
 
 bool
 InterruptCheck(JSContext *cx)
 {
--- a/js/src/jit/arm/LIR-arm.h
+++ b/js/src/jit/arm/LIR-arm.h
@@ -282,21 +282,21 @@ class LTableSwitch : public LInstruction
 
     MTableSwitch *mir() const {
         return mir_->toTableSwitch();
     }
 
     const LAllocation *index() {
         return getOperand(0);
     }
-    const LAllocation *tempInt() {
-        return getTemp(0)->output();
+    const LDefinition *tempInt() {
+        return getTemp(0);
     }
     // This is added to share the same CodeGenerator prefixes.
-    const LAllocation *tempPointer() {
+    const LDefinition *tempPointer() {
         return nullptr;
     }
 };
 
 // Takes a tableswitch with an integer to decide
 class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 2>
 {
   public:
@@ -311,58 +311,58 @@ class LTableSwitchV : public LInstructio
     }
 
     MTableSwitch *mir() const {
         return mir_->toTableSwitch();
     }
 
     static const size_t InputValue = 0;
 
-    const LAllocation *tempInt() {
-        return getTemp(0)->output();
+    const LDefinition *tempInt() {
+        return getTemp(0);
     }
-    const LAllocation *tempFloat() {
-        return getTemp(1)->output();
+    const LDefinition *tempFloat() {
+        return getTemp(1);
     }
-    const LAllocation *tempPointer() {
+    const LDefinition *tempPointer() {
         return nullptr;
     }
 };
 
 class LGuardShape : public LInstructionHelper<0, 1, 1>
 {
   public:
     LIR_HEADER(GuardShape);
 
     LGuardShape(const LAllocation &in, const LDefinition &temp) {
         setOperand(0, in);
         setTemp(0, temp);
     }
     const MGuardShape *mir() const {
         return mir_->toGuardShape();
     }
-    const LAllocation *tempInt() {
-        return getTemp(0)->output();
+    const LDefinition *tempInt() {
+        return getTemp(0);
     }
 };
 
 class LGuardObjectType : public LInstructionHelper<0, 1, 1>
 {
   public:
     LIR_HEADER(GuardObjectType);
 
     LGuardObjectType(const LAllocation &in, const LDefinition &temp) {
         setOperand(0, in);
         setTemp(0, temp);
     }
     const MGuardObjectType *mir() const {
         return mir_->toGuardObjectType();
     }
-    const LAllocation *tempInt() {
-        return getTemp(0)->output();
+    const LDefinition *tempInt() {
+        return getTemp(0);
     }
 };
 
 class LInterruptCheck : public LInstructionHelper<0, 0, 0>
 {
   public:
     LIR_HEADER(InterruptCheck);
 };
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -1157,17 +1157,17 @@ class AssemblerX86Shared
         masm.pusha();
     }
     void popAllRegs() {
         masm.popa();
     }
 #endif
 
     // Zero-extend byte to 32-bit integer.
-    void movzxbl(const Register &src, const Register &dest) {
+    void movzbl(const Register &src, const Register &dest) {
         masm.movzbl_rr(src.code(), dest.code());
     }
 
     void cdq() {
         masm.cdq();
     }
     void idiv(Register divisor) {
         masm.idivl_r(divisor.code());
--- a/js/src/jit/shared/CodeGenerator-shared-inl.h
+++ b/js/src/jit/shared/CodeGenerator-shared-inl.h
@@ -56,19 +56,19 @@ ToTempRegisterOrInvalid(const LDefinitio
 
 static inline Register
 ToTempUnboxRegister(const LDefinition *def)
 {
     return ToTempRegisterOrInvalid(def);
 }
 
 static inline Register
-ToRegisterOrInvalid(const LAllocation *a)
+ToRegisterOrInvalid(const LDefinition *a)
 {
-    return a ? ToRegister(*a) : InvalidReg;
+    return a ? ToRegister(a) : InvalidReg;
 }
 
 static inline FloatRegister
 ToFloatRegister(const LAllocation &a)
 {
     JS_ASSERT(a.isFloatReg());
     return a.toFloatReg()->reg();
 }
--- a/js/src/jit/shared/LIR-x86-shared.h
+++ b/js/src/jit/shared/LIR-x86-shared.h
@@ -190,21 +190,21 @@ class LTableSwitch : public LInstruction
 
     MTableSwitch *mir() const {
         return mir_->toTableSwitch();
     }
 
     const LAllocation *index() {
         return getOperand(0);
     }
-    const LAllocation *tempInt() {
-        return getTemp(0)->output();
+    const LDefinition *tempInt() {
+        return getTemp(0);
     }
-    const LAllocation *tempPointer() {
-        return getTemp(1)->output();
+    const LDefinition *tempPointer() {
+        return getTemp(1);
     }
 };
 
 // Takes a tableswitch with a value to decide
 class LTableSwitchV : public LInstructionHelper<0, BOX_PIECES, 3>
 {
   public:
     LIR_HEADER(TableSwitchV)
@@ -219,24 +219,24 @@ class LTableSwitchV : public LInstructio
     }
 
     MTableSwitch *mir() const {
         return mir_->toTableSwitch();
     }
 
     static const size_t InputValue = 0;
 
-    const LAllocation *tempInt() {
-        return getTemp(0)->output();
+    const LDefinition *tempInt() {
+        return getTemp(0);
     }
-    const LAllocation *tempFloat() {
-        return getTemp(1)->output();
+    const LDefinition *tempFloat() {
+        return getTemp(1);
     }
-    const LAllocation *tempPointer() {
-        return getTemp(2)->output();
+    const LDefinition *tempPointer() {
+        return getTemp(2);
     }
 };
 
 class LGuardShape : public LInstructionHelper<0, 1, 0>
 {
   public:
     LIR_HEADER(GuardShape)
 
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -564,26 +564,26 @@ class MacroAssemblerX86Shared : public A
             return true;
         }
         return false;
     }
 
     void convertBoolToInt32(Register source, Register dest) {
         // Note that C++ bool is only 1 byte, so zero extend it to clear the
         // higher-order bits.
-        movzxbl(source, dest);
+        movzbl(source, dest);
     }
 
     void emitSet(Assembler::Condition cond, const Register &dest,
                  Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond) {
         if (GeneralRegisterSet(Registers::SingleByteRegs).has(dest)) {
             // If the register we're defining is a single byte register,
             // take advantage of the setCC instruction
             setCC(cond, dest);
-            movzxbl(dest, dest);
+            movzbl(dest, dest);
 
             if (ifNaN != Assembler::NaN_HandledByCond) {
                 Label noNaN;
                 j(Assembler::NoParity, &noNaN);
                 mov(ImmWord(ifNaN == Assembler::NaN_IsTrue), dest);
                 bind(&noNaN);
             }
         } else {
--- a/js/src/jit/x86/BaselineIC-x86.cpp
+++ b/js/src/jit/x86/BaselineIC-x86.cpp
@@ -25,17 +25,17 @@ ICCompare_Int32::Compiler::generateStubC
     Label failure;
     masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
     masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
 
     // Compare payload regs of R0 and R1.
     Assembler::Condition cond = JSOpToCondition(op, /* signed = */true);
     masm.cmpl(R0.payloadReg(), R1.payloadReg());
     masm.setCC(cond, R0.payloadReg());
-    masm.movzxbl(R0.payloadReg(), R0.payloadReg());
+    masm.movzbl(R0.payloadReg(), R0.payloadReg());
 
     // Box the result and return
     masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.payloadReg(), R0);
     EmitReturnFromIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -680,17 +680,17 @@ IonRuntime::generateVMWrapper(JSContext 
 
       case Type_Int32:
       case Type_Pointer:
         masm.Pop(ReturnReg);
         break;
 
       case Type_Bool:
         masm.Pop(ReturnReg);
-        masm.movzxbl(ReturnReg, ReturnReg);
+        masm.movzbl(ReturnReg, ReturnReg);
         break;
 
       case Type_Double:
         if (cx->runtime()->jitSupportsFloatingPoint)
             masm.Pop(ReturnFloatReg);
         else
             masm.breakpoint();
         break;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -394,102 +394,132 @@ array_length_setter(JSContext *cx, Handl
     if (!obj->is<ArrayObject>()) {
         return JSObject::defineProperty(cx, obj, cx->names().length, vp,
                                         nullptr, nullptr, JSPROP_ENUMERATE);
     }
 
     Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
     MOZ_ASSERT(arr->lengthIsWritable(),
                "setter shouldn't be called if property is non-writable");
-    return ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, strict);
+    return ArraySetLength<SequentialExecution>(cx, arr, id, JSPROP_PERMANENT, vp, strict);
 }
 
 struct ReverseIndexComparator
 {
     bool operator()(const uint32_t& a, const uint32_t& b, bool *lessOrEqualp) {
         MOZ_ASSERT(a != b, "how'd we get duplicate indexes?");
         *lessOrEqualp = b <= a;
         return true;
     }
 };
 
+template <ExecutionMode mode>
 bool
-js::CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *newLen)
+js::CanonicalizeArrayLengthValue(typename ExecutionModeTraits<mode>::ContextType cx,
+                                 HandleValue v, uint32_t *newLen)
 {
-    if (!ToUint32(cx, v, newLen))
-        return false;
-
     double d;
-    if (!ToNumber(cx, v, &d))
-        return false;
+
+    if (mode == ParallelExecution) {
+        if (v.isObject())
+            return false;
+
+        if (!NonObjectToUint32(cx, v, newLen))
+            return false;
+
+        if (!NonObjectToNumber(cx, v, &d))
+            return false;
+    } else {
+        if (!ToUint32(cx->asJSContext(), v, newLen))
+            return false;
+
+        if (!ToNumber(cx->asJSContext(), v, &d))
+            return false;
+    }
+
     if (d == *newLen)
         return true;
 
     if (cx->isJSContext())
         JS_ReportErrorNumber(cx->asJSContext(), js_GetErrorMessage, nullptr,
                              JSMSG_BAD_ARRAY_LENGTH);
     return false;
 }
 
+template bool
+js::CanonicalizeArrayLengthValue<SequentialExecution>(JSContext *cx,
+                                                      HandleValue v, uint32_t *newLen);
+template bool
+js::CanonicalizeArrayLengthValue<ParallelExecution>(ForkJoinSlice *slice,
+                                                    HandleValue v, uint32_t *newLen);
+
 /* ES6 20130308 draft 8.4.2.4 ArraySetLength */
+template <ExecutionMode mode>
 bool
-js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id, unsigned attrs,
-                   HandleValue value, bool setterIsStrict)
+js::ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cxArg,
+                   Handle<ArrayObject*> arr, HandleId id,
+                   unsigned attrs, HandleValue value, bool setterIsStrict)
 {
-    MOZ_ASSERT(id == NameToId(cx->names().length));
+    MOZ_ASSERT(cxArg->isThreadLocal(arr));
+    MOZ_ASSERT(id == NameToId(cxArg->names().length));
 
     /* Steps 1-2 are irrelevant in our implementation. */
 
     /* Steps 3-5. */
     uint32_t newLen;
-    if (!CanonicalizeArrayLengthValue(cx, value, &newLen))
+    if (!CanonicalizeArrayLengthValue<mode>(cxArg, value, &newLen))
         return false;
 
     // Abort if we're being asked to change enumerability or configurability.
     // (The length property of arrays is non-configurable, so such attempts
     // must fail.)  This behavior is spread throughout the ArraySetLength spec
     // algorithm, but we only need check it once as our array implementation
     // is internally so different from the spec algorithm.  (ES5 and ES6 define
     // behavior by delegating to the default define-own-property algorithm --
     // OrdinaryDefineOwnProperty in ES6, the default [[DefineOwnProperty]] in
     // ES5 -- but we reimplement all the conflict-detection bits ourselves here
     // so that we can use a customized length representation.)
     if (!(attrs & JSPROP_PERMANENT) || (attrs & JSPROP_ENUMERATE)) {
         if (!setterIsStrict)
             return true;
-        return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
+        // Bail for strict mode in parallel execution, as we need to go back
+        // to sequential mode to throw the error.
+        if (mode == ParallelExecution)
+            return false;
+        return Throw(cxArg->asJSContext(), id, JSMSG_CANT_REDEFINE_PROP);
     }
 
     /* Steps 6-7. */
     bool lengthIsWritable = arr->lengthIsWritable();
 #ifdef DEBUG
     {
-        RootedShape lengthShape(cx, arr->nativeLookup(cx, id));
+        RootedShape lengthShape(cxArg, arr->nativeLookupPure(id));
         MOZ_ASSERT(lengthShape);
         MOZ_ASSERT(lengthShape->writable() == lengthIsWritable);
     }
 #endif
 
     uint32_t oldLen = arr->length();
 
     /* Steps 8-9 for arrays with non-writable length. */
     if (!lengthIsWritable) {
         if (newLen == oldLen)
             return true;
 
-        if (!cx->isJSContext())
+        if (!cxArg->isJSContext())
             return false;
 
         if (setterIsStrict) {
-            return JS_ReportErrorFlagsAndNumber(cx->asJSContext(),
+            return JS_ReportErrorFlagsAndNumber(cxArg->asJSContext(),
                                                 JSREPORT_ERROR, js_GetErrorMessage, nullptr,
                                                 JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
         }
 
-        return JSObject::reportReadOnly(cx->asJSContext(), id, JSREPORT_STRICT | JSREPORT_WARNING);
+        return JSObject::reportReadOnly(cxArg->asJSContext(), id,
+                                        JSREPORT_STRICT | JSREPORT_WARNING);
     }
 
     /* Step 8. */
     bool succeeded = true;
     do {
         // The initialized length and capacity of an array only need updating
         // when non-hole elements are added or removed, which doesn't happen
         // when array length stays the same or increases.
@@ -507,24 +537,31 @@ js::ArraySetLength(JSContext *cx, Handle
         // separate from non-indexed storage.
         if (!arr->isIndexed()) {
             uint32_t oldCapacity = arr->getDenseCapacity();
             uint32_t oldInitializedLength = arr->getDenseInitializedLength();
             MOZ_ASSERT(oldCapacity >= oldInitializedLength);
             if (oldInitializedLength > newLen)
                 arr->setDenseInitializedLength(newLen);
             if (oldCapacity > newLen)
-                arr->shrinkElements(cx, newLen);
+                arr->shrinkElements(cxArg, newLen);
 
             // We've done the work of deleting any dense elements needing
             // deletion, and there are no sparse elements.  Thus we can skip
             // straight to defining the length.
             break;
         }
 
+        // Bail from parallel execution if need to perform step 15, which is
+        // unsafe and isn't a common case.
+        if (mode == ParallelExecution)
+            return false;
+
+        JSContext *cx = cxArg->asJSContext();
+
         // Step 15.
         //
         // Attempt to delete all elements above the new length, from greatest
         // to least.  If any of these deletions fails, we're supposed to define
         // the length to one greater than the index that couldn't be deleted,
         // *with the property attributes specified*.  This might convert the
         // length to be not the value specified, yet non-writable.  (You may be
         // forgiven for thinking these are interesting semantics.)  Example:
@@ -623,27 +660,39 @@ js::ArraySetLength(JSContext *cx, Handle
     } while (false);
 
     /* Steps 12, 16. */
 
     // Yes, we totally drop a non-stub getter/setter from a defineProperty
     // API call on the floor here.  Given that getter/setter will go away in
     // the long run, with accessors replacing them both internally and at the
     // API level, just run with this.
-    RootedShape lengthShape(cx, arr->nativeLookup(cx, id));
-    if (!JSObject::changeProperty(cx, arr, lengthShape, attrs,
-                                  JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED,
-                                  array_length_getter, array_length_setter))
+    RootedShape lengthShape(cxArg, mode == ParallelExecution
+                            ? arr->nativeLookupPure(id)
+                            : arr->nativeLookup(cxArg->asJSContext(), id));
+    if (!JSObject::changeProperty<mode>(cxArg, arr, lengthShape, attrs,
+                                        JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED,
+                                        array_length_getter, array_length_setter))
     {
         return false;
     }
 
-    RootedValue v(cx, NumberValue(newLen));
-    AddTypePropertyId(cx, arr, id, v);
-    ArrayObject::setLength(cx, arr, newLen);
+    RootedValue v(cxArg, NumberValue(newLen));
+    if (mode == ParallelExecution) {
+        // Adding the property type or overflowing int32 requires changing TI
+        // state.
+        if (!HasTypePropertyId(arr, id, v) || newLen > INT32_MAX)
+            return false;
+        arr->setLengthInt32(newLen);
+    } else {
+        JSContext *cx = cxArg->asJSContext();
+        AddTypePropertyId(cx, arr, id, v);
+        ArrayObject::setLength(cx, arr, newLen);
+    }
+
 
     // All operations past here until the |!succeeded| code must be infallible,
     // so that all element fields remain properly synchronized.
 
     // Trim the initialized length, if needed, to preserve the <= length
     // invariant.  (Capacity was already reduced during element deletion, if
     // necessary.)
     ObjectElements *header = arr->getElementsHeader();
@@ -654,33 +703,45 @@ js::ArraySetLength(JSContext *cx, Handle
 
         // When an array's length becomes non-writable, writes to indexes
         // greater than or equal to the length don't change the array.  We
         // handle this with a check for non-writable length in most places.
         // But in JIT code every check counts -- so we piggyback the check on
         // the already-required range check for |index < capacity| by making
         // capacity of arrays with non-writable length never exceed the length.
         if (arr->getDenseCapacity() > newLen) {
-            arr->shrinkElements(cx, newLen);
+            arr->shrinkElements(cxArg, newLen);
             arr->getElementsHeader()->capacity = newLen;
         }
     }
 
     if (setterIsStrict && !succeeded) {
+        // We can't have arrived here under ParallelExecution, as we have
+        // returned from the function before step 15 above.
+        JSContext *cx = cxArg->asJSContext();
         RootedId elementId(cx);
         if (!IndexToId(cx, newLen - 1, &elementId))
             return false;
         return arr->reportNotConfigurable(cx, elementId);
     }
 
     return true;
 }
 
+template bool
+js::ArraySetLength<SequentialExecution>(JSContext *cx, Handle<ArrayObject*> arr,
+                                        HandleId id, unsigned attrs, HandleValue value,
+                                        bool setterIsStrict);
+template bool
+js::ArraySetLength<ParallelExecution>(ForkJoinSlice *slice, Handle<ArrayObject*> arr,
+                                      HandleId id, unsigned attrs, HandleValue value,
+                                      bool setterIsStrict);
+
 bool
-js::WouldDefinePastNonwritableLength(ExclusiveContext *cx,
+js::WouldDefinePastNonwritableLength(ThreadSafeContext *cx,
                                      HandleObject obj, uint32_t index, bool strict,
                                      bool *definesPast)
 {
     if (!obj->is<ArrayObject>()) {
         *definesPast = false;
         return true;
     }
 
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -71,26 +71,30 @@ NewDenseCopiedArray(JSContext *cx, uint3
                     NewObjectKind newKind = GenericObject);
 
 /*
  * Determines whether a write to the given element on |obj| should fail because
  * |obj| is an Array with a non-writable length, and writing that element would
  * increase the length of the array.
  */
 extern bool
-WouldDefinePastNonwritableLength(ExclusiveContext *cx,
+WouldDefinePastNonwritableLength(ThreadSafeContext *cx,
                                  HandleObject obj, uint32_t index, bool strict,
                                  bool *definesPast);
 
 /*
  * Canonicalize |vp| to a uint32_t value potentially suitable for use as an
  * array length.
+ *
+ * For parallel execution we can only canonicalize non-object values.
  */
+template <ExecutionMode mode>
 extern bool
-CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *canonicalized);
+CanonicalizeArrayLengthValue(typename ExecutionModeTraits<mode>::ContextType cx,
+                             HandleValue v, uint32_t *canonicalized);
 
 extern bool
 GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp);
 
 extern bool
 SetLengthProperty(JSContext *cx, HandleObject obj, double length);
 
 extern bool
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -135,16 +135,23 @@ namespace frontend { struct CompileError
  *
  * Contexts which are a ThreadSafeContext but not an ExclusiveContext are used
  * to represent a ForkJoinSlice, the per-thread parallel context used in PJS.
  */
 
 struct ThreadSafeContext : ContextFriendFields,
                            public MallocProvider<ThreadSafeContext>
 {
+    friend struct StackBaseShape;
+    friend UnownedBaseShape *BaseShape::lookupUnowned(ThreadSafeContext *cx,
+                                                      const StackBaseShape &base);
+    friend Shape *JSObject::lookupChildProperty(ThreadSafeContext *cx,
+                                                JS::HandleObject obj, js::HandleShape parent,
+                                                js::StackShape &child);
+
   public:
     enum ContextKind {
         Context_JS,
         Context_Exclusive,
         Context_ForkJoin
     };
 
   private:
@@ -235,24 +242,27 @@ struct ThreadSafeContext : ContextFriend
 
     inline Allocator *const allocator();
 
     // Allocations can only trigger GC when running on the main thread.
     inline AllowGC allowGC() const { return isJSContext() ? CanGC : NoGC; }
 
     template <typename T>
     bool isInsideCurrentZone(T thing) const {
-        return thing->isInsideZone(zone_);
+        return thing->zoneFromAnyThread() == zone_;
     }
 
     template <typename T>
     inline bool isInsideCurrentCompartment(T thing) const {
         return thing->compartment() == compartment_;
     }
 
+    template <typename T>
+    inline bool isThreadLocal(T thing) const;
+
     void *onOutOfMemory(void *p, size_t nbytes) {
         return runtime_->onOutOfMemory(p, nbytes, maybeJSContext());
     }
 
     inline void updateMallocCounter(size_t nbytes) {
         // Note: this is racy.
         runtime_->updateMallocCounter(zone_, nbytes);
     }
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -128,74 +128,76 @@ class CompartmentChecker
 };
 #endif /* JS_CRASH_DIAGNOSTICS */
 
 /*
  * Don't perform these checks when called from a finalizer. The checking
  * depends on other objects not having been swept yet.
  */
 #define START_ASSERT_SAME_COMPARTMENT()                                       \
+    if (!cx->isExclusiveContext())                                            \
+        return;                                                               \
     if (cx->isHeapBusy())                                                     \
         return;                                                               \
-    CompartmentChecker c(cx)
+    CompartmentChecker c(cx->asExclusiveContext())
 
 template <class T1> inline void
-assertSameCompartment(ExclusiveContext *cx, const T1 &t1)
+assertSameCompartment(ThreadSafeContext *cx, const T1 &t1)
 {
 #ifdef JS_CRASH_DIAGNOSTICS
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
 #endif
 }
 
 template <class T1> inline void
-assertSameCompartmentDebugOnly(ExclusiveContext *cx, const T1 &t1)
+assertSameCompartmentDebugOnly(ThreadSafeContext *cx, const T1 &t1)
 {
 #ifdef DEBUG
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
 #endif
 }
 
 template <class T1, class T2> inline void
-assertSameCompartment(ExclusiveContext *cx, const T1 &t1, const T2 &t2)
+assertSameCompartment(ThreadSafeContext *cx, const T1 &t1, const T2 &t2)
 {
 #ifdef JS_CRASH_DIAGNOSTICS
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
     c.check(t2);
 #endif
 }
 
 template <class T1, class T2, class T3> inline void
-assertSameCompartment(ExclusiveContext *cx, const T1 &t1, const T2 &t2, const T3 &t3)
+assertSameCompartment(ThreadSafeContext *cx, const T1 &t1, const T2 &t2, const T3 &t3)
 {
 #ifdef JS_CRASH_DIAGNOSTICS
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
     c.check(t2);
     c.check(t3);
 #endif
 }
 
 template <class T1, class T2, class T3, class T4> inline void
-assertSameCompartment(ExclusiveContext *cx,
+assertSameCompartment(ThreadSafeContext *cx,
                       const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4)
 {
 #ifdef JS_CRASH_DIAGNOSTICS
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
     c.check(t2);
     c.check(t3);
     c.check(t4);
 #endif
 }
 
 template <class T1, class T2, class T3, class T4, class T5> inline void
-assertSameCompartment(ExclusiveContext *cx,
+assertSameCompartment(ThreadSafeContext *cx,
                       const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5)
 {
 #ifdef JS_CRASH_DIAGNOSTICS
     START_ASSERT_SAME_COMPARTMENT();
     c.check(t1);
     c.check(t2);
     c.check(t3);
     c.check(t4);
@@ -556,9 +558,15 @@ JSNativeThreadSafeWrapper(JSContext *cx,
 
 template <JSThreadSafeNative threadSafeNative>
 inline js::ParallelResult
 JSParallelNativeThreadSafeWrapper(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp)
 {
     return threadSafeNative(slice, argc, vp) ? js::TP_SUCCESS : js::TP_FATAL;
 }
 
+/* static */ inline JSContext *
+js::ExecutionModeTraits<js::SequentialExecution>::toContextType(ExclusiveContext *cx)
+{
+    return cx->asJSContext();
+}
+
 #endif /* jscntxtinlines_h */
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -44,16 +44,37 @@ struct AutoMarkInDeadZone
 
 inline Allocator *const
 ThreadSafeContext::allocator()
 {
     JS_ASSERT_IF(isJSContext(), &asJSContext()->zone()->allocator == allocator_);
     return allocator_;
 }
 
+template <typename T>
+inline bool
+ThreadSafeContext::isThreadLocal(T thing) const
+{
+    if (!isForkJoinSlice())
+        return true;
+
+    if (!IsInsideNursery(runtime_, thing) &&
+        allocator_->arenas.containsArena(runtime_, thing->arenaHeader()))
+    {
+        // GC should be suppressed in preparation for mutating thread local
+        // objects, as we don't want to trip any barriers.
+        JS_ASSERT(!thing->zoneFromAnyThread()->needsBarrier());
+        JS_ASSERT(!thing->runtimeFromAnyThread()->needsBarrier());
+
+        return true;
+    }
+
+    return false;
+}
+
 namespace gc {
 
 static inline AllocKind
 GetGCObjectKind(const Class *clasp)
 {
     if (clasp == FunctionClassPtr)
         return JSFunction::FinalizeKind;
     uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -254,17 +254,17 @@ types::TypeHasProperty(JSContext *cx, Ty
 
         AutoEnterAnalysis enter(cx);
 
         /*
          * We don't track types for properties inherited from prototypes which
          * haven't yet been accessed during analysis of the inheriting object.
          * Don't do the property instantiation now.
          */
-        TypeSet *types = obj->maybeGetProperty(cx, id);
+        TypeSet *types = obj->maybeGetProperty(id);
         if (!types)
             return true;
 
         if (!types->hasType(type)) {
             TypeFailure(cx, "Missing type in object %s %s: %s",
                         TypeObjectString(obj), TypeIdString(id), TypeString(type));
         }
     }
@@ -705,17 +705,17 @@ TypeObjectKey::property(jsid id)
         MOZ_CRASH();
     return property;
 #else
     MOZ_CRASH();
 #endif
 }
 
 bool
-types::FinishCompilation(JSContext *cx, JSScript *script, jit::ExecutionMode executionMode,
+types::FinishCompilation(JSContext *cx, JSScript *script, ExecutionMode executionMode,
                          CompilerConstraintList *constraints, RecompileInfo *precompileInfo)
 {
     if (constraints->failed())
         return false;
 
     CompilerOutput co(script, executionMode);
 
     TypeCompartment &types = cx->compartment()->types;
@@ -1004,17 +1004,17 @@ TemporaryTypeSet::hasObjectFlags(Compile
 
 static inline void
 ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnknown, bool force)
 {
     if (object->unknownProperties())
         return;
 
     /* All constraints listening to state changes are on the empty id. */
-    TypeSet *types = object->maybeGetProperty(cxArg, JSID_EMPTY);
+    TypeSet *types = object->maybeGetProperty(JSID_EMPTY);
 
     /* Mark as unknown after getting the types, to avoid assertion. */
     if (markingUnknown)
         object->flags |= OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES;
 
     if (types) {
         if (JSContext *cx = cxArg->maybeJSContext()) {
             TypeConstraint *constraint = types->constraintList;
@@ -2512,24 +2512,33 @@ TypeObject::markPropertyConfigured(Exclu
 
     id = IdToTypeId(id);
 
     TypeSet *types = getProperty(cx, id);
     if (types)
         types->setConfiguredProperty(cx);
 }
 
+bool
+TypeObject::isPropertyConfigured(jsid id)
+{
+    TypeSet *types = maybeGetProperty(id);
+    if (types)
+        return types->configuredProperty();
+    return false;
+}
+
 void
 TypeObject::markStateChange(ExclusiveContext *cxArg)
 {
     if (unknownProperties())
         return;
 
     AutoEnterAnalysis enter(cxArg);
-    TypeSet *types = maybeGetProperty(cxArg, JSID_EMPTY);
+    TypeSet *types = maybeGetProperty(JSID_EMPTY);
     if (types) {
         if (JSContext *cx = cxArg->maybeJSContext()) {
             TypeConstraint *constraint = types->constraintList;
             while (constraint) {
                 constraint->newObjectState(cx, this, true);
                 constraint = constraint->next;
             }
         } else {
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -97,32 +97,81 @@ class RootedBase<TaggedProto> : public T
     friend class TaggedProtoOperations<Rooted<TaggedProto> >;
     const TaggedProto *extract() const {
         return static_cast<const Rooted<TaggedProto> *>(this)->address();
     }
 };
 
 class CallObject;
 
+/*
+ * Execution Mode Overview
+ *
+ * JavaScript code can execute either sequentially or in parallel, such as in
+ * PJS. Functions which behave identically in either execution mode can take a
+ * ThreadSafeContext, and functions which have similar but not identical
+ * behavior between execution modes can be templated on the mode. Such
+ * functions use a context parameter type from ExecutionModeTraits below
+ * indicating whether they are only permitted constrained operations (such as
+ * thread safety, and side effects limited to being thread-local), or whether
+ * they can have arbitrary side effects.
+ */
+
+enum ExecutionMode {
+    /* Normal JavaScript execution. */
+    SequentialExecution,
+
+    /*
+     * JavaScript code to be executed in parallel worker threads in PJS in a
+     * fork join fashion.
+     */
+    ParallelExecution,
+
+    /*
+     * Modes after this point are internal and are not counted in
+     * NumExecutionModes below.
+     */
+
+    /*
+     * MIR analysis performed when invoking 'new' on a script, to determine
+     * definite properties. Used by the optimizing JIT.
+     */
+    DefinitePropertiesAnalysis
+};
+
+/*
+ * Not as part of the enum so we don't get warnings about unhandled enum
+ * values.
+ */
+static const unsigned NumExecutionModes = ParallelExecution + 1;
+
+template <ExecutionMode mode>
+struct ExecutionModeTraits
+{
+};
+
+template <> struct ExecutionModeTraits<SequentialExecution>
+{
+    typedef JSContext * ContextType;
+    typedef ExclusiveContext * ExclusiveContextType;
+
+    static inline JSContext *toContextType(ExclusiveContext *cx);
+};
+
+template <> struct ExecutionModeTraits<ParallelExecution>
+{
+    typedef ForkJoinSlice * ContextType;
+    typedef ForkJoinSlice * ExclusiveContextType;
+
+    static inline ForkJoinSlice *toContextType(ForkJoinSlice *cx) { return cx; }
+};
+
 namespace jit {
     struct IonScript;
     class IonAllocPolicy;
-
-    enum ExecutionMode {
-        // Normal JavaScript execution
-        SequentialExecution,
-
-        // JavaScript code to be executed in parallel worker threads,
-        // e.g. by ParallelArray
-        ParallelExecution,
-
-        // MIR analysis performed when invoking 'new' on a script, to determine
-        // definite properties
-        DefinitePropertiesAnalysis
-    };
 }
 
 namespace analyze {
     class ScriptAnalysis;
 }
 
 namespace types {
 
@@ -955,17 +1004,17 @@ struct TypeObject : gc::BarrieredCell<Ty
 
     /*
      * Get or create a property of this object. Only call this for properties which
      * a script accesses explicitly.
      */
     inline HeapTypeSet *getProperty(ExclusiveContext *cx, jsid id);
 
     /* Get a property only if it already exists. */
-    inline HeapTypeSet *maybeGetProperty(ExclusiveContext *cx, jsid id);
+    inline HeapTypeSet *maybeGetProperty(jsid id);
 
     inline unsigned getPropertyCount();
     inline Property *getProperty(unsigned i);
 
     /* Tenure counter management. */
 
     /*
      * When an object allocation site generates objects that are long lived
@@ -1010,16 +1059,17 @@ struct TypeObject : gc::BarrieredCell<Ty
     void addPropertyType(ExclusiveContext *cx, const char *name, const Value &value);
     void markPropertyConfigured(ExclusiveContext *cx, jsid id);
     void markStateChange(ExclusiveContext *cx);
     void setFlags(ExclusiveContext *cx, TypeObjectFlags flags);
     void markUnknown(ExclusiveContext *cx);
     void clearAddendum(ExclusiveContext *cx);
     void clearNewScriptAddendum(ExclusiveContext *cx);
     void clearTypedObjectAddendum(ExclusiveContext *cx);
+    bool isPropertyConfigured(jsid id);
 
     void print();
 
     inline void clearProperties();
     inline void sweep(FreeOp *fop);
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
@@ -1230,32 +1280,32 @@ class HeapTypeSetKey
  * indirection enables the invalidation of all constraints related to the same
  * compilation.
  */
 class CompilerOutput
 {
     // If this compilation has not been invalidated, the associated script and
     // kind of compilation being performed.
     JSScript *script_;
-    unsigned mode_ : 2;
+    ExecutionMode mode_ : 2;
 
     // Whether this compilation is about to be invalidated.
     bool pendingInvalidation_ : 1;
 
   public:
     CompilerOutput()
-      : script_(nullptr), mode_(0), pendingInvalidation_(false)
+      : script_(nullptr), mode_(SequentialExecution), pendingInvalidation_(false)
     {}
 
-    CompilerOutput(JSScript *script, jit::ExecutionMode mode)
+    CompilerOutput(JSScript *script, ExecutionMode mode)
       : script_(script), mode_(mode), pendingInvalidation_(false)
     {}
 
     JSScript *script() const { return script_; }
-    inline jit::ExecutionMode mode() const { return static_cast<jit::ExecutionMode>(mode_); }
+    inline ExecutionMode mode() const { return mode_; }
 
     inline jit::IonScript *ion() const;
 
     bool isValid() const {
         return script_ != nullptr;
     }
     void invalidate() {
         script_ = nullptr;
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -408,17 +408,17 @@ TypeMonitorCall(JSContext *cx, const js:
 }
 
 inline bool
 TrackPropertyTypes(ExclusiveContext *cx, JSObject *obj, jsid id)
 {
     if (!cx->typeInferenceEnabled() || obj->hasLazyType() || obj->type()->unknownProperties())
         return false;
 
-    if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(cx, id))
+    if (obj->hasSingletonType() && !obj->type()->maybeGetProperty(id))
         return false;
 
     return true;
 }
 
 inline void
 EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
 {
@@ -432,16 +432,37 @@ EnsureTrackPropertyTypes(JSContext *cx, 
     if (obj->hasSingletonType()) {
         AutoEnterAnalysis enter(cx);
         obj->type()->getProperty(cx, id);
     }
 
     JS_ASSERT(obj->type()->unknownProperties() || TrackPropertyTypes(cx, obj, id));
 }
 
+inline bool
+HasTypePropertyId(JSObject *obj, jsid id, Type type)
+{
+    if (obj->hasLazyType())
+        return true;
+
+    if (obj->type()->unknownProperties())
+        return true;
+
+    if (HeapTypeSet *types = obj->type()->maybeGetProperty(IdToTypeId(id)))
+        return types->hasType(type);
+
+    return false;
+}
+
+inline bool
+HasTypePropertyId(JSObject *obj, jsid id, const Value &value)
+{
+    return HasTypePropertyId(obj, id, GetValueType(value));
+}
+
 /* Add a possible type for a property of obj. */
 inline void
 AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, Type type)
 {
     if (cx->typeInferenceEnabled()) {
         id = IdToTypeId(id);
         if (TrackPropertyTypes(cx, obj, id))
             obj->type()->addPropertyType(cx, id, type);
@@ -507,16 +528,22 @@ MarkTypePropertyConfigured(ExclusiveCont
 {
     if (cx->typeInferenceEnabled()) {
         id = IdToTypeId(id);
         if (TrackPropertyTypes(cx, obj, id))
             obj->type()->markPropertyConfigured(cx, id);
     }
 }
 
+inline bool
+IsTypePropertyIdMarkedConfigured(JSObject *obj, jsid id)
+{
+    return obj->type()->isPropertyConfigured(id);
+}
+
 /* Mark a state change on a particular object. */
 inline void
 MarkObjectStateChange(ExclusiveContext *cx, JSObject *obj)
 {
     if (cx->typeInferenceEnabled() && !obj->hasLazyType() && !obj->type()->unknownProperties())
         obj->type()->markStateChange(cx);
 }
 
@@ -1323,17 +1350,17 @@ TypeObject::getProperty(ExclusiveContext
             MOZ_ASSUME_UNREACHABLE("Missing property");
         }
     }
 
     return &(*pprop)->types;
 }
 
 inline HeapTypeSet *
-TypeObject::maybeGetProperty(ExclusiveContext *cx, jsid id)
+TypeObject::maybeGetProperty(jsid id)
 {
     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
     JS_ASSERT(!unknownProperties());
 
     Property *prop = HashSetLookup<jsid,Property,Property>
         (propertySet, basePropertyCount(), id);
 
@@ -1379,29 +1406,29 @@ TypeObjectAddendum::writeBarrierPre(Type
 
 inline void
 TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
 {
 #ifdef JSGC_INCREMENTAL
     if (!newScript || !newScript->fun->runtimeFromAnyThread()->needsBarrier())
         return;
 
-    JS::Zone *zone = newScript->fun->zone();
+    JS::Zone *zone = newScript->fun->zoneFromAnyThread();
     if (zone->needsBarrier()) {
         MarkObject(zone->barrierTracer(), &newScript->fun, "write barrier");
         MarkShape(zone->barrierTracer(), &newScript->shape, "write barrier");
     }
 #endif
 }
 
 // Allocate a CompilerOutput for a finished compilation and generate the type
 // constraints for the compilation. Returns whether the type constraints
 // still hold.
 bool
-FinishCompilation(JSContext *cx, JSScript *script, jit::ExecutionMode executionMode,
+FinishCompilation(JSContext *cx, JSScript *script, ExecutionMode executionMode,
                   CompilerConstraintList *constraints, RecompileInfo *precompileInfo);
 
 class CompilerConstraint;
 class CompilerConstraintList
 {
 #ifdef JS_ION
     // Generated constraints.
     Vector<CompilerConstraint *, 0, jit::IonAllocPolicy> constraints;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -665,17 +665,17 @@ DefinePropertyOnObject(JSContext *cx, Ha
                 if (!shape->configurable() &&
                     (!shape->hasDefaultGetter() || !shape->hasDefaultSetter()) &&
                     desc.isDataDescriptor() &&
                     (desc.hasWritable() ? desc.writable() : shape->writable()))
                 {
                     return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, id, rval);
                 }
 
-                if (!js_NativeGet(cx, obj, obj2, shape, &v))
+                if (!NativeGet(cx, obj, obj2, shape, &v))
                     return false;
             }
 
             if (desc.isDataDescriptor()) {
                 if (!shapeDataDescriptor)
                     break;
 
                 bool same;
@@ -879,17 +879,17 @@ DefinePropertyOnArray(JSContext *cx, Han
         // But canonicalization may throw a RangeError (or other exception, if
         // the value is an object with user-defined conversion semantics)
         // before other attributes are checked.  So as long as our internal
         // defineProperty hook doesn't match the ECMA one, this duplicate
         // checking can't be helped.
         RootedValue v(cx);
         if (desc.hasValue()) {
             uint32_t newLen;
-            if (!CanonicalizeArrayLengthValue(cx, desc.value(), &newLen))
+            if (!CanonicalizeArrayLengthValue<SequentialExecution>(cx, desc.value(), &newLen))
                 return false;
             v.setNumber(newLen);
         } else {
             v.setNumber(arr->length());
         }
 
         if (desc.hasConfigurable() && desc.configurable())
             return Reject(cx, id, JSMSG_CANT_REDEFINE_PROP, throwError, rval);
@@ -903,17 +903,17 @@ DefinePropertyOnArray(JSContext *cx, Han
         if (!arr->lengthIsWritable()) {
             if (desc.hasWritable() && desc.writable())
                 return Reject(cx, id, JSMSG_CANT_REDEFINE_PROP, throwError, rval);
         } else {
             if (desc.hasWritable() && !desc.writable())
                 attrs = attrs | JSPROP_READONLY;
         }
 
-        return ArraySetLength(cx, arr, id, attrs, v, throwError);
+        return ArraySetLength<SequentialExecution>(cx, arr, id, attrs, v, throwError);
     }
 
     /* Step 3. */
     uint32_t index;
     if (js_IdIsIndex(id, &index)) {
         /* Step 3b. */
         uint32_t oldLen = arr->length();
 
@@ -2433,19 +2433,20 @@ js_InitClass(JSContext *cx, HandleObject
         return nullptr;
     }
 
     return DefineConstructorAndPrototype(cx, obj, key, atom, protoProto, clasp, constructor, nargs,
                                          ps, fs, static_ps, static_fs, ctorp, ctorKind);
 }
 
 /* static */ inline bool
-JSObject::updateSlotsForSpan(ExclusiveContext *cx,
+JSObject::updateSlotsForSpan(ThreadSafeContext *cx,
                              HandleObject obj, size_t oldSpan, size_t newSpan)
 {
+    JS_ASSERT(cx->isThreadLocal(obj));
     JS_ASSERT(oldSpan != newSpan);
 
     size_t oldCount = dynamicSlotsCount(obj->numFixedSlots(), oldSpan);
     size_t newCount = dynamicSlotsCount(obj->numFixedSlots(), newSpan);
 
     if (oldSpan < newSpan) {
         if (oldCount < newCount && !JSObject::growSlots(cx, obj, oldCount, newCount))
             return false;
@@ -2462,18 +2463,19 @@ JSObject::updateSlotsForSpan(ExclusiveCo
         if (oldCount > newCount)
             JSObject::shrinkSlots(cx, obj, oldCount, newCount);
     }
 
     return true;
 }
 
 /* static */ bool
-JSObject::setLastProperty(ExclusiveContext *cx, HandleObject obj, HandleShape shape)
+JSObject::setLastProperty(ThreadSafeContext *cx, HandleObject obj, HandleShape shape)
 {
+    JS_ASSERT(cx->isThreadLocal(obj));
     JS_ASSERT(!obj->inDictionaryMode());
     JS_ASSERT(!shape->inDictionary());
     JS_ASSERT(shape->compartment() == obj->compartment());
     JS_ASSERT(shape->numFixedSlots() == obj->numFixedSlots());
 
     size_t oldSpan = obj->lastProperty()->slotSpan();
     size_t newSpan = shape->slotSpan();
 
@@ -2485,59 +2487,61 @@ JSObject::setLastProperty(ExclusiveConte
     if (!updateSlotsForSpan(cx, obj, oldSpan, newSpan))
         return false;
 
     obj->shape_ = shape;
     return true;
 }
 
 /* static */ bool
-JSObject::setSlotSpan(ExclusiveContext *cx, HandleObject obj, uint32_t span)
+JSObject::setSlotSpan(ThreadSafeContext *cx, HandleObject obj, uint32_t span)
 {
+    JS_ASSERT(cx->isThreadLocal(obj));
     JS_ASSERT(obj->inDictionaryMode());
 
     size_t oldSpan = obj->lastProperty()->base()->slotSpan();
     if (oldSpan == span)
         return true;
 
     if (!JSObject::updateSlotsForSpan(cx, obj, oldSpan, span))
         return false;
 
     obj->lastProperty()->base()->setSlotSpan(span);
     return true;
 }
 
 static HeapSlot *
-AllocateSlots(ExclusiveContext *cx, JSObject *obj, uint32_t nslots)
+AllocateSlots(ThreadSafeContext *cx, JSObject *obj, uint32_t nslots)
 {
 #ifdef JSGC_GENERATIONAL
     if (cx->isJSContext())
         return cx->asJSContext()->runtime()->gcNursery.allocateSlots(cx->asJSContext(), obj, nslots);
 #endif
     return cx->pod_malloc<HeapSlot>(nslots);
 }
 
 static HeapSlot *
-ReallocateSlots(ExclusiveContext *cx, JSObject *obj, HeapSlot *oldSlots,
+ReallocateSlots(ThreadSafeContext *cx, JSObject *obj, HeapSlot *oldSlots,
                 uint32_t oldCount, uint32_t newCount)
 {
 #ifdef JSGC_GENERATIONAL
     if (cx->isJSContext()) {
         return cx->asJSContext()->runtime()->gcNursery.reallocateSlots(cx->asJSContext(),
                                                                        obj, oldSlots,
                                                                        oldCount, newCount);
     }
 #endif
     return (HeapSlot *)cx->realloc_(oldSlots, oldCount * sizeof(HeapSlot),
                                     newCount * sizeof(HeapSlot));
 }
 
 /* static */ bool
-JSObject::growSlots(ExclusiveContext *cx, HandleObject obj, uint32_t oldCount, uint32_t newCount)
+JSObject::growSlots(ThreadSafeContext *cx, HandleObject obj, uint32_t oldCount, uint32_t newCount)
 {
+    JS_ASSERT(cx->isThreadLocal(obj));
     JS_ASSERT(newCount > oldCount);
     JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
 
     /*
      * Slot capacities are determined by the span of allocated objects. Due to
      * the limited number of bits to store shape slots, object growth is
      * throttled well before the slot capacity can overflow.
      */
@@ -2578,62 +2582,53 @@ JSObject::growSlots(ExclusiveContext *cx
         Debug_SetSlotRangeToCrashOnTouch(obj->slots, newCount);
         return true;
     }
 
     HeapSlot *newslots = ReallocateSlots(cx, obj, obj->slots, oldCount, newCount);
     if (!newslots)
         return false;  /* Leave slots at its old size. */
 
-    bool changed = obj->slots != newslots;
     obj->slots = newslots;
 
     Debug_SetSlotRangeToCrashOnTouch(obj->slots + oldCount, newCount - oldCount);
 
-    /* Changes in the slots of global objects can trigger recompilation. */
-    if (changed && obj->is<GlobalObject>())
-        types::MarkObjectStateChange(cx, obj);
-
     return true;
 }
 
 static void
-FreeSlots(ExclusiveContext *cx, HeapSlot *slots)
+FreeSlots(ThreadSafeContext *cx, HeapSlot *slots)
 {
     // Note: threads without a JSContext do not have access to nursery allocated things.
 #ifdef JSGC_GENERATIONAL
     if (cx->isJSContext())
         return cx->asJSContext()->runtime()->gcNursery.freeSlots(cx->asJSContext(), slots);
 #endif
     js_free(slots);
 }
 
 /* static */ void
-JSObject::shrinkSlots(ExclusiveContext *cx, HandleObject obj, uint32_t oldCount, uint32_t newCount)
+JSObject::shrinkSlots(ThreadSafeContext *cx, HandleObject obj, uint32_t oldCount, uint32_t newCount)
 {
+    JS_ASSERT(cx->isThreadLocal(obj));
     JS_ASSERT(newCount < oldCount);
 
     if (newCount == 0) {
         FreeSlots(cx, obj->slots);
         obj->slots = nullptr;
         return;
     }
 
     JS_ASSERT(newCount >= SLOT_CAPACITY_MIN);
 
     HeapSlot *newslots = ReallocateSlots(cx, obj, obj->slots, oldCount, newCount);
     if (!newslots)
         return;  /* Leave slots at its old size. */
 
-    bool changed = obj->slots != newslots;
     obj->slots = newslots;
-
-    /* Watch for changes in global object slots, as for growSlots. */
-    if (changed && obj->is<GlobalObject>())
-        types::MarkObjectStateChange(cx, obj);
 }
 
 /* static */ bool
 JSObject::sparsifyDenseElement(ExclusiveContext *cx, HandleObject obj, uint32_t index)
 {
     RootedValue value(cx, obj->getDenseElement(index));
     JS_ASSERT(!value.isMagic(JS_ELEMENTS_HOLE));
 
@@ -2912,16 +2907,18 @@ JSObject::growElements(ThreadSafeContext
     Debug_SetSlotRangeToCrashOnTouch(elements + initlen, actualCapacity - initlen);
 
     return true;
 }
 
 void
 JSObject::shrinkElements(ThreadSafeContext *cx, uint32_t newcap)
 {
+    JS_ASSERT(cx->isThreadLocal(this));
+
     uint32_t oldcap = getDenseCapacity();
     JS_ASSERT(newcap <= oldcap);
 
     /* Don't shrink elements below the minimum capacity. */
     if (oldcap <= SLOT_CAPACITY_MIN || !hasDynamicElements())
         return;
 
     newcap = Max(newcap, SLOT_CAPACITY_MIN);
@@ -3144,18 +3141,20 @@ js_FindClassObject(ExclusiveContext *cx,
                 v.get().setUndefined();
         }
     }
     vp.set(v);
     return true;
 }
 
 /* static */ bool
-JSObject::allocSlot(ExclusiveContext *cx, HandleObject obj, uint32_t *slotp)
+JSObject::allocSlot(ThreadSafeContext *cx, HandleObject obj, uint32_t *slotp)
 {
+    JS_ASSERT(cx->isThreadLocal(obj));
+
     uint32_t slot = obj->slotSpan();
     JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
 
     /*
      * If this object is in dictionary mode, try to pull a free slot from the
      * shape table's slot-number freelist.
      */
     if (obj->inDictionaryMode()) {
@@ -3295,17 +3294,18 @@ js_AddNativeProperty(JSContext *cx, Hand
      * Purge the property cache of now-shadowed id in obj's scope chain. Do
      * this optimistically (assuming no failure below) before locking obj, so
      * we can lock the shadowed scope.
      */
     if (!PurgeScopeChain(cx, obj, id))
         return nullptr;
 
     Shape *shape =
-        JSObject::putProperty(cx, obj, id, getter, setter, slot, attrs, flags, shortid);
+        JSObject::putProperty<SequentialExecution>(cx, obj, id, getter, setter, slot,
+                                                   attrs, flags, shortid);
     if (!shape)
         return shape;
 
     if (JSID_IS_INT(id))
         JSObject::removeDenseElementForSparseIndex(cx, obj, JSID_TO_INT(id));
 
     return shape;
 }
@@ -3402,21 +3402,27 @@ JSObject::addDataProperty(ExclusiveConte
 }
 
 /*
  * Backward compatibility requires allowing addProperty hooks to mutate the
  * nominal initial value of a slotful property, while GC safety wants that
  * value to be stored before the call-out through the hook.  Optimize to do
  * both while saving cycles for classes that stub their addProperty hook.
  */
+template <ExecutionMode mode>
 static inline bool
-CallAddPropertyHook(ExclusiveContext *cx, const Class *clasp, HandleObject obj, HandleShape shape,
+CallAddPropertyHook(typename ExecutionModeTraits<mode>::ExclusiveContextType cxArg,
+                    const Class *clasp, HandleObject obj, HandleShape shape,
                     HandleValue nominal)
 {
     if (clasp->addProperty != JS_PropertyStub) {
+        if (mode == ParallelExecution)
+            return false;
+
+        ExclusiveContext *cx = cxArg->asExclusiveContext();
         if (!cx->shouldBeJSContext())
             return false;
 
         /* Make a local copy of value so addProperty can mutate its inout parameter. */
         RootedValue value(cx, nominal);
 
         Rooted<jsid> id(cx, shape->propid());
         if (!CallJSPropertyOp(cx->asJSContext(), clasp->addProperty, obj, id, &value)) {
@@ -3426,30 +3432,44 @@ CallAddPropertyHook(ExclusiveContext *cx
         if (value.get() != nominal) {
             if (shape->hasSlot())
                 JSObject::nativeSetSlotWithType(cx, obj, shape, value);
         }
     }
     return true;
 }
 
+template <ExecutionMode mode>
 static inline bool
-CallAddPropertyHookDense(ExclusiveContext *cx, const Class *clasp, HandleObject obj, uint32_t index,
+CallAddPropertyHookDense(typename ExecutionModeTraits<mode>::ExclusiveContextType cxArg,
+                         const Class *clasp, HandleObject obj, uint32_t index,
                          HandleValue nominal)
 {
     /* Inline addProperty for array objects. */
     if (obj->is<ArrayObject>()) {
-        Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
+        Rooted<ArrayObject*> arr(cxArg, &obj->as<ArrayObject>());
         uint32_t length = arr->length();
-        if (index >= length)
-            ArrayObject::setLength(cx, arr, index + 1);
+        if (index >= length) {
+            if (mode == ParallelExecution) {
+                /* We cannot deal with overflows in parallel. */
+                if (length > INT32_MAX)
+                    return false;
+                arr->setLengthInt32(index + 1);
+            } else {
+                ArrayObject::setLength(cxArg->asExclusiveContext(), arr, index + 1);
+            }
+        }
         return true;
     }
 
     if (clasp->addProperty != JS_PropertyStub) {
+        if (mode == ParallelExecution)
+            return false;
+
+        ExclusiveContext *cx = cxArg->asExclusiveContext();
         if (!cx->shouldBeJSContext())
             return false;
 
         /* Make a local copy of value so addProperty can mutate its inout parameter. */
         RootedValue value(cx, nominal);
 
         Rooted<jsid> id(cx, INT_TO_JSID(index));
         if (!CallJSPropertyOp(cx->asJSContext(), clasp->addProperty, obj, id, &value)) {
@@ -3458,97 +3478,125 @@ CallAddPropertyHookDense(ExclusiveContex
         }
         if (value.get() != nominal)
             JSObject::setDenseElementWithType(cx, obj, index, value);
     }
 
     return true;
 }
 
+template <ExecutionMode mode>
 static inline bool
-DefinePropertyOrElement(ExclusiveContext *cx, HandleObject obj, HandleId id,
+DefinePropertyOrElement(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
+                        HandleObject obj, HandleId id,
                         PropertyOp getter, StrictPropertyOp setter,
                         unsigned attrs, unsigned flags, int shortid,
                         HandleValue value, bool callSetterAfterwards, bool setterIsStrict)
 {
     /* Use dense storage for new indexed properties where possible. */
     if (JSID_IS_INT(id) &&
         getter == JS_PropertyStub &&
         setter == JS_StrictPropertyStub &&
         attrs == JSPROP_ENUMERATE &&
-        (!obj->isIndexed() || !obj->nativeContains(cx, id)))
+        (!obj->isIndexed() || !obj->nativeContainsPure(id)))
     {
         uint32_t index = JSID_TO_INT(id);
         bool definesPast;
         if (!WouldDefinePastNonwritableLength(cx, obj, index, setterIsStrict, &definesPast))
             return false;
-        if (definesPast)
+        if (definesPast) {
+            /*
+             * Strict mode changes semantics and we must throw, so bail out of
+             * parallel execution if we are strict.
+             */
+            if (mode == ParallelExecution)
+                return !setterIsStrict;
             return true;
-
-        JSObject::EnsureDenseResult result = obj->ensureDenseElements(cx, index, 1);
+        }
+
+        JSObject::EnsureDenseResult result;
+        if (mode == ParallelExecution) {
+            if (obj->writeToIndexWouldMarkNotPacked(index))
+                return false;
+            result = obj->ensureDenseElementsPreservePackedFlag(cx, index, 1);
+        } else {
+            result = obj->ensureDenseElements(cx->asExclusiveContext(), index, 1);
+        }
+
         if (result == JSObject::ED_FAILED)
             return false;
         if (result == JSObject::ED_OK) {
             obj->setDenseElementMaybeConvertDouble(index, value);
-            return CallAddPropertyHookDense(cx, obj->getClass(), obj, index, value);
+            return CallAddPropertyHookDense<mode>(cx, obj->getClass(), obj, index, value);
         }
     }
 
     if (obj->is<ArrayObject>()) {
         Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
         if (id == NameToId(cx->names().length)) {
-            if (!cx->shouldBeJSContext())
+            if (mode == SequentialExecution && !cx->shouldBeJSContext())
                 return false;
-            return ArraySetLength(cx->asJSContext(), arr, id, attrs, value, setterIsStrict);
+            return ArraySetLength<mode>(ExecutionModeTraits<mode>::toContextType(cx), arr, id,
+                                        attrs, value, setterIsStrict);
         }
 
         uint32_t index;
         if (js_IdIsIndex(id, &index)) {
             bool definesPast;
             if (!WouldDefinePastNonwritableLength(cx, arr, index, setterIsStrict, &definesPast))
                 return false;
-            if (definesPast)
+            if (definesPast) {
+                /* Bail out of parallel execution if we are strict to throw. */
+                if (mode == ParallelExecution)
+                    return !setterIsStrict;
                 return true;
+            }
         }
     }
 
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
 
-    RootedShape shape(cx, JSObject::putProperty(cx, obj, id, getter, setter, SHAPE_INVALID_SLOT,
-                                                attrs, flags, shortid));
+    RootedShape shape(cx, JSObject::putProperty<mode>(cx, obj, id, getter, setter,
+                                                      SHAPE_INVALID_SLOT,
+                                                      attrs, flags, shortid));
     if (!shape)
         return false;
 
     if (shape->hasSlot())
         obj->nativeSetSlot(shape->slot(), value);
 
     /*
      * Clear any existing dense index after adding a sparse indexed property,
      * and investigate converting the object to dense indexes.
      */
     if (JSID_IS_INT(id)) {
+        if (mode == ParallelExecution)
+            return false;
+
+        ExclusiveContext *ncx = cx->asExclusiveContext();
         uint32_t index = JSID_TO_INT(id);
-        JSObject::removeDenseElementForSparseIndex(cx, obj, index);
-        JSObject::EnsureDenseResult result = JSObject::maybeDensifySparseElements(cx, obj);
+        JSObject::removeDenseElementForSparseIndex(ncx, obj, index);
+        JSObject::EnsureDenseResult result = JSObject::maybeDensifySparseElements(ncx, obj);
         if (result == JSObject::ED_FAILED)
             return false;
         if (result == JSObject::ED_OK) {
             JS_ASSERT(setter == JS_StrictPropertyStub);
-            return CallAddPropertyHookDense(cx, obj->getClass(), obj, index, value);
+            return CallAddPropertyHookDense<mode>(cx, obj->getClass(), obj, index, value);
         }
     }
 
-    if (!CallAddPropertyHook(cx, obj->getClass(), obj, shape, value))
+    if (!CallAddPropertyHook<mode>(cx, obj->getClass(), obj, shape, value))
         return false;
 
     if (callSetterAfterwards && setter != JS_StrictPropertyStub) {
         if (!cx->shouldBeJSContext())
             return false;
         RootedValue nvalue(cx, value);
-        return js_NativeSet(cx->asJSContext(), obj, obj, shape, setterIsStrict, &nvalue);
+        return NativeSet<mode>(ExecutionModeTraits<mode>::toContextType(cx),
+                               obj, obj, shape, setterIsStrict, &nvalue);
     }
     return true;
 }
 
 bool
 js::DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, HandleId id, HandleValue value,
                          PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                          unsigned flags, int shortid, unsigned defineHow /* = 0 */)
@@ -3579,24 +3627,24 @@ js::DefineNativeProperty(ExclusiveContex
             return false;
         if (shape && pobj == obj) {
             if (IsImplicitDenseElement(shape)) {
                 if (!JSObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
                     return false;
                 shape = obj->nativeLookup(cx, id);
             }
             if (shape->isAccessorDescriptor()) {
-                shape = JSObject::changeProperty(cx, obj, shape, attrs,
-                                                 JSPROP_GETTER | JSPROP_SETTER,
-                                                 (attrs & JSPROP_GETTER)
-                                                 ? getter
-                                                 : shape->getter(),
-                                                 (attrs & JSPROP_SETTER)
-                                                 ? setter
-                                                 : shape->setter());
+                shape = JSObject::changeProperty<SequentialExecution>(cx, obj, shape, attrs,
+                                                                      JSPROP_GETTER | JSPROP_SETTER,
+                                                                      (attrs & JSPROP_GETTER)
+                                                                      ? getter
+                                                                      : shape->getter(),
+                                                                      (attrs & JSPROP_SETTER)
+                                                                      ? setter
+                                                                      : shape->setter());
                 if (!shape)
                     return false;
             } else {
                 shape = nullptr;
             }
         } else {
             shape = nullptr;
         }
@@ -3625,24 +3673,25 @@ js::DefineNativeProperty(ExclusiveContex
          * initial value of the property.
          */
         AddTypePropertyId(cx, obj, id, value);
         if (attrs & JSPROP_READONLY)
             MarkTypePropertyConfigured(cx, obj, id);
     }
 
     if (!shape) {
-        return DefinePropertyOrElement(cx, obj, id, getter, setter,
-                                       attrs, flags, shortid, value, false, false);
+        return DefinePropertyOrElement<SequentialExecution>(cx, obj, id, getter, setter,
+                                                            attrs, flags, shortid, value,
+                                                            false, false);
     }
 
     if (shape->hasSlot())
         obj->nativeSetSlot(shape->slot(), value);
 
-    return CallAddPropertyHook(cx, clasp, obj, shape, value);
+    return CallAddPropertyHook<SequentialExecution>(cx, clasp, obj, shape, value);
 }
 
 /*
  * Call obj's resolve hook.
  *
  * cx, id, and flags are the parameters initially passed to the ongoing lookup;
  * objp and propp are its out parameters. obj is an object along the prototype
  * chain from where the lookup started.
@@ -4083,39 +4132,50 @@ NativeGetInline(JSContext *cx,
     /* Update slotful shapes according to the value produced by the getter. */
     if (shape->hasSlot() && pobj->nativeContains(cx, shape))
         pobj->nativeSetSlot(shape->slot(), vp);
 
     return true;
 }
 
 bool
-js_NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Handle<Shape*> shape,
-             MutableHandle<Value> vp)
+js::NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Handle<Shape*> shape,
+              MutableHandle<Value> vp)
 {
     return NativeGetInline<CanGC>(cx, obj, obj, pobj, shape, vp);
 }
 
-
+template <ExecutionMode mode>
 bool
-js_NativeSet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> receiver,
-             HandleShape shape, bool strict, MutableHandleValue vp)
+js::NativeSet(typename ExecutionModeTraits<mode>::ContextType cxArg,
+              Handle<JSObject*> obj, Handle<JSObject*> receiver,
+              HandleShape shape, bool strict, MutableHandleValue vp)
 {
+    JS_ASSERT(cxArg->isThreadLocal(obj));
     JS_ASSERT(obj->isNative());
 
     if (shape->hasSlot()) {
-        uint32_t slot = shape->slot();
-
         /* If shape has a stub setter, just store vp. */
         if (shape->hasDefaultSetter()) {
-            AddTypePropertyId(cx, obj, shape->propid(), vp);
-            obj->nativeSetSlot(slot, vp);
+            if (mode == ParallelExecution) {
+                if (!obj->nativeSetSlotIfHasType(shape, vp))
+                    return false;
+            } else {
+                obj->nativeSetSlotWithType(cxArg->asExclusiveContext(), obj, shape, vp);
+            }
+
             return true;
         }
-    } else {
+    }
+
+    if (mode == ParallelExecution)
+        return false;
+    JSContext *cx = cxArg->asJSContext();
+
+    if (!shape->hasSlot()) {
         /*
          * Allow API consumers to create shared properties with stub setters.
          * Such properties effectively function as data descriptors which are
          * not writable, so attempting to set such a property should do nothing
          * or throw if we're in strict mode.
          */
         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
             return js_ReportGetterOnlyAssignment(cx, strict);
@@ -4137,16 +4197,25 @@ js_NativeSet(JSContext *cx, Handle<JSObj
      {
         AddTypePropertyId(cx, obj, shape->propid(), ovp);
         obj->setSlot(shape->slot(), vp);
     }
 
     return true;
 }
 
+template bool
+js::NativeSet<SequentialExecution>(JSContext *cx,
+                                   Handle<JSObject*> obj, Handle<JSObject*> receiver,
+                                   HandleShape shape, bool strict, MutableHandleValue vp);
+template bool
+js::NativeSet<ParallelExecution>(ForkJoinSlice *slice,
+                                 Handle<JSObject*> obj, Handle<JSObject*> receiver,
+                                 HandleShape shape, bool strict, MutableHandleValue vp);
+
 template <AllowGC allowGC>
 static JS_ALWAYS_INLINE bool
 GetPropertyHelperInline(JSContext *cx,
                         typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
                         typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
                         typename MaybeRooted<jsid, allowGC>::HandleType id,
                         typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
 {
@@ -4239,17 +4308,17 @@ GetPropertyHelperInline(JSContext *cx,
                : JSObject::getGeneric(cx, obj2Handle, obj2Handle, idHandle, vpHandle);
     }
 
     if (IsImplicitDenseElement(shape)) {
         vp.set(obj2->getDenseElement(JSID_TO_INT(id)));
         return true;
     }
 
-    /* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
+    /* This call site is hot -- use the always-inlined variant of NativeGet(). */
     if (!NativeGetInline<allowGC>(cx, obj, receiver, obj2, shape, vp))
         return false;
 
     return true;
 }
 
 bool
 baseops::GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, MutableHandleValue vp)
@@ -4548,36 +4617,53 @@ JSObject::callMethod(JSContext *cx, Hand
 {
     RootedValue fval(cx);
     RootedObject obj(cx, this);
     if (!JSObject::getGeneric(cx, obj, obj, id, &fval))
         return false;
     return Invoke(cx, ObjectValue(*obj), fval, argc, argv, vp);
 }
 
+template <ExecutionMode mode>
 bool
-baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
+baseops::SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cxArg,
+                           HandleObject obj, HandleObject receiver, HandleId id,
                            unsigned defineHow, MutableHandleValue vp, bool strict)
 {
+    JS_ASSERT(cxArg->isThreadLocal(obj));
     JS_ASSERT((defineHow & ~DNP_UNQUALIFIED) == 0);
 
     if (JS_UNLIKELY(obj->watched())) {
+        if (mode == ParallelExecution)
+            return false;
+
         /* Fire watchpoints, if any. */
+        JSContext *cx = cxArg->asJSContext();
         WatchpointMap *wpmap = cx->compartment()->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
 
-    RootedObject pobj(cx);
-    RootedShape shape(cx);
-    if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &shape))
-        return false;
+    RootedObject pobj(cxArg);
+    RootedShape shape(cxArg);
+    if (mode == ParallelExecution) {
+        if (!LookupPropertyPure(obj, id, pobj.address(), shape.address()))
+            return false;
+    } else {
+        JSContext *cx = cxArg->asJSContext();
+        if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &shape))
+            return false;
+    }
     if (shape) {
         if (!pobj->isNative()) {
             if (pobj->is<ProxyObject>()) {
+                if (mode == ParallelExecution)
+                    return false;
+
+                JSContext *cx = cxArg->asJSContext();
                 Rooted<PropertyDescriptor> pd(cx);
                 if (!Proxy::getPropertyDescriptor(cx, pobj, id, &pd, JSRESOLVE_ASSIGNING))
                     return false;
 
                 if ((pd.attributes() & (JSPROP_SHARED | JSPROP_SHADOWABLE)) == JSPROP_SHARED) {
                     return !pd.setter() ||
                            CallSetter(cx, receiver, id, pd.setter(), pd.attributes(),
                                       pd.shortid(), strict, vp);
@@ -4593,21 +4679,22 @@ baseops::SetPropertyHelper(JSContext *cx
             }
 
             shape = nullptr;
         }
     } else {
         /* We should never add properties to lexical blocks. */
         JS_ASSERT(!obj->is<BlockObject>());
 
-        if (obj->is<GlobalObject>() &&
-            (defineHow & DNP_UNQUALIFIED) &&
-            !MaybeReportUndeclaredVarAssignment(cx, JSID_TO_STRING(id)))
-        {
-            return false;
+        if (obj->is<GlobalObject>() && (defineHow & DNP_UNQUALIFIED)) {
+            if (mode == ParallelExecution)
+                return false;
+
+            if (!MaybeReportUndeclaredVarAssignment(cxArg->asJSContext(), JSID_TO_STRING(id)))
+                return false;
         }
     }
 
     /*
      * Now either shape is null, meaning id was not found in obj or one of its
      * prototypes; or shape is non-null, meaning id was found directly in pobj.
      */
     unsigned attrs = JSPROP_ENUMERATE;
@@ -4619,23 +4706,37 @@ baseops::SetPropertyHelper(JSContext *cx
 
     if (IsImplicitDenseElement(shape)) {
         /* ES5 8.12.4 [[Put]] step 2, for a dense data property on pobj. */
         if (pobj != obj)
             shape = nullptr;
     } else if (shape) {
         /* ES5 8.12.4 [[Put]] step 2. */
         if (shape->isAccessorDescriptor()) {
-            if (shape->hasDefaultSetter())
-                return js_ReportGetterOnlyAssignment(cx, strict);
+            if (shape->hasDefaultSetter()) {
+                /* Bail out of parallel execution if we are strict to throw. */
+                if (mode == ParallelExecution)
+                    return !strict;
+
+                return js_ReportGetterOnlyAssignment(cxArg->asJSContext(), strict);
+            }
         } else {
             JS_ASSERT(shape->isDataDescriptor());
 
             if (!shape->writable()) {
-                /* Error in strict mode code, warn with extra warnings options, otherwise do nothing. */
+                /*
+                 * Error in strict mode code, warn with extra warnings
+                 * options, otherwise do nothing.
+                 *
+                 * Bail out of parallel execution if we are strict to throw.
+                 */
+                if (mode == ParallelExecution)
+                    return !strict;
+
+                JSContext *cx = cxArg->asJSContext();
                 if (strict)
                     return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
                 if (cx->hasExtraWarningsOption())
                     return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
                 return true;
             }
         }
 
@@ -4643,17 +4744,20 @@ baseops::SetPropertyHelper(JSContext *cx
         if (pobj != obj) {
             /*
              * We found id in a prototype object: prepare to share or shadow.
              */
             if (!shape->shadowable()) {
                 if (shape->hasDefaultSetter() && !shape->hasGetterValue())
                     return true;
 
-                return shape->set(cx, obj, receiver, strict, vp);
+                if (mode == ParallelExecution)
+                    return false;
+
+                return shape->set(cxArg->asJSContext(), obj, receiver, strict, vp);
             }
 
             /*
              * Preserve attrs except JSPROP_SHARED, getter, and setter when
              * shadowing any property that has no slot (is shared). We must
              * clear the shared attribute for the shadowing shape so that the
              * property in obj that it defines has a slot to retain the value
              * being set, in case the setter simply cannot operate on instances
@@ -4685,65 +4789,106 @@ baseops::SetPropertyHelper(JSContext *cx
              */
             shape = nullptr;
         }
     }
 
     if (IsImplicitDenseElement(shape)) {
         uint32_t index = JSID_TO_INT(id);
         bool definesPast;
-        if (!WouldDefinePastNonwritableLength(cx, obj, index, strict, &definesPast))
+        if (!WouldDefinePastNonwritableLength(cxArg, obj, index, strict, &definesPast))
             return false;
-        if (definesPast)
+        if (definesPast) {
+            /* Bail out of parallel execution if we are strict to throw. */
+            if (mode == ParallelExecution)
+                return !strict;
             return true;
-
-        JSObject::setDenseElementWithType(cx, obj, index, vp);
+        }
+
+        if (mode == ParallelExecution)
+            obj->setDenseElementIfHasType(index, vp);
+        else
+            JSObject::setDenseElementWithType(cxArg->asJSContext(), obj, index, vp);
         return true;
     }
 
-    if (obj->is<ArrayObject>() && id == NameToId(cx->names().length)) {
-        Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
-        return ArraySetLength(cx, arr, id, attrs, vp, strict);
+    if (obj->is<ArrayObject>() && id == NameToId(cxArg->names().length)) {
+        Rooted<ArrayObject*> arr(cxArg, &obj->as<ArrayObject>());
+        return ArraySetLength<mode>(cxArg, arr, id, attrs, vp, strict);
     }
 
     if (!shape) {
         bool extensible;
-        if (!JSObject::isExtensible(cx, obj, &extensible))
-            return false;
+        if (mode == ParallelExecution) {
+            if (obj->is<ProxyObject>())
+                return false;
+            extensible = obj->nonProxyIsExtensible();
+        } else {
+            if (!JSObject::isExtensible(cxArg->asJSContext(), obj, &extensible))
+                return false;
+        }
+
         if (!extensible) {
+            /* Bail out of parallel execution if we are strict to throw. */
+            if (mode == ParallelExecution)
+                return !strict;
+
             /* Error in strict mode code, warn with extra warnings option, otherwise do nothing. */
+            JSContext *cx = cxArg->asJSContext();
             if (strict)
                 return obj->reportNotExtensible(cx);
             if (cx->hasExtraWarningsOption())
                 return obj->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
             return true;
         }
 
-        /* Purge the property cache of now-shadowed id in obj's scope chain. */
-        if (!PurgeScopeChain(cx, obj, id))
-            return false;
-
-        if (getter == JS_PropertyStub)
-            AddTypePropertyId(cx, obj, id, vp);
-
-        return DefinePropertyOrElement(cx, obj, id, getter, setter,
-                                       attrs, flags, shortid, vp, true, strict);
-    }
-
-    return js_NativeSet(cx, obj, receiver, shape, strict, vp);
+        if (mode == ParallelExecution) {
+            if (obj->isDelegate())
+                return false;
+
+            if (getter != JS_PropertyStub || !HasTypePropertyId(obj, id, vp))
+                return false;
+        } else {
+            JSContext *cx = cxArg->asJSContext();
+
+            /* Purge the property cache of now-shadowed id in obj's scope chain. */
+            if (!PurgeScopeChain(cx, obj, id))
+                return false;
+
+            if (getter == JS_PropertyStub)
+                AddTypePropertyId(cx, obj, id, vp);
+        }
+
+        return DefinePropertyOrElement<mode>(cxArg, obj, id, getter, setter,
+                                             attrs, flags, shortid, vp, true, strict);
+    }
+
+    return NativeSet<mode>(cxArg, obj, receiver, shape, strict, vp);
 }
 
+template bool
+baseops::SetPropertyHelper<SequentialExecution>(JSContext *cx, HandleObject obj,
+                                                HandleObject receiver,
+                                                HandleId id, unsigned defineHow,
+                                                MutableHandleValue vp, bool strict);
+template bool
+baseops::SetPropertyHelper<ParallelExecution>(ForkJoinSlice *slice, HandleObject obj,
+                                              HandleObject receiver,
+                                              HandleId id, unsigned defineHow,
+                                              MutableHandleValue vp, bool strict);
+
 bool
 baseops::SetElementHelper(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
                           unsigned defineHow, MutableHandleValue vp, bool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
-    return baseops::SetPropertyHelper(cx, obj, receiver, id, defineHow, vp, strict);
+    return baseops::SetPropertyHelper<SequentialExecution>(cx, obj, receiver, id, defineHow, vp,
+                                                           strict);
 }
 
 bool
 baseops::GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject nobj(cx);
     RootedShape shape(cx);
     if (!baseops::LookupProperty<CanGC>(cx, obj, id, &nobj, &shape))
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -112,26 +112,30 @@ GetProperty(JSContext *cx, HandleObject 
 }
 
 inline bool
 GetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
 {
     return GetElement(cx, obj, obj, index, vp);
 }
 
+template <ExecutionMode mode>
 extern bool
-SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
-                  unsigned defineHow, MutableHandleValue vp, bool strict);
+SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cx, HandleObject obj,
+                  HandleObject receiver, HandleId id, unsigned defineHow,
+                  MutableHandleValue vp, bool strict);
 
+template <ExecutionMode mode>
 inline bool
-SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receiver, PropertyName *name,
-                  unsigned defineHow, MutableHandleValue vp, bool strict)
+SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cx, HandleObject obj,
+                  HandleObject receiver, PropertyName *name, unsigned defineHow,
+                  MutableHandleValue vp, bool strict)
 {
     Rooted<jsid> id(cx, NameToId(name));
-    return SetPropertyHelper(cx, obj, receiver, id, defineHow, vp, strict);
+    return SetPropertyHelper<mode>(cx, obj, receiver, id, defineHow, vp, strict);
 }
 
 extern bool
 SetElementHelper(JSContext *cx, HandleObject obj, HandleObject Receiver, uint32_t index,
                  unsigned defineHow, MutableHandleValue vp, bool strict);
 
 extern bool
 GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
@@ -225,17 +229,17 @@ class JSObject : public js::ObjectImpl
 
   public:
     static const js::Class class_;
 
     /*
      * Update the last property, keeping the number of allocated slots in sync
      * with the object's new slot span.
      */
-    static bool setLastProperty(js::ExclusiveContext *cx,
+    static bool setLastProperty(js::ThreadSafeContext *cx,
                                 JS::HandleObject obj, js::HandleShape shape);
 
     /* As above, but does not change the slot span. */
     inline void setLastPropertyInfallible(js::Shape *shape);
 
     /*
      * Make a non-array object with the specified initial state. This method
      * takes ownership of any extantSlots it is passed.
@@ -262,17 +266,17 @@ class JSObject : public js::ObjectImpl
      */
     inline void removeLastProperty(js::ExclusiveContext *cx);
     inline bool canRemoveLastProperty();
 
     /*
      * Update the slot span directly for a dictionary object, and allocate
      * slots to cover the new span if necessary.
      */
-    static bool setSlotSpan(js::ExclusiveContext *cx, JS::HandleObject obj, uint32_t span);
+    static bool setSlotSpan(js::ThreadSafeContext *cx, JS::HandleObject obj, uint32_t span);
 
     /* Upper bound on the number of elements in an object. */
     static const uint32_t NELEMENTS_LIMIT = JS_BIT(28);
 
   public:
     bool setDelegate(js::ExclusiveContext *cx) {
         return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
     }
@@ -364,25 +368,25 @@ class JSObject : public js::ObjectImpl
         return slot - numFixedSlots();
     }
 
     /*
      * Grow or shrink slots immediately before changing the slot span.
      * The number of allocated slots is not stored explicitly, and changes to
      * the slots must track changes in the slot span.
      */
-    static bool growSlots(js::ExclusiveContext *cx, js::HandleObject obj, uint32_t oldCount,
+    static bool growSlots(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
                           uint32_t newCount);
-    static void shrinkSlots(js::ExclusiveContext *cx, js::HandleObject obj, uint32_t oldCount,
+    static void shrinkSlots(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
                             uint32_t newCount);
 
     bool hasDynamicSlots() const { return slots != nullptr; }
 
   protected:
-    static inline bool updateSlotsForSpan(js::ExclusiveContext *cx,
+    static inline bool updateSlotsForSpan(js::ThreadSafeContext *cx,
                                           js::HandleObject obj, size_t oldSpan, size_t newSpan);
 
   public:
     /*
      * Trigger the write barrier on a range of slots that will no longer be
      * reachable.
      */
     void prepareSlotRangeForOverwrite(size_t start, size_t end) {
@@ -399,16 +403,18 @@ class JSObject : public js::ObjectImpl
     void rollbackProperties(js::ExclusiveContext *cx, uint32_t slotSpan);
 
     void nativeSetSlot(uint32_t slot, const js::Value &value) {
         JS_ASSERT(isNative());
         JS_ASSERT(slot < slotSpan());
         return setSlot(slot, value);
     }
 
+    inline bool nativeSetSlotIfHasType(js::Shape *shape, const js::Value &value);
+
     static inline void nativeSetSlotWithType(js::ExclusiveContext *cx,
                                              js::HandleObject, js::Shape *shape,
                                              const js::Value &value);
 
     inline const js::Value &getReservedSlot(uint32_t index) const {
         JS_ASSERT(index < JSSLOT_FREE(getClass()));
         return getSlot(index);
     }
@@ -597,25 +603,32 @@ class JSObject : public js::ObjectImpl
     }
 
     uint32_t getDenseCapacity() {
         JS_ASSERT(isNative());
         JS_ASSERT(getElementsHeader()->capacity >= getElementsHeader()->initializedLength);
         return getElementsHeader()->capacity;
     }
 
+  private:
+    inline void ensureDenseInitializedLengthNoPackedCheck(js::ThreadSafeContext *cx,
+                                                          uint32_t index, uint32_t extra);
+
+  public:
     void setDenseInitializedLength(uint32_t length) {
         JS_ASSERT(isNative());
         JS_ASSERT(length <= getDenseCapacity());
         prepareElementRangeForOverwrite(length, getElementsHeader()->initializedLength);
         getElementsHeader()->initializedLength = length;
     }
 
     inline void ensureDenseInitializedLength(js::ExclusiveContext *cx,
                                              uint32_t index, uint32_t extra);
+    inline void ensureDenseInitializedLengthPreservePackedFlag(js::ThreadSafeContext *cx,
+                                                               uint32_t index, uint32_t extra);
     void setDenseElement(uint32_t index, const js::Value &val) {
         JS_ASSERT(isNative() && index < getDenseInitializedLength());
         elements[index].set(this, js::HeapSlot::Element, index, val);
     }
 
     void initDenseElement(uint32_t index, const js::Value &val) {
         JS_ASSERT(isNative() && index < getDenseInitializedLength());
         elements[index].init(this, js::HeapSlot::Element, index, val);
@@ -623,16 +636,17 @@ class JSObject : public js::ObjectImpl
 
     void setDenseElementMaybeConvertDouble(uint32_t index, const js::Value &val) {
         if (val.isInt32() && shouldConvertDoubleElements())
             setDenseElement(index, js::DoubleValue(val.toInt32()));
         else
             setDenseElement(index, val);
     }
 
+    inline bool setDenseElementIfHasType(uint32_t index, const js::Value &val);
     static inline void setDenseElementWithType(js::ExclusiveContext *cx, js::HandleObject obj,
                                                uint32_t index, const js::Value &val);
     static inline void initDenseElementWithType(js::ExclusiveContext *cx, js::HandleObject obj,
                                                 uint32_t index, const js::Value &val);
     static inline void setDenseElementHole(js::ExclusiveContext *cx,
                                            js::HandleObject obj, uint32_t index);
     static inline void removeDenseElementForSparseIndex(js::ExclusiveContext *cx,
                                                         js::HandleObject obj, uint32_t index);
@@ -648,17 +662,17 @@ class JSObject : public js::ObjectImpl
             memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
             DenseRangeWriteBarrierPost(rt, this, dstStart, count);
         }
     }
 
     void initDenseElements(uint32_t dstStart, const js::Value *src, uint32_t count) {
         JS_ASSERT(dstStart + count <= getDenseCapacity());
         memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));
-        DenseRangeWriteBarrierPost(runtimeFromMainThread(), this, dstStart, count);
+        DenseRangeWriteBarrierPost(runtimeFromAnyThread(), this, dstStart, count);
     }
 
     void moveDenseElements(uint32_t dstStart, uint32_t srcStart, uint32_t count) {
         JS_ASSERT(dstStart + count <= getDenseCapacity());
         JS_ASSERT(srcStart + count <= getDenseInitializedLength());
 
         /*
          * Using memmove here would skip write barriers. Also, we need to consider
@@ -704,30 +718,37 @@ class JSObject : public js::ObjectImpl
     bool shouldConvertDoubleElements() {
         JS_ASSERT(isNative());
         return getElementsHeader()->shouldConvertDoubleElements();
     }
 
     inline void setShouldConvertDoubleElements();
 
     /* Packed information for this object's elements. */
+    inline bool writeToIndexWouldMarkNotPacked(uint32_t index);
     inline void markDenseElementsNotPacked(js::ExclusiveContext *cx);
 
     /*
      * ensureDenseElements ensures that the object can hold at least
      * index + extra elements. It returns ED_OK on success, ED_FAILED on
      * failure to grow the array, ED_SPARSE when the object is too sparse to
      * grow (this includes the case of index + extra overflow). In the last
      * two cases the object is kept intact.
      */
     enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE };
+
+  private:
+    inline EnsureDenseResult ensureDenseElementsNoPackedCheck(js::ThreadSafeContext *cx,
+                                                              uint32_t index, uint32_t extra);
+
+  public:
     inline EnsureDenseResult ensureDenseElements(js::ExclusiveContext *cx,
                                                  uint32_t index, uint32_t extra);
-    inline EnsureDenseResult parExtendDenseElements(js::ThreadSafeContext *cx, js::Value *v,
-                                                    uint32_t extra);
+    inline EnsureDenseResult ensureDenseElementsPreservePackedFlag(js::ThreadSafeContext *cx,
+