Merge m-c to elm
authorNick Alexander <nalexander@mozilla.com>
Fri, 11 Oct 2013 09:33:44 -0700
changeset 161457 c73deceb25c56667f0101a42bed6659435c27d1c
parent 161456 205a579f88a998339bf9ff060e9cd31f5d6888aa (current diff)
parent 150438 6b101d4c6d241e3fa39b5ce71f122243fe2c118c (diff)
child 161458 26f7871068f002c7e053628a1a0651b40e1a15e9
push id25884
push userttaubert@mozilla.com
push dateSat, 21 Dec 2013 00:37:32 +0000
treeherdermozilla-central@b3d4af4ec2df [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to elm
dom/icc/interfaces/nsIDOMIccCardLockErrorEvent.idl
dom/webidl/IccCardLockErrorEvent.webidl
media/webrtc/shared_libs.mk
mobile/android/base/GeckoView.java.frag
mobile/android/base/Makefile.in
mobile/android/base/android-services-files.mk
mobile/android/base/resources/xml/preferences.xml.in
mobile/android/base/resources/xml/preferences_customize.xml.in
mobile/android/base/resources/xml/searchable.xml.in
mobile/android/base/resources/xml/sync_authenticator.xml.in
mobile/android/base/resources/xml/sync_options.xml.in
mobile/android/base/resources/xml/sync_syncadapter.xml.in
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Bug 899574 needed a clobber, at least on Windows.
+Bug 922461 needs a clobber to regenerate code and survive bug 925243's FAIL_ON_WARNINGS annotation.
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -535,17 +535,18 @@ GetClosestInterestingAccessible(id anObj
 }
 
 - (id)value
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   nsAutoString value;
   mGeckoAccessible->GetValue (value);
-  return value.IsEmpty() ? nil : [NSString stringWithCharacters:value.BeginReading() length:value.Length()];
+  return value.IsEmpty() ? nil : [NSString stringWithCharacters:reinterpret_cast<const unichar*>(value.BeginReading())
+                                                         length:value.Length()];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (void)valueDidChange
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
@@ -579,17 +580,18 @@ GetClosestInterestingAccessible(id anObj
 }
 
 - (NSString*)help
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
   nsAutoString helpText;
   mGeckoAccessible->GetHelp (helpText);
-  return helpText.IsEmpty() ? nil : [NSString stringWithCharacters:helpText.BeginReading() length:helpText.Length()];
+  return helpText.IsEmpty() ? nil : [NSString stringWithCharacters:reinterpret_cast<const unichar*>(helpText.BeginReading())
+                                                            length:helpText.Length()];
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 // objc-style description (from NSObject); not to be confused with the accessible description above.
 - (NSString*)description
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "ed107ffac75d42dbacc19f81d0e2650e34c83a16", 
+    "revision": "c7c750d66279bf2b7f9164d8b57d425a028e1fd9", 
     "repo_path": "/integration/gaia-central"
 }
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -3,16 +3,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 function debug(msg) {
   Services.console.logStringMessage("SessionStoreContent: " + msg);
 }
 
+let Cu = Components.utils;
+
 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
 
 XPCOMUtils.defineLazyModuleGetter(this, "DocShellCapabilities",
   "resource:///modules/sessionstore/DocShellCapabilities.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
   "resource:///modules/sessionstore/SessionHistory.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
   "resource:///modules/sessionstore/SessionStorage.jsm");
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -2521,17 +2521,19 @@ let SessionStoreInternal = {
 
       // Make sure that set/getTabValue will set/read the correct data by
       // wiping out any current value in tab.__SS_extdata.
       delete tab.__SS_extdata;
 
       if (!tabData.entries || tabData.entries.length == 0) {
         // make sure to blank out this tab's content
         // (just purging the tab's history won't be enough)
-        browser.contentDocument.location = "about:blank";
+        browser.loadURIWithFlags("about:blank",
+                                 Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY,
+                                 null, null, null);
         continue;
       }
 
       browser.stop(); // in case about:blank isn't done yet
 
       // wall-paper fix for bug 439675: make sure that the URL to be loaded
       // is always visible in the address bar
       let activeIndex = (tabData.index || tabData.entries.length) - 1;
--- a/browser/devtools/framework/test/browser_toolbox_options.js
+++ b/browser/devtools/framework/test/browser_toolbox_options.js
@@ -1,163 +1,216 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-let doc = null, toolbox = null, panelWin = null, index = 0, prefValues = [], prefNodes = [];
+let doc = null, toolbox = null, panelWin = null, modifiedPrefs = [];
 
 function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
   let target = TargetFactory.forTab(gBrowser.selectedTab);
 
   gBrowser.selectedBrowser.addEventListener("load", function onLoad(evt) {
     gBrowser.selectedBrowser.removeEventListener(evt.type, onLoad, true);
-    gDevTools.showToolbox(target).then(testSelectTool);
+    gDevTools.showToolbox(target)
+      .then(testSelectTool)
+      .then(testOptionsShortcut)
+      .then(testOptions)
+      .then(testToggleTools)
+      .then(cleanup, errorHandler);
   }, true);
 
   content.location = "data:text/html;charset=utf8,test for dynamically registering and unregistering tools";
 }
 
 function testSelectTool(aToolbox) {
+  let deferred = promise.defer();
+
   toolbox = aToolbox;
   doc = toolbox.doc;
-  toolbox.once("options-selected", testOptionsShortcut);
+  toolbox.once("options-selected", () => {
+    ok(true, "Toolbox selected via selectTool method");
+    deferred.resolve();
+  });
   toolbox.selectTool("options");
+
+  return deferred.promise;
 }
 
 function testOptionsShortcut() {
-  ok(true, "Toolbox selected via selectTool method");
-  toolbox.once("options-selected", testOptions);
+  let deferred = promise.defer();
+
+  toolbox.once("options-selected", (event, tool) => {
+    ok(true, "Toolbox selected via shortcut key");
+    deferred.resolve(tool);
+  });
   toolbox.selectTool("webconsole")
          .then(() => synthesizeKeyFromKeyTag("toolbox-options-key", doc));
+
+  return deferred.promise;
 }
 
-function testOptions(event, tool) {
-  ok(true, "Toolbox selected via button click");
+function testOptions(tool) {
   panelWin = tool.panelWin;
-  // Testing pref changes
-  let prefCheckboxes = tool.panelDoc.querySelectorAll("checkbox[data-pref]");
-  for (let checkbox of prefCheckboxes) {
-    prefNodes.push(checkbox);
-    prefValues.push(Services.prefs.getBoolPref(checkbox.getAttribute("data-pref")));
+  let prefNodes = tool.panelDoc.querySelectorAll("checkbox[data-pref]");
+
+  // Store modified pref names so that they can be cleared on error.
+  for (let node of prefNodes) {
+    let pref = node.getAttribute("data-pref");
+    modifiedPrefs.push(pref);
+  }
+
+  // Test each options pref
+  let p = promise.resolve();
+  for (let node of prefNodes) {
+    let prefValue = Services.prefs.getBoolPref(node.getAttribute("data-pref"));
+    p = p.then(testMouseClick.bind(null, node, prefValue));
   }
   // Do again with opposite values to reset prefs
-  for (let checkbox of prefCheckboxes) {
-    prefNodes.push(checkbox);
-    prefValues.push(!Services.prefs.getBoolPref(checkbox.getAttribute("data-pref")));
+  for (let node of prefNodes) {
+    let prefValue = !Services.prefs.getBoolPref(node.getAttribute("data-pref"));
+    p = p.then(testMouseClick.bind(null, node, prefValue));
   }
-  testMouseClicks();
+
+  return p;
 }
 
-function testMouseClicks() {
-  if (index == prefValues.length) {
-    checkTools();
-    return;
-  }
-  gDevTools.once("pref-changed", prefChanged);
-  info("Click event synthesized for index " + index);
-  prefNodes[index].scrollIntoView();
+function testMouseClick(node, prefValue) {
+  let deferred = promise.defer();
+
+  let pref = node.getAttribute("data-pref");
+  gDevTools.once("pref-changed", (event, data) => {
+    if (data.pref == pref) {
+      ok(true, "Correct pref was changed");
+      is(data.oldValue, prefValue, "Previous value is correct");
+      is(data.newValue, !prefValue, "New value is correct");
+    } else {
+      ok(false, "Pref " + pref + " was not changed correctly");
+    }
+    deferred.resolve();
+  });
+
+  node.scrollIntoView();
 
   // We use executeSoon here to ensure that the element is in view and
   // clickable.
   executeSoon(function() {
-    EventUtils.synthesizeMouseAtCenter(prefNodes[index], {}, panelWin);
+    info("Click event synthesized for pref " + pref);
+    EventUtils.synthesizeMouseAtCenter(node, {}, panelWin);
   });
-}
 
-function prefChanged(event, data) {
-  if (data.pref == prefNodes[index].getAttribute("data-pref")) {
-    ok(true, "Correct pref was changed");
-    is(data.oldValue, prefValues[index], "Previous value is correct");
-    is(data.newValue, !prefValues[index], "New value is correct");
-    index++;
-    testMouseClicks();
-    return;
-  }
-  ok(false, "Pref was not changed correctly");
-  cleanup();
-}
-
-function checkTools() {
-  let toolsPref = panelWin.document.querySelectorAll("#default-tools-box > checkbox:not([unsupported])");
-  prefNodes = [];
-  index = 0;
-  for (let tool of toolsPref) {
-    prefNodes.push(tool);
-  }
-  // Randomize the order in which we remove the tool and then add them back so
-  // that we get to know if the tabs are correctly placed as per their ordinals.
-  prefNodes = prefNodes.sort(() => Math.random() > 0.5 ? 1: -1);
-
-  // Wait for the next turn of the event loop to avoid stack overflow errors.
-  executeSoon(toggleTools);
+  return deferred.promise;
 }
 
-function toggleTools() {
-  if (index < prefNodes.length) {
-    gDevTools.once("tool-unregistered", checkUnregistered);
-    let node = prefNodes[index];
-    node.scrollIntoView();
-    EventUtils.synthesizeMouseAtCenter(node, {}, panelWin);
+function testToggleTools() {
+  let toolNodes = panelWin.document.querySelectorAll("#default-tools-box > checkbox:not([unsupported])");
+  let enabledTools = Array.prototype.filter.call(toolNodes, node => node.checked);
+
+  // Store modified pref names so that they can be cleared on error.
+  for (let tool of gDevTools.getDefaultTools()) {
+    let pref = tool.visibilityswitch;
+    modifiedPrefs.push(pref);
+  }
+
+  // Toggle each tool
+  let p = promise.resolve();
+  for (let node of toolNodes) {
+    p = p.then(toggleTool.bind(null, node));
+  }
+  // Toggle again to reset tool enablement state
+  for (let node of toolNodes) {
+    p = p.then(toggleTool.bind(null, node));
   }
-  else if (index < 2*prefNodes.length) {
-    gDevTools.once("tool-registered", checkRegistered);
-    let node = prefNodes[index - prefNodes.length];
-    node.scrollIntoView();
-    EventUtils.synthesizeMouseAtCenter(node, {}, panelWin);
+
+  // Test that a tool can still be added when no tabs are present:
+  // Disable all tools
+  for (let node of enabledTools) {
+    p = p.then(toggleTool.bind(null, node));
+  }
+  // Re-enable the tools which are enabled by default
+  for (let node of enabledTools) {
+    p = p.then(toggleTool.bind(null, node));
   }
-  else {
-    cleanup();
-  }
+
+  // Toggle first, middle, and last tools to ensure that toolbox tabs are
+  // inserted in order
+  let firstTool  = toolNodes[0],
+      middleTool = toolNodes[(toolNodes.length / 2) | 0],
+      lastTool   = toolNodes[toolNodes.length - 1];
+
+  p = p.then(toggleTool.bind(null, firstTool))
+       .then(toggleTool.bind(null, firstTool))
+       .then(toggleTool.bind(null, middleTool))
+       .then(toggleTool.bind(null, middleTool))
+       .then(toggleTool.bind(null, lastTool))
+       .then(toggleTool.bind(null, lastTool));
+
+  return p;
 }
 
-function checkUnregistered(event, data) {
-  if (data.id == prefNodes[index].getAttribute("id")) {
+function toggleTool(node) {
+  let deferred = promise.defer();
+
+  let toolId = node.getAttribute("id");
+  if (node.checked) {
+    gDevTools.once("tool-unregistered", checkUnregistered.bind(null, toolId, deferred));
+  } else {
+    gDevTools.once("tool-registered", checkRegistered.bind(null, toolId, deferred));
+  }
+  node.scrollIntoView();
+  EventUtils.synthesizeMouseAtCenter(node, {}, panelWin);
+
+  return deferred.promise;
+}
+
+function checkUnregistered(toolId, deferred, event, data) {
+  if (data.id == toolId) {
     ok(true, "Correct tool removed");
     // checking tab on the toolbox
-    ok(!doc.getElementById("toolbox-tab-" + data.id), "Tab removed for " +
-       data.id);
-    index++;
-    // Wait for the next turn of the event loop to avoid stack overflow errors.
-    executeSoon(toggleTools);
-    return;
+    ok(!doc.getElementById("toolbox-tab-" + toolId), "Tab removed for " + toolId);
+  } else {
+    ok(false, "Something went wrong, " + toolId + " was not unregistered");
   }
-  ok(false, "Something went wrong, " + data.id + " was not unregistered");
-  cleanup();
+  deferred.resolve();
 }
 
-function checkRegistered(event, data) {
-  if (data == prefNodes[index - prefNodes.length].getAttribute("id")) {
+function checkRegistered(toolId, deferred, event, data) {
+  if (data == toolId) {
     ok(true, "Correct tool added back");
     // checking tab on the toolbox
-    let radio = doc.getElementById("toolbox-tab-" + data);
-    ok(radio, "Tab added back for " + data);
+    let radio = doc.getElementById("toolbox-tab-" + toolId);
+    ok(radio, "Tab added back for " + toolId);
     if (radio.previousSibling) {
       ok(+radio.getAttribute("ordinal") >=
          +radio.previousSibling.getAttribute("ordinal"),
          "Inserted tab's ordinal is greater than equal to its previous tab." +
          "Expected " + radio.getAttribute("ordinal") + " >= " +
          radio.previousSibling.getAttribute("ordinal"));
     }
     if (radio.nextSibling) {
       ok(+radio.getAttribute("ordinal") <
          +radio.nextSibling.getAttribute("ordinal"),
          "Inserted tab's ordinal is less than its next tab. Expected " +
          radio.getAttribute("ordinal") + " < " +
          radio.nextSibling.getAttribute("ordinal"));
     }
-    index++;
-    // Wait for the next turn of the event loop to avoid stack overflow errors.
-    executeSoon(toggleTools);
-    return;
+  } else {
+    ok(false, "Something went wrong, " + toolId + " was not registered");
   }
-  ok(false, "Something went wrong, " + data + " was not registered back");
-  cleanup();
+  deferred.resolve();
 }
 
 function cleanup() {
   toolbox.destroy().then(function() {
     gBrowser.removeCurrentTab();
-    toolbox = doc = prefNodes = prefValues = panelWin = null;
+    for (let pref of modifiedPrefs) {
+      Services.prefs.clearUserPref(pref);
+    }
+    toolbox = doc = panelWin = modifiedPrefs = null;
     finish();
   });
 }
+
+function errorHandler(error) {
+  ok(false, "Unexpected error: " + error);
+  cleanup();
+}
--- a/browser/devtools/framework/test/browser_toolbox_window_shortcuts.js
+++ b/browser/devtools/framework/test/browser_toolbox_window_shortcuts.js
@@ -1,29 +1,41 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 let Toolbox = devtools.Toolbox;
 
-let toolbox, toolIDs, idIndex;
+let toolbox, toolIDs, idIndex, modifiedPrefs = [];
 
 function test() {
   waitForExplicitFinish();
 
   if (window.navigator.userAgent.indexOf("Mac OS X 10.8") != -1 ||
       window.navigator.userAgent.indexOf("Windows NT 5.1") != -1) {
     info("Skipping Mac OSX 10.8 and Windows xp, see bug 838069");
     finish();
     return;
   }
   addTab("about:blank", function() {
     toolIDs = [];
     for (let [id, definition] of gDevTools._tools) {
       if (definition.key) {
         toolIDs.push(id);
+
+        // Enable disabled tools
+        let pref = definition.visibilityswitch, prefValue;
+        try {
+          prefValue = Services.prefs.getBoolPref(pref);
+        } catch (e) {
+          continue;
+        }
+        if (!prefValue) {
+          modifiedPrefs.push(pref);
+          Services.prefs.setBoolPref(pref, true);
+        }
       }
     }
     let target = TargetFactory.forTab(gBrowser.selectedTab);
     idIndex = 0;
     gDevTools.showToolbox(target, toolIDs[0], Toolbox.HostType.WINDOW)
              .then(testShortcuts);
   });
 }
@@ -66,12 +78,15 @@ function selectCB(event, id) {
 
   testShortcuts(toolbox, idIndex + 1);
 }
 
 function tidyUp() {
   toolbox.destroy().then(function() {
     gBrowser.removeCurrentTab();
 
-    toolbox = toolIDs = idIndex = Toolbox = null;
+    for (let pref of modifiedPrefs) {
+      Services.prefs.clearUserPref(pref);
+    }
+    toolbox = toolIDs = idIndex = modifiedPrefs = Toolbox = null;
     finish();
   });
 }
--- a/browser/metro/base/content/ContextCommands.js
+++ b/browser/metro/base/content/ContextCommands.js
@@ -254,16 +254,34 @@ var ContextCommands = {
   findInPage: function cc_findInPage() {
     FindHelperUI.show();
   },
 
   viewOnDesktop: function cc_viewOnDesktop() {
     Appbar.onViewOnDesktop();
   },
 
+  // Checks for MS app store specific meta data, and if present opens
+  // the Windows Store to the appropriate app
+  openWindowsStoreLink: function cc_openWindowsStoreLink() {
+    let storeLink = this.getStoreLink();
+    if (storeLink) {
+      Browser.selectedBrowser.contentWindow.document.location = storeLink;
+    }
+  },
+
+  getStoreLink: function cc_getStoreLink() {
+    let metaData = Browser.selectedBrowser.contentWindow.document.getElementsByTagName("meta");
+    let msApplicationName = metaData.namedItem("msApplication-PackageFamilyName");
+    if (msApplicationName) {
+      return "ms-windows-store:PDP?PFN=" + msApplicationName.getAttribute("content");
+    }
+    return null;
+  },
+
   /*
    * Utilities
    */
 
   saveToWinLibrary: function cc_saveToWinLibrary(aType) {
     let popupState = ContextMenuUI.popupState;
     let browser = popupState.target;
 
--- a/browser/metro/base/content/appbar.js
+++ b/browser/metro/base/content/appbar.js
@@ -112,16 +112,18 @@ var Appbar = {
     }
   },
 
   onMenuButton: function(aEvent) {
       let typesArray = [];
 
       if (!BrowserUI.isStartTabVisible)
         typesArray.push("find-in-page");
+      if (ContextCommands.getStoreLink())
+        typesArray.push("ms-meta-data");
       if (ConsolePanelView.enabled)
         typesArray.push("open-error-console");
       if (!Services.metro.immersive)
         typesArray.push("open-jsshell");
 
       try {
         // If we have a valid http or https URI then show the view on desktop
         // menu item.
--- a/browser/metro/base/content/browser.xul
+++ b/browser/metro/base/content/browser.xul
@@ -783,16 +783,19 @@
 
           <!-- standard buttons -->
           <richlistitem id="context-findinpage" type="find-in-page" onclick="ContextCommands.findInPage();">
             <label value="&appbarFindInPage2.label;"/>
           </richlistitem>
           <richlistitem id="context-viewondesktop" type="view-on-desktop" onclick="ContextCommands.viewOnDesktop();">
             <label value="&appbarViewOnDesktop2.label;"/>
           </richlistitem>
+          <richlistitem id="context-msmetadata" type="ms-meta-data" onclick="ContextCommands.openWindowsStoreLink();">
+            <label value="&appbarMSMetaData2.label;"/>
+          </richlistitem>
         </richlistbox>
       </vbox>
     </box>
 
     <vbox id="select-container" class="menu-container" hidden="true">
       <vbox id="select-popup" class="select-popup">
         <richlistbox id="select-commands" flex="1"/>
       </vbox>
--- a/browser/metro/locales/en-US/chrome/browser.dtd
+++ b/browser/metro/locales/en-US/chrome/browser.dtd
@@ -12,16 +12,17 @@
 <!ENTITY closetab.label        "Close Tab">
 
 <!ENTITY autocompleteResultsHeader.label  "Your Results">
 
 <!ENTITY appbarErrorConsole.label   "Open error console">
 <!ENTITY appbarJSShell.label        "Open JavaScript shell">
 <!ENTITY appbarFindInPage2.label    "Find in page">
 <!ENTITY appbarViewOnDesktop2.label "View on desktop">
+<!ENTITY appbarMSMetaData2.label    "Get app for this site">
 
 <!ENTITY topSitesHeader.label        "Top Sites">
 <!ENTITY bookmarksHeader.label       "Bookmarks">
 <!ENTITY recentHistoryHeader.label   "Recent History">
 <!ENTITY remoteTabsHeader.label      "Tabs from Other Devices">
 
 <!-- LOCALIZATION NOTE (narrowTopSitesHeader.label,
                         narrowBookmarksHeader.label,
--- a/build/docs/conf.py
+++ b/build/docs/conf.py
@@ -14,24 +14,24 @@ here = os.path.abspath(os.path.dirname(_
 mozilla_dir = os.path.normpath(os.path.join(here, '..', '..'))
 
 import mdn_theme
 
 extensions = [
     'sphinx.ext.autodoc',
     'sphinx.ext.graphviz',
     'sphinx.ext.todo',
+    'mozbuild.sphinx',
 ]
 
 templates_path = ['_templates']
 source_suffix = '.rst'
 master_doc = 'index'
 project = u'Mozilla Build System'
 year = datetime.now().year
-copyright = u'%s, Mozilla Foundation, CC BY-SA 3.0 or any later version' % year
 
 # Grab the version from the source tree's milestone.
 with open(os.path.join(mozilla_dir, 'config', 'milestone.txt'), 'rt') as fh:
     for line in fh:
         line = line.strip()
 
         if not line or line.startswith('#'):
             continue
--- a/build/docs/index.rst
+++ b/build/docs/index.rst
@@ -13,16 +13,17 @@ Overview
 Important Concepts
 ==================
 .. toctree::
    :maxdepth: 1
 
    build-overview
    Mozconfig Files <mozconfigs>
    mozbuild-files
+   mozbuild-symbols
    Profile Guided Optimization <pgo>
    slow
    environment-variables
    build-targets
    python
    test_manifests
    mozinfo
    preprocessor
@@ -35,16 +36,28 @@ mozbuild is a Python package containing 
 Mozilla build system.
 
 .. toctree::
    :maxdepth: 1
 
    mozbuild/index
    mozbuild/dumbmake
 
+Python Packages
+===============
+
+.. toctree::
+   :maxdepth: 2
+
+   python/codegen
+   python/makeutils
+   python/mozbuild
+   python/mozpack
+   python/mozversioncontrol
+
 
 Indices and tables
 ==================
 
 * :ref:`genindex`
 * :ref:`modindex`
 * :ref:`search`
 
new file mode 100644
--- /dev/null
+++ b/build/docs/mozbuild-symbols.rst
@@ -0,0 +1,7 @@
+.. _mozbuild_symbols:
+
+========================
+mozbuild Sandbox Symbols
+========================
+
+.. mozbuildsymbols:: mozbuild.frontend.sandbox_symbols
new file mode 100644
--- /dev/null
+++ b/build/docs/python/makeutils.rst
@@ -0,0 +1,7 @@
+makeutils Module
+================
+
+.. automodule:: makeutils
+    :members:
+    :undoc-members:
+    :show-inheritance:
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozbuild.action.rst
@@ -0,0 +1,35 @@
+action Package
+==============
+
+:mod:`link_deps` Module
+-----------------------
+
+.. automodule:: mozbuild.action.link_deps
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`process_install_manifest` Module
+--------------------------------------
+
+.. automodule:: mozbuild.action.process_install_manifest
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`xpccheck` Module
+----------------------
+
+.. automodule:: mozbuild.action.xpccheck
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`xpidl-process` Module
+---------------------------
+
+.. automodule:: mozbuild.action.xpidl-process
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozbuild.backend.rst
@@ -0,0 +1,35 @@
+backend Package
+===============
+
+:mod:`base` Module
+------------------
+
+.. automodule:: mozbuild.backend.base
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`common` Module
+--------------------
+
+.. automodule:: mozbuild.backend.common
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`configenvironment` Module
+-------------------------------
+
+.. automodule:: mozbuild.backend.configenvironment
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`recursivemake` Module
+---------------------------
+
+.. automodule:: mozbuild.backend.recursivemake
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozbuild.compilation.rst
@@ -0,0 +1,11 @@
+compilation Package
+===================
+
+:mod:`warnings` Module
+----------------------
+
+.. automodule:: mozbuild.compilation.warnings
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozbuild.controller.rst
@@ -0,0 +1,19 @@
+controller Package
+==================
+
+:mod:`building` Module
+----------------------
+
+.. automodule:: mozbuild.controller.building
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`clobber` Module
+---------------------
+
+.. automodule:: mozbuild.controller.clobber
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozbuild.frontend.rst
@@ -0,0 +1,51 @@
+frontend Package
+================
+
+:mod:`data` Module
+------------------
+
+.. automodule:: mozbuild.frontend.data
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`emitter` Module
+---------------------
+
+.. automodule:: mozbuild.frontend.emitter
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`mach_commands` Module
+---------------------------
+
+.. automodule:: mozbuild.frontend.mach_commands
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`reader` Module
+--------------------
+
+.. automodule:: mozbuild.frontend.reader
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`sandbox` Module
+---------------------
+
+.. automodule:: mozbuild.frontend.sandbox
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`sandbox_symbols` Module
+-----------------------------
+
+.. automodule:: mozbuild.frontend.sandbox_symbols
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozbuild.rst
@@ -0,0 +1,103 @@
+mozbuild Package
+================
+
+:mod:`base` Module
+------------------
+
+.. automodule:: mozbuild.base
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`config` Module
+--------------------
+
+.. automodule:: mozbuild.config
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`html_build_viewer` Module
+-------------------------------
+
+.. automodule:: mozbuild.html_build_viewer
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`mach_commands` Module
+---------------------------
+
+.. automodule:: mozbuild.mach_commands
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`makeutil` Module
+----------------------
+
+.. automodule:: mozbuild.makeutil
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`mozconfig` Module
+-----------------------
+
+.. automodule:: mozbuild.mozconfig
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`mozinfo` Module
+---------------------
+
+.. automodule:: mozbuild.mozinfo
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`pythonutil` Module
+------------------------
+
+.. automodule:: mozbuild.pythonutil
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`sphinx` Module
+--------------------
+
+.. automodule:: mozbuild.sphinx
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`util` Module
+------------------
+
+.. automodule:: mozbuild.util
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`virtualenv` Module
+------------------------
+
+.. automodule:: mozbuild.virtualenv
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+
+    mozbuild.action
+    mozbuild.backend
+    mozbuild.compilation
+    mozbuild.controller
+    mozbuild.frontend
+    mozbuild.test
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozpack.chrome.rst
@@ -0,0 +1,19 @@
+chrome Package
+==============
+
+:mod:`flags` Module
+-------------------
+
+.. automodule:: mozpack.chrome.flags
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`manifest` Module
+----------------------
+
+.. automodule:: mozpack.chrome.manifest
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozpack.packager.rst
@@ -0,0 +1,35 @@
+packager Package
+================
+
+:mod:`packager` Package
+-----------------------
+
+.. automodule:: mozpack.packager
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`formats` Module
+---------------------
+
+.. automodule:: mozpack.packager.formats
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`l10n` Module
+------------------
+
+.. automodule:: mozpack.packager.l10n
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`unpack` Module
+--------------------
+
+.. automodule:: mozpack.packager.unpack
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozpack.rst
@@ -0,0 +1,76 @@
+mozpack Package
+===============
+
+:mod:`copier` Module
+--------------------
+
+.. automodule:: mozpack.copier
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`errors` Module
+--------------------
+
+.. automodule:: mozpack.errors
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`executables` Module
+-------------------------
+
+.. automodule:: mozpack.executables
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`files` Module
+-------------------
+
+.. automodule:: mozpack.files
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`manifests` Module
+-----------------------
+
+.. automodule:: mozpack.manifests
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`mozjar` Module
+--------------------
+
+.. automodule:: mozpack.mozjar
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`path` Module
+------------------
+
+.. automodule:: mozpack.path
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+:mod:`unify` Module
+-------------------
+
+.. automodule:: mozpack.unify
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
+Subpackages
+-----------
+
+.. toctree::
+
+    mozpack.chrome
+    mozpack.packager
+    mozpack.test
+
new file mode 100644
--- /dev/null
+++ b/build/docs/python/mozversioncontrol.rst
@@ -0,0 +1,11 @@
+mozversioncontrol Package
+=========================
+
+:mod:`repoupdate` Module
+------------------------
+
+.. automodule:: mozversioncontrol.repoupdate
+    :members:
+    :undoc-members:
+    :show-inheritance:
+
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -47,16 +47,17 @@ SEARCH_PATHS = [
     'testing/mozbase/mozhttpd',
     'testing/mozbase/mozlog',
     'testing/mozbase/moznetwork',
     'testing/mozbase/mozprocess',
     'testing/mozbase/mozprofile',
     'testing/mozbase/mozrunner',
     'testing/mozbase/mozsystemmonitor',
     'testing/mozbase/mozinfo',
+    'testing/mozbase/moztest',
     'testing/mozbase/manifestdestiny',
     'xpcom/idl-parser',
 ]
 
 # Individual files providing mach commands.
 MACH_MODULES = [
     'addon-sdk/mach_commands.py',
     'layout/tools/reftest/mach_commands.py',
--- a/config/baseconfig.mk
+++ b/config/baseconfig.mk
@@ -1,13 +1,18 @@
 includedir := $(includedir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
 idldir = $(datadir)/idl/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
 installdir = $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
 sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION)
-DIST = $(DEPTH)/dist
+
+ifndef INCLUDED_FUNCTIONS_MK
+include $(topsrcdir)/config/makefiles/functions.mk
+endif
+
+DIST := $(call core_realpath,$(DEPTH)/dist)
 
 # We do magic with OBJ_SUFFIX in config.mk, the following ensures we don't
 # manually use it before config.mk inclusion
 _OBJ_SUFFIX := $(OBJ_SUFFIX)
 OBJ_SUFFIX = $(error config/config.mk needs to be included before using OBJ_SUFFIX)
 
 # We only want to do the pymake sanity on Windows, other os's can cope
 ifeq ($(HOST_OS_ARCH),WINNT)
--- a/config/config.mk
+++ b/config/config.mk
@@ -59,20 +59,16 @@ CHECK_VARS := \
  $(NULL)
 
 # checks for internal spaces or trailing spaces in the variable
 # named by $x
 check-variable = $(if $(filter-out 0 1,$(words $($(x))z)),$(error Spaces are not allowed in $(x)))
 
 $(foreach x,$(CHECK_VARS),$(check-variable))
 
-ifndef INCLUDED_FUNCTIONS_MK
-include $(topsrcdir)/config/makefiles/functions.mk
-endif
-
 RM = rm -f
 
 # LIBXUL_DIST is not defined under js/src, thus we make it mean DIST there.
 LIBXUL_DIST ?= $(DIST)
 
 # FINAL_TARGET specifies the location into which we copy end-user-shipped
 # build products (typelibs, components, chrome).
 #
--- a/configure.in
+++ b/configure.in
@@ -3499,17 +3499,16 @@ MALLOC_H=
 for file in $MALLOC_HEADERS; do
   MOZ_CHECK_HEADER($file, [MALLOC_H=$file])
   if test "$MALLOC_H" != ""; then
     AC_DEFINE_UNQUOTED(MALLOC_H, <$MALLOC_H>)
     break
   fi
 done
 
-MOZ_ALLOCATING_FUNCS="strndup posix_memalign memalign valloc"
 AC_CHECK_FUNCS(strndup posix_memalign memalign valloc)
 
 AC_CHECK_FUNCS(malloc_usable_size)
 
 dnl See if compiler supports some gcc-style attributes
 
 AC_CACHE_CHECK(for __attribute__((always_inline)),
                ac_cv_attribute_always_inline,
@@ -4010,17 +4009,16 @@ MOZ_OPUS=1
 MOZ_WEBM=1
 MOZ_DASH=
 MOZ_DIRECTSHOW=
 MOZ_WMF=
 MOZ_WEBRTC=1
 MOZ_PEERCONNECTION=
 MOZ_SRTP=
 MOZ_WEBRTC_SIGNALING=
-MOZ_WEBRTC_IN_LIBXUL=
 MOZ_WEBRTC_ASSERT_ALWAYS=1
 MOZ_SCTP=
 MOZ_MEDIA_PLUGINS=
 MOZ_MEDIA_NAVIGATOR=
 MOZ_OMX_PLUGIN=
 MOZ_VP8=
 MOZ_VP8_ERROR_CONCEALMENT=
 MOZ_VP8_ENCODER=
@@ -5187,33 +5185,29 @@ if test -n "$MOZ_WEBRTC"; then
     MOZ_RAW=1
     MOZ_VP8=1
     MOZ_VP8_ENCODER=1
     MOZ_VP8_ERROR_CONCEALMENT=1
 
 dnl enable once Signaling lands
     MOZ_WEBRTC_SIGNALING=1
     AC_DEFINE(MOZ_WEBRTC_SIGNALING)
-    if test "${OS_TARGET}" = "WINNT"; then
-        MOZ_WEBRTC_IN_LIBXUL=1
-    fi
 dnl enable once PeerConnection lands
     MOZ_PEERCONNECTION=1
     AC_DEFINE(MOZ_PEERCONNECTION)
     MOZ_SCTP=1
     MOZ_SRTP=1
     AC_DEFINE(MOZ_SCTP)
     AC_DEFINE(MOZ_SRTP)
 fi
 
 AC_SUBST(MOZ_WEBRTC)
 AC_SUBST(MOZ_WEBRTC_LEAKING_TESTS)
 AC_SUBST(MOZ_WEBRTC_SIGNALING)
 AC_SUBST(MOZ_PEERCONNECTION)
-AC_SUBST(MOZ_WEBRTC_IN_LIBXUL)
 AC_SUBST(MOZ_WEBRTC_ASSERT_ALWAYS)
 AC_SUBST(MOZ_SCTP)
 AC_SUBST(MOZ_SRTP)
 
 dnl Use integers over floats for audio on B2G and Android, because audio
 dnl backends for those platforms don't support floats.
 if test "$OS_TARGET" = "Android"; then
     MOZ_SAMPLE_TYPE_S16=1
@@ -7148,17 +7142,17 @@ fi
 
 dnl ========================================================
 dnl Zealous JavaScript GC
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(gczeal,
 [  --enable-gczeal         Enable zealous JavaScript GCing],
     JS_GC_ZEAL=1,
     JS_GC_ZEAL= )
-if test -n "$JS_GC_ZEAL"; then
+if test -n "$JS_GC_ZEAL" -o -n "$MOZ_DEBUG"; then
     AC_DEFINE(JS_GC_ZEAL)
 fi
 
 dnl ========================================================
 dnl JS opt-mode assertions and minidump instrumentation
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(js-diagnostics,
 [  --enable-js-diagnostics
--- a/content/base/src/nsContentPolicy.cpp
+++ b/content/base/src/nsContentPolicy.cpp
@@ -112,17 +112,18 @@ nsContentPolicy::CheckPolicy(CPMethod   
         }
     }
 
     /* 
      * Enumerate mPolicies and ask each of them, taking the logical AND of
      * their permissions.
      */
     nsresult rv;
-    const nsCOMArray<nsIContentPolicy>& entries = mPolicies.GetEntries();
+    nsCOMArray<nsIContentPolicy> entries;
+    mPolicies.GetEntries(entries);
     int32_t count = entries.Count();
     for (int32_t i = 0; i < count; i++) {
         /* check the appropriate policy */
         rv = (entries[i]->*policyMethod)(contentType, contentLocation,
                                          requestingLocation, requestingContext,
                                          mimeType, extra, requestPrincipal,
                                          decision);
 
--- a/content/base/src/nsDOMDataChannel.cpp
+++ b/content/base/src/nsDOMDataChannel.cpp
@@ -16,32 +16,39 @@
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetDataChannelLog();
 #endif
 #undef LOG
 #define LOG(args) PR_LOG(GetDataChannelLog(), PR_LOG_DEBUG, args)
 
 
 #include "nsDOMDataChannelDeclarations.h"
+#include "nsDOMDataChannel.h"
 #include "nsIDOMFile.h"
 #include "nsIDOMDataChannel.h"
 #include "nsIDOMMessageEvent.h"
 #include "nsDOMEventTargetHelper.h"
 
 #include "nsError.h"
 #include "nsAutoPtr.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsNetUtil.h"
 #include "nsDOMFile.h"
 
 #include "DataChannel.h"
 
+// Since we've moved the windows.h include down here, we have to explicitly
+// undef GetBinaryType, otherwise we'll get really odd conflicts
+#ifdef GetBinaryType
+#undef GetBinaryType
+#endif
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsDOMDataChannel::~nsDOMDataChannel()
 {
   // Don't call us anymore!  Likely isn't an issue (or maybe just less of
   // one) once we block GC until all the (appropriate) onXxxx handlers
   // are dropped. (See WebRTC spec)
@@ -68,16 +75,23 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_ADDREF_INHERITED(nsDOMDataChannel, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsDOMDataChannel, nsDOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsDOMDataChannel)
   NS_INTERFACE_MAP_ENTRY(nsIDOMDataChannel)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
+nsDOMDataChannel::nsDOMDataChannel(already_AddRefed<mozilla::DataChannel> aDataChannel)
+  : mDataChannel(aDataChannel)
+  , mBinaryType(DC_BINARY_TYPE_BLOB)
+{
+  SetIsDOMBinding();
+}
+
 nsresult
 nsDOMDataChannel::Init(nsPIDOMWindow* aDOMWindow)
 {
   nsresult rv;
   nsAutoString urlParam;
 
   MOZ_ASSERT(mDataChannel);
   mDataChannel->SetListener(this, nullptr);
--- a/content/base/src/nsDOMDataChannel.h
+++ b/content/base/src/nsDOMDataChannel.h
@@ -5,32 +5,32 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsDOMDataChannel_h
 #define nsDOMDataChannel_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/DataChannelBinding.h"
 #include "mozilla/dom/TypedArray.h"
-#include "mozilla/net/DataChannel.h"
+#include "mozilla/net/DataChannelListener.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMDataChannel.h"
+#include "nsIInputStream.h"
+
+
+namespace mozilla {
+class DataChannel;
+};
 
 class nsDOMDataChannel : public nsDOMEventTargetHelper,
                          public nsIDOMDataChannel,
                          public mozilla::DataChannelListener
 {
 public:
-  nsDOMDataChannel(already_AddRefed<mozilla::DataChannel> aDataChannel)
-    : mDataChannel(aDataChannel)
-    , mBinaryType(DC_BINARY_TYPE_BLOB)
-  {
-    SetIsDOMBinding();
-  }
-
+  nsDOMDataChannel(already_AddRefed<mozilla::DataChannel> aDataChannel);
   ~nsDOMDataChannel();
 
   nsresult Init(nsPIDOMWindow* aDOMWindow);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMDATACHANNEL
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -499,17 +499,18 @@ nsFrameLoader::ReallyStartLoadingInterna
   if (OwnerIsBrowserFrame()) {
     flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
             nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER;
   }
 
   // Kick off the load...
   bool tmpState = mNeedsAsyncDestroy;
   mNeedsAsyncDestroy = true;
-  rv = mDocShell->LoadURI(mURIToLoad, loadInfo, flags, false);
+  nsCOMPtr<nsIURI> uriToLoad = mURIToLoad;
+  rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false);
   mNeedsAsyncDestroy = tmpState;
   mURIToLoad = nullptr;
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -715,17 +715,16 @@ GK_ATOM(onfrequencychange, "onfrequencyc
 GK_ATOM(onget, "onget")
 GK_ATOM(ongroupchange, "ongroupchange")
 GK_ATOM(onhashchange, "onhashchange")
 GK_ATOM(onheadphoneschange, "onheadphoneschange")
 GK_ATOM(onheld, "onheld")
 GK_ATOM(onhfpstatuschanged, "onhfpstatuschanged")
 GK_ATOM(onholding, "onholding")
 GK_ATOM(oniccinfochange, "oniccinfochange")
-GK_ATOM(onicccardlockerror, "onicccardlockerror")
 GK_ATOM(onincoming, "onincoming")
 GK_ATOM(oninput, "oninput")
 GK_ATOM(oninvalid, "oninvalid")
 GK_ATOM(onkeydown, "onkeydown")
 GK_ATOM(onkeypress, "onkeypress")
 GK_ATOM(onkeyup, "onkeyup")
 GK_ATOM(onlevelchange, "onlevelchange")
 GK_ATOM(onLoad, "onLoad")
--- a/content/canvas/test/webgl/non-conf-tests/mochitest.ini
+++ b/content/canvas/test/webgl/non-conf-tests/mochitest.ini
@@ -1,8 +1,9 @@
 [DEFAULT]
 support-files =
   driver-info.js
   webgl-util.js
 
+[test_highp_fs.html]
 [test_webgl_available.html]
 [test_webgl_conformance.html]
 [test_webgl_request_mismatch.html]
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/webgl/non-conf-tests/test_highp_fs.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<title>WebGL test: `highp` support</title>
+<script src="/MochiKit/MochiKit.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css">
+<script src="driver-info.js"></script>
+<script src="webgl-util.js"></script>
+<script id="shader-vs" type="x-shader/x-vertex">
+
+void main(void) {
+  gl_Position = vec4(vec3(0.0), 1.0);
+}
+
+</script>
+<script id="shader-fs" type="x-shader/x-fragment">
+
+precision highp float;
+
+void main(void) {
+  gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+}
+
+</script>
+<body>
+<canvas id="c"></canvas>
+<script>
+
+// Give ourselves a scope to return early from:
+(function() {
+  var gl = WebGLUtil.getWebGL('c');
+  if (!gl) {
+    todo(false, 'WebGL is unavailable.');
+    return;
+  }
+
+  // Catch actual WebGLUtil errors, not GL errors.
+  function errorFunc(str) {
+    ok(false, 'Error: ' + str);
+  }
+  WebGLUtil.setErrorFunc(errorFunc);
+
+  function checkGLError(func, info) {
+    var error = gl.getError();
+    var prefix = info ? ('[' + info + '] ') : ''
+    func(!error, prefix + 'gl.getError should be 0x0, was 0x' + error.toString(16) + '.');
+  }
+
+  var format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
+  var prog = WebGLUtil.createProgramByIds(gl, 'shader-vs', 'shader-fs');
+  checkGLError(ok);
+  
+  if (format) {
+    ok(prog, 'Frag shader with unconditional `precision highp float` should ' +
+             'link if `getShaderPrecisionFormat` gives a format for it.');
+  } else {
+    ok(!prog, 'Frag shader with unconditional `precision highp float` should ' +
+              'NOT link if `getShaderPrecisionFormat` gives NO format for it.');
+  }
+})();
+
+</script>
+
--- a/content/canvas/test/webgl/non-conf-tests/webgl-util.js
+++ b/content/canvas/test/webgl/non-conf-tests/webgl-util.js
@@ -1,26 +1,42 @@
 WebGLUtil = (function() {
   // ---------------------------------------------------------------------------
-  // Error handling
+  // Error handling (for obvious failures, such as invalid element ids)
 
   function defaultErrorFunc(str) {
     console.log('Error: ' + str);
   }
 
   var gErrorFunc = defaultErrorFunc;
   function setErrorFunc(func) {
     gErrorFunc = func;
   }
 
   function error(str) {
     gErrorFunc(str);
   }
 
   // ---------------------------------------------------------------------------
+  // Warning handling (for failures that may be intentional)
+
+  function defaultWarningFunc(str) {
+    console.log('Warning: ' + str);
+  }
+
+  var gWarningFunc = defaultWarningFunc;
+  function setWarningFunc(func) {
+    gWarningFunc = func;
+  }
+
+  function warning(str) {
+    gWarningFunc(str);
+  }
+
+  // ---------------------------------------------------------------------------
   // WebGL helpers
 
   function getWebGL(canvasId, requireConformant) {
     // `requireConformant` will default to falsey if it is not supplied.
 
     var canvas = document.getElementById(canvasId);
 
     var gl = null;
@@ -58,29 +74,29 @@ WebGLUtil = (function() {
   // Returns a valid shader, or null on errors.
   function createShaderById(gl, id) {
     var elem = document.getElementById(id);
     if (!elem) {
       error('Failed to create shader from non-existent id \'' + id + '\'.');
       return null;
     }
 
-    var src = getContentById(id);
+    var src = getContentFromElem(elem);
 
     var shader;
     if (elem.type == "x-shader/x-fragment") {
       shader = gl.createShader(gl.FRAGMENT_SHADER);
-    } else if (shaderScript.type == "x-shader/x-vertex") {
+    } else if (elem.type == "x-shader/x-vertex") {
       shader = gl.createShader(gl.VERTEX_SHADER);
     } else {
       error('Bad MIME type for shader \'' + id + '\': ' + elem.type + '.');
       return null;
     }
 
-    gl.shaderSource(shader, str);
+    gl.shaderSource(shader, src);
     gl.compileShader(shader);
 
     return shader;
   }
 
   function createProgramByIds(gl, vsId, fsId) {
     var vs = createShaderById(gl, vsId);
     var fs = createShaderById(gl, fsId);
@@ -88,27 +104,28 @@ WebGLUtil = (function() {
       return null;
 
     var prog = gl.createProgram();
     gl.attachShader(prog, vs);
     gl.attachShader(prog, fs);
     gl.linkProgram(prog);
 
     if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
-      var str = "Shader program linking failed:\n";
-      str += "Shader program info log:\n" + gl.getProgramInfoLog(prog) + "\n\n";
-      str += "Vert shader log:\n" + gl.getShaderInfoLog(vs) + "\n\n";
-      str += "Frag shader log:\n" + gl.getShaderInfoLog(fs);
-      error(str);
+      var str = "Shader program linking failed:";
+      str += "\nShader program info log:\n" + gl.getProgramInfoLog(prog);
+      str += "\n\nVert shader log:\n" + gl.getShaderInfoLog(vs);
+      str += "\n\nFrag shader log:\n" + gl.getShaderInfoLog(fs);
+      warning(str);
       return null;
     }
 
     return prog;
   }
 
   return {
     setErrorFunc: setErrorFunc,
+    setWarningFunc: setWarningFunc,
 
     getWebGL: getWebGL,
     createShaderById: createShaderById,
     createProgramByIds: createProgramByIds,
   };
 })();
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -264,81 +264,29 @@ struct DeltaValues
     deltaX(aEvent->deltaX), deltaY(aEvent->deltaY)
   {
   }
 
   double deltaX;
   double deltaY;
 };
 
-/******************************************************************/
-/* nsScrollbarsForWheel                                           */
-/******************************************************************/
-
-class nsScrollbarsForWheel {
-public:
-  static void PrepareToScrollText(nsEventStateManager* aESM,
-                                  nsIFrame* aTargetFrame,
-                                  WheelEvent* aEvent);
-  static void SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget);
-  // Hide all scrollbars (both mActiveOwner's and mActivatedScrollTargets')
-  static void MayInactivate();
-  static void Inactivate();
-  static bool IsActive();
-  static void OwnWheelTransaction(bool aOwn);
-
-protected:
-  static const size_t         kNumberOfTargets = 4;
-  static const DeltaValues    directions[kNumberOfTargets];
-  static nsWeakFrame          sActiveOwner;
-  static nsWeakFrame          sActivatedScrollTargets[kNumberOfTargets];
-  static bool                 sHadWheelStart;
-  static bool                 sOwnWheelTransaction;
-
-
-  /**
-   * These two methods are called upon NS_WHEEL_START/NS_WHEEL_STOP events
-   * to show/hide the right scrollbars.
-   */
-  static void TemporarilyActivateAllPossibleScrollTargets(
-                                  nsEventStateManager* aESM,
-                                  nsIFrame* aTargetFrame,
-                                  WheelEvent* aEvent);
-  static void DeactivateAllTemporarilyActivatedScrollTargets();
-};
-
-const DeltaValues nsScrollbarsForWheel::directions[kNumberOfTargets] = {
-  DeltaValues(-1, 0), DeltaValues(+1, 0), DeltaValues(0, -1), DeltaValues(0, +1)
-};
-nsWeakFrame nsScrollbarsForWheel::sActiveOwner = nullptr;
-nsWeakFrame nsScrollbarsForWheel::sActivatedScrollTargets[kNumberOfTargets] = {
-  nullptr, nullptr, nullptr, nullptr
-};
-bool nsScrollbarsForWheel::sHadWheelStart = false;
-bool nsScrollbarsForWheel::sOwnWheelTransaction = false;
-
-/******************************************************************/
-/* nsMouseWheelTransaction                                        */
-/******************************************************************/
-
 class nsMouseWheelTransaction {
 public:
   static nsIFrame* GetTargetFrame() { return sTargetFrame; }
   static void BeginTransaction(nsIFrame* aTargetFrame,
                                WheelEvent* aEvent);
   // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
   // frame might be destroyed in the event handler.
   static bool UpdateTransaction(WheelEvent* aEvent);
-  static void MayEndTransaction();
   static void EndTransaction();
   static void OnEvent(WidgetEvent* aEvent);
   static void Shutdown();
   static uint32_t GetTimeoutTime();
 
-  static void OwnScrollbars(bool aOwn);
 
   static DeltaValues AccelerateWheelDelta(WheelEvent* aEvent,
                                           bool aAllowScrollSpeedOverride);
 
   enum {
     kScrollSeriesTimeout = 80
   };
 protected:
@@ -346,78 +294,66 @@ protected:
   static void OnFailToScrollTarget();
   static void OnTimeout(nsITimer *aTimer, void *aClosure);
   static void SetTimeout();
   static uint32_t GetIgnoreMoveDelayTime();
   static int32_t GetAccelerationStart();
   static int32_t GetAccelerationFactor();
   static DeltaValues OverrideSystemScrollSpeed(WheelEvent* aEvent);
   static double ComputeAcceleratedWheelDelta(double aDelta, int32_t aFactor);
-  static bool OutOfTime(uint32_t aBaseTime, uint32_t aThreshold);
 
   static nsWeakFrame sTargetFrame;
   static uint32_t    sTime;        // in milliseconds
   static uint32_t    sMouseMoved;  // in milliseconds
   static nsITimer*   sTimer;
   static int32_t     sScrollSeriesCounter;
-  static bool        sOwnScrollbars;
 };
 
 nsWeakFrame nsMouseWheelTransaction::sTargetFrame(nullptr);
 uint32_t    nsMouseWheelTransaction::sTime        = 0;
 uint32_t    nsMouseWheelTransaction::sMouseMoved  = 0;
 nsITimer*   nsMouseWheelTransaction::sTimer       = nullptr;
 int32_t     nsMouseWheelTransaction::sScrollSeriesCounter = 0;
-bool        nsMouseWheelTransaction::sOwnScrollbars = false;
+
+static bool
+OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
+{
+  uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
+  return (now - aBaseTime > aThreshold);
+}
 
 static bool
 CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, double aDirection)
 {
   return aDirection > 0.0 ? aValue < static_cast<double>(aMax) :
                             static_cast<double>(aMin) < aValue;
 }
 
 static bool
-CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDirectionX, double aDirectionY)
+CanScrollOn(nsIScrollableFrame* aScrollFrame, double aDeltaX, double aDeltaY)
 {
   MOZ_ASSERT(aScrollFrame);
-  NS_ASSERTION(aDirectionX || aDirectionY,
+  NS_ASSERTION(aDeltaX || aDeltaY,
                "One of the delta values must be non-zero at least");
 
   nsPoint scrollPt = aScrollFrame->GetScrollPosition();
   nsRect scrollRange = aScrollFrame->GetScrollRange();
   uint32_t directions = aScrollFrame->GetPerceivedScrollingDirections();
 
-  return (aDirectionX && (directions & nsIScrollableFrame::HORIZONTAL) &&
-          CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDirectionX)) ||
-         (aDirectionY && (directions & nsIScrollableFrame::VERTICAL) &&
-          CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDirectionY));
-}
-
-bool
-nsMouseWheelTransaction::OutOfTime(uint32_t aBaseTime, uint32_t aThreshold)
-{
-  uint32_t now = PR_IntervalToMilliseconds(PR_IntervalNow());
-  return (now - aBaseTime > aThreshold);
-}
-
-void
-nsMouseWheelTransaction::OwnScrollbars(bool aOwn)
-{
-  sOwnScrollbars = aOwn;
+  return (aDeltaX && (directions & nsIScrollableFrame::HORIZONTAL) &&
+          CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aDeltaX)) ||
+         (aDeltaY && (directions & nsIScrollableFrame::VERTICAL) &&
+          CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aDeltaY));
 }
 
 void
 nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
                                           WheelEvent* aEvent)
 {
   NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
-  MOZ_ASSERT(aEvent->message == NS_WHEEL_WHEEL,
-             "Transaction must be started with a wheel event");
-  nsScrollbarsForWheel::OwnWheelTransaction(false);
   sTargetFrame = aTargetFrame;
   sScrollSeriesCounter = 0;
   if (!UpdateTransaction(aEvent)) {
     NS_ERROR("BeginTransaction is called even cannot scroll the frame");
     EndTransaction();
   }
 }
 
@@ -445,37 +381,22 @@ nsMouseWheelTransaction::UpdateTransacti
   // 2. If the computer runs slowly by other processes eating the CPU resource,
   //    the event creation time doesn't keep real time.
   sTime = PR_IntervalToMilliseconds(PR_IntervalNow());
   sMouseMoved = 0;
   return true;
 }
 
 void
-nsMouseWheelTransaction::MayEndTransaction()
-{
-  if (!sOwnScrollbars && nsScrollbarsForWheel::IsActive()) {
-    nsScrollbarsForWheel::OwnWheelTransaction(true);
-  } else {
-    EndTransaction();
-  }
-}
-
-void
 nsMouseWheelTransaction::EndTransaction()
 {
   if (sTimer)
     sTimer->Cancel();
   sTargetFrame = nullptr;
   sScrollSeriesCounter = 0;
-  if (sOwnScrollbars) {
-    sOwnScrollbars = false;
-    nsScrollbarsForWheel::OwnWheelTransaction(false);
-    nsScrollbarsForWheel::Inactivate();
-  }
 }
 
 void
 nsMouseWheelTransaction::OnEvent(WidgetEvent* aEvent)
 {
   if (!sTargetFrame)
     return;
 
@@ -489,28 +410,28 @@ nsMouseWheelTransaction::OnEvent(WidgetE
   }
 
   switch (aEvent->message) {
     case NS_WHEEL_WHEEL:
       if (sMouseMoved != 0 &&
           OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
         // Terminate the current mousewheel transaction if the mouse moved more
         // than ignoremovedelay milliseconds ago
-        MayEndTransaction();
+        EndTransaction();
       }
       return;
     case NS_MOUSE_MOVE:
     case NS_DRAGDROP_OVER:
       if (IsMouseEventReal(aEvent)) {
         // If the cursor is moving to be outside the frame,
         // terminate the scrollwheel transaction.
         nsIntPoint pt = GetScreenPoint(static_cast<WidgetGUIEvent*>(aEvent));
         nsIntRect r = sTargetFrame->GetScreenRectExternal();
         if (!r.Contains(pt)) {
-          MayEndTransaction();
+          EndTransaction();
           return;
         }
 
         // If the cursor is moving inside the frame, and it is less than
         // ignoremovedelay milliseconds since the last scroll operation, ignore
         // the mouse move; otherwise, record the current mouse move time to be
         // checked later
         if (OutOfTime(sTime, GetIgnoreMoveDelayTime())) {
@@ -549,34 +470,33 @@ nsMouseWheelTransaction::OnFailToScrollT
     nsContentUtils::DispatchTrustedEvent(
                       sTargetFrame->GetContent()->OwnerDoc(),
                       sTargetFrame->GetContent(),
                       NS_LITERAL_STRING("MozMouseScrollFailed"),
                       true, true);
   }
   // The target frame might be destroyed in the event handler, at that time,
   // we need to finish the current transaction
-  if (!sTargetFrame) {
+  if (!sTargetFrame)
     EndTransaction();
-  }
 }
 
 void
 nsMouseWheelTransaction::OnTimeout(nsITimer* aTimer, void* aClosure)
 {
   if (!sTargetFrame) {
     // The transaction target was destroyed already
     EndTransaction();
     return;
   }
   // Store the sTargetFrame, the variable becomes null in EndTransaction.
   nsIFrame* frame = sTargetFrame;
   // We need to finish current transaction before DOM event firing. Because
   // the next DOM event might create strange situation for us.
-  MayEndTransaction();
+  EndTransaction();
 
   if (Preferences::GetBool("test.mousescroll", false)) {
     // This event is used for automated tests, see bug 442774.
     nsContentUtils::DispatchTrustedEvent(
                       frame->GetContent()->OwnerDoc(),
                       frame->GetContent(),
                       NS_LITERAL_STRING("MozMouseScrollTransactionTimeout"),
                       true, true);
@@ -701,137 +621,16 @@ nsMouseWheelTransaction::OverrideSystemS
   nsresult rv =
     widget->OverrideSystemMouseScrollSpeed(aEvent->deltaX, aEvent->deltaY,
                                            overriddenDeltaValues.deltaX,
                                            overriddenDeltaValues.deltaY);
   return NS_FAILED(rv) ? DeltaValues(aEvent) : overriddenDeltaValues;
 }
 
 /******************************************************************/
-/* nsScrollbarsForWheel                                           */
-/******************************************************************/
-
-void
-nsScrollbarsForWheel::PrepareToScrollText(
-                                  nsEventStateManager* aESM,
-                                  nsIFrame* aTargetFrame,
-                                  WheelEvent* aEvent)
-{
-  if (aEvent->message == NS_WHEEL_START) {
-    nsMouseWheelTransaction::OwnScrollbars(false);
-    if (!IsActive()) {
-      TemporarilyActivateAllPossibleScrollTargets(aESM, aTargetFrame, aEvent);
-      sHadWheelStart = true;
-    }
-  } else {
-    DeactivateAllTemporarilyActivatedScrollTargets();
-  }
-}
-
-void
-nsScrollbarsForWheel::SetActiveScrollTarget(nsIScrollableFrame* aScrollTarget)
-{
-  if (!sHadWheelStart) {
-    return;
-  }
-  nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(aScrollTarget);
-  if (!scrollbarOwner) {
-    return;
-  }
-  sHadWheelStart = false;
-  sActiveOwner = do_QueryFrame(aScrollTarget);
-  scrollbarOwner->ScrollbarActivityStarted();
-}
-
-void
-nsScrollbarsForWheel::MayInactivate()
-{
-  if (!sOwnWheelTransaction && nsMouseWheelTransaction::GetTargetFrame()) {
-    nsMouseWheelTransaction::OwnScrollbars(true);
-  } else {
-    Inactivate();
-  }
-}
-
-void
-nsScrollbarsForWheel::Inactivate()
-{
-  nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(sActiveOwner);
-  if (scrollbarOwner) {
-    scrollbarOwner->ScrollbarActivityStopped();
-  }
-  sActiveOwner = nullptr;
-  DeactivateAllTemporarilyActivatedScrollTargets();
-  if (sOwnWheelTransaction) {
-    sOwnWheelTransaction = false;
-    nsMouseWheelTransaction::OwnScrollbars(false);
-    nsMouseWheelTransaction::EndTransaction();
-  }
-}
-
-bool
-nsScrollbarsForWheel::IsActive()
-{
-  if (sActiveOwner) {
-    return true;
-  }
-  for (size_t i = 0; i < kNumberOfTargets; ++i) {
-    if (sActivatedScrollTargets[i]) {
-      return true;
-    }
-  }
-  return false;
-}
-
-void
-nsScrollbarsForWheel::OwnWheelTransaction(bool aOwn)
-{
-  sOwnWheelTransaction = aOwn;
-}
-
-void
-nsScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets(
-                                               nsEventStateManager* aESM,
-                                               nsIFrame* aTargetFrame,
-                                               WheelEvent* aEvent)
-{
-  for (size_t i = 0; i < kNumberOfTargets; i++) {
-    const DeltaValues *dir = &directions[i];
-    nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
-    MOZ_ASSERT(!*scrollTarget, "scroll target still temporarily activated!");
-    nsIScrollableFrame* target =
-      aESM->ComputeScrollTarget(aTargetFrame, dir->deltaX, dir->deltaY, aEvent, 
-                                nsEventStateManager::COMPUTE_DEFAULT_ACTION_TARGET);
-    if (target) {
-      nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(target);
-      if (scrollbarOwner) {
-        nsIFrame* targetFrame = do_QueryFrame(target);
-        *scrollTarget = targetFrame;
-        scrollbarOwner->ScrollbarActivityStarted();
-      }
-    }
-  }
-}
-
-void
-nsScrollbarsForWheel::DeactivateAllTemporarilyActivatedScrollTargets()
-{
-  for (size_t i = 0; i < kNumberOfTargets; i++) {
-    nsWeakFrame* scrollTarget = &sActivatedScrollTargets[i];
-    if (*scrollTarget) {
-      nsIScrollbarOwner* scrollbarOwner = do_QueryFrame(*scrollTarget);
-      if (scrollbarOwner) {
-        scrollbarOwner->ScrollbarActivityStopped();
-      }
-      *scrollTarget = nullptr;
-    }
-  }
-}
-
-/******************************************************************/
 /* nsEventStateManager                                            */
 /******************************************************************/
 
 nsEventStateManager::nsEventStateManager()
   : mLockCursor(0),
     mPreLockPoint(0,0),
     mCurrentTarget(nullptr),
     mLastMouseOverFrame(nullptr),
@@ -1173,30 +972,23 @@ nsEventStateManager::PreHandleEvent(nsPr
   case NS_KEY_UP:
     {
       nsIContent* content = GetFocusedContent();
       if (content)
         mCurrentTargetContent = content;
     }
     break;
   case NS_WHEEL_WHEEL:
-  case NS_WHEEL_START:
-  case NS_WHEEL_STOP:
     {
       NS_ASSERTION(aEvent->mFlags.mIsTrusted,
                    "Untrusted wheel event shouldn't be here");
 
       nsIContent* content = GetFocusedContent();
-      if (content) {
+      if (content)
         mCurrentTargetContent = content;
-      }
-
-      if (aEvent->message != NS_WHEEL_WHEEL) {
-        break;
-      }
 
       WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
       WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
 
       // If we won't dispatch a DOM event for this event, nothing to do anymore.
       if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
         break;
       }
@@ -2749,30 +2541,16 @@ nsEventStateManager::SendPixelScrollEven
                               &event, nullptr, aStatus);
 }
 
 nsIScrollableFrame*
 nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
                                          WheelEvent* aEvent,
                                          ComputeScrollTargetOptions aOptions)
 {
-  return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY,
-                             aEvent, aOptions);
-}
-
-// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
-// for which scrollbarowners to activate when two finger down on trackpad
-// and before any actual motion
-nsIScrollableFrame*
-nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
-                                         double aDirectionX,
-                                         double aDirectionY,
-                                         WheelEvent* aEvent,
-                                         ComputeScrollTargetOptions aOptions)
-{
   if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
     // If the user recently scrolled with the mousewheel, then they probably
     // want to scroll the same view as before instead of the view under the
     // cursor.  nsMouseWheelTransaction tracks the frame currently being
     // scrolled with the mousewheel. We consider the transaction ended when the
     // mouse moves more than "mousewheel.transaction.ignoremovedelay"
     // milliseconds after the last scroll operation, or any time the mouse moves
     // out of the frame, or when more than "mousewheel.transaction.timeout"
@@ -2786,24 +2564,24 @@ nsEventStateManager::ComputeScrollTarget
         return frameToScroll;
       }
     }
   }
 
   // If the event doesn't cause scroll actually, we cannot find scroll target
   // because we check if the event can cause scroll actually on each found
   // scrollable frame.
-  if (!aDirectionX && !aDirectionY) {
+  if (!aEvent->deltaX && !aEvent->deltaY) {
     return nullptr;
   }
 
   bool checkIfScrollableX =
-    aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
+    aEvent->deltaX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
   bool checkIfScrollableY =
-    aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
+    aEvent->deltaY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
 
   nsIScrollableFrame* frameToScroll = nullptr;
   nsIFrame* scrollFrame =
     !(aOptions & START_FROM_PARENT) ? aTargetFrame :
                                       GetParentFrameToScroll(aTargetFrame);
   for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
     // Check whether the frame wants to provide us with a scrollable view.
     frameToScroll = scrollFrame->GetScrollTargetFrame();
@@ -2821,17 +2599,18 @@ nsEventStateManager::ComputeScrollTarget
     if ((hiddenForV && hiddenForH) ||
         (checkIfScrollableY && !checkIfScrollableX && hiddenForV) ||
         (checkIfScrollableX && !checkIfScrollableY && hiddenForH)) {
       continue;
     }
 
     // For default action, we should climb up the tree if cannot scroll it
     // by the event actually.
-    bool canScroll = CanScrollOn(frameToScroll, aDirectionX, aDirectionY);
+    bool canScroll = CanScrollOn(frameToScroll,
+                                 aEvent->deltaX, aEvent->deltaY);
     // Comboboxes need special care.
     nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
     if (comboBox) {
       if (comboBox->IsDroppedDown()) {
         // Don't propagate to parent when drop down menu is active.
         return canScroll ? frameToScroll : nullptr;
       }
       // Always propagate when not dropped down (even if focused).
@@ -3386,61 +3165,43 @@ nsEventStateManager::PostHandleEvent(nsP
 
       nsIPresShell *shell = presContext->GetPresShell();
       if (shell) {
         nsRefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
         frameSelection->SetMouseDownState(false);
       }
     }
     break;
-  case NS_WHEEL_STOP:
-    {
-      MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
-      nsScrollbarsForWheel::MayInactivate();
-    }
-    break;
   case NS_WHEEL_WHEEL:
-  case NS_WHEEL_START:
     {
       MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
 
       if (*aStatus == nsEventStatus_eConsumeNoDefault) {
-        nsScrollbarsForWheel::Inactivate();
         break;
       }
 
       WheelEvent* wheelEvent = static_cast<WheelEvent*>(aEvent);
       switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
         case WheelPrefs::ACTION_SCROLL: {
+          if (!wheelEvent->deltaX && !wheelEvent->deltaY) {
+            break;
+          }
           // For scrolling of default action, we should honor the mouse wheel
           // transaction.
-          
-          nsScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent);
-          
-          if (aEvent->message != NS_WHEEL_WHEEL ||
-              (!wheelEvent->deltaX && !wheelEvent->deltaY)) {
-            break;
-          }
-
           nsIScrollableFrame* scrollTarget =
             ComputeScrollTarget(aTargetFrame, wheelEvent,
                                 COMPUTE_DEFAULT_ACTION_TARGET);
-
-          nsScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
-
           wheelEvent->overflowDeltaX = wheelEvent->deltaX;
           wheelEvent->overflowDeltaY = wheelEvent->deltaY;
-
           WheelPrefs::GetInstance()->
             CancelApplyingUserPrefsFromOverflowDelta(wheelEvent);
           if (scrollTarget) {
             DoScrollText(scrollTarget, wheelEvent);
           } else {
             nsMouseWheelTransaction::EndTransaction();
-            nsScrollbarsForWheel::Inactivate();
           }
           break;
         }
         case WheelPrefs::ACTION_HISTORY: {
           // If this event doesn't cause NS_MOUSE_SCROLL event or the direction
           // is oblique, don't perform history back/forward.
           int32_t intDelta = wheelEvent->GetPreferredIntDelta();
           if (!intDelta) {
--- a/content/events/src/nsEventStateManager.h
+++ b/content/events/src/nsEventStateManager.h
@@ -41,17 +41,16 @@ class TabParent;
 /*
  * Event listener manager
  */
 
 class nsEventStateManager : public nsSupportsWeakReference,
                             public nsIObserver
 {
   friend class nsMouseWheelTransaction;
-  friend class nsScrollbarsForWheel;
 public:
 
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint;
 
   nsEventStateManager();
   virtual ~nsEventStateManager();
@@ -553,22 +552,16 @@ protected:
       (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS | START_FROM_PARENT),
     COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS     =
       (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS | START_FROM_PARENT)
   };
   nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
                                           mozilla::WheelEvent* aEvent,
                                           ComputeScrollTargetOptions aOptions);
 
-  nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
-                                          double aDirectionX,
-                                          double aDirectionY,
-                                          mozilla::WheelEvent* aEvent,
-                                          ComputeScrollTargetOptions aOptions);
-
   /**
    * GetScrollAmount() returns the scroll amount in app uints of one line or
    * one page.  If the wheel event scrolls a page, returns the page width and
    * height.  Otherwise, returns line height for both its width and height.
    *
    * @param aScrollableFrame    A frame which will be scrolled by the event.
    *                            The result of ComputeScrollTarget() is
    *                            expected for this value.
--- a/content/events/test/test_all_synthetic_events.html
+++ b/content/events/test/test_all_synthetic_events.html
@@ -162,20 +162,16 @@ const kEventConstructors = {
   GamepadButtonEvent:                        { create: function (aName, aProps) {
                                                          return new GamepadButtonEvent(aName, aProps);
                                                        },
                                              },
   HashChangeEvent:                           { create: function (aName, aProps) {
                                                          return new HashChangeEvent(aName, aProps);
                                                        },
                                              },
-  IccCardLockErrorEvent:                     { create: function (aName, aProps) {
-                                                          return new IccCardLockErrorEvent(aName, aProps);
-                                                       },
-                                             },
   IDBVersionChangeEvent:                     { create: function (aName, aProps) {
                                                          return new IDBVersionChangeEvent(aName, aProps);
                                                        },
                                              },
   KeyEvent:                                  { create: function (aName, aProps) {
                                                          var e = document.createEvent("keyboardevent");
                                                          e.initKeyEvent(aName, aProps.bubbles, aProps.cancelable,
                                                                         aProps.view,
--- a/content/html/content/src/HTMLImageElement.cpp
+++ b/content/html/content/src/HTMLImageElement.cpp
@@ -313,16 +313,59 @@ HTMLImageElement::AfterSetAttr(int32_t a
       aValue && !aValue->IsEmptyString()) {
     // add the image to the hashtable as needed
     NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eAtom,
       "Expected atom value for name/id");
     mForm->AddImageElementToTable(this,
       nsDependentAtomString(aValue->GetAtomValue()));
   }
 
+  if (aNameSpaceID == kNameSpaceID_None &&
+      aName == nsGkAtoms::src &&
+      !aValue) {
+    CancelImageRequests(aNotify);
+  }
+
+  // If we plan to call LoadImage, we want to do it first so that the image load
+  // kicks off. But if aNotify is false, we are coming from the parser or some
+  // such place; we'll get bound after all the attributes have been set, so
+  // we'll do the image load from BindToTree. Skip the LoadImage call in that case.
+  if (aNotify &&
+      aNameSpaceID == kNameSpaceID_None &&
+      aName == nsGkAtoms::crossorigin) {
+    // We want aForce == true in this LoadImage call, because we want to force
+    // a new load of the image with the new cross origin policy.
+    nsAutoString uri;
+    GetAttr(kNameSpaceID_None, nsGkAtoms::src, uri);
+    LoadImage(uri, true, aNotify);
+  }
+
+  if (aNotify &&
+      aNameSpaceID == kNameSpaceID_None &&
+      aName == nsGkAtoms::src &&
+      aValue) {
+
+    // Prevent setting image.src by exiting early
+    if (nsContentUtils::IsImageSrcSetDisabled()) {
+      return NS_OK;
+    }
+
+    // A hack to get animations to reset. See bug 594771.
+    mNewRequestsWillNeedAnimationReset = true;
+
+    // Force image loading here, so that we'll try to load the image from
+    // network if it's set to be not cacheable...  If we change things so that
+    // the state gets in Element's attr-setting happen around this
+    // LoadImage call, we could start passing false instead of aNotify
+    // here.
+    LoadImage(aValue->GetStringValue(), true, aNotify);
+
+    mNewRequestsWillNeedAnimationReset = false;
+  }
+
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
                                             aValue, aNotify);
 }
 
 
 nsresult
 HTMLImageElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
@@ -382,54 +425,24 @@ HTMLImageElement::IsHTMLFocusable(bool a
   return false;
 }
 
 nsresult
 HTMLImageElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                           nsIAtom* aPrefix, const nsAString& aValue,
                           bool aNotify)
 {
-  // If we plan to call LoadImage, we want to do it first so that the
-  // image load kicks off _before_ the reflow triggered by the SetAttr.  But if
-  // aNotify is false, we are coming from the parser or some such place; we'll
-  // get bound after all the attributes have been set, so we'll do the
-  // image load from BindToTree.  Skip the LoadImage call in that case.
-  if (aNotify &&
-      aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
-
-    // Prevent setting image.src by exiting early
-    if (nsContentUtils::IsImageSrcSetDisabled()) {
-      return NS_OK;
-    }
-
-    // A hack to get animations to reset. See bug 594771.
-    mNewRequestsWillNeedAnimationReset = true;
-
-    // Force image loading here, so that we'll try to load the image from
-    // network if it's set to be not cacheable...  If we change things so that
-    // the state gets in Element's attr-setting happen around this
-    // LoadImage call, we could start passing false instead of aNotify
-    // here.
-    LoadImage(aValue, true, aNotify);
-
-    mNewRequestsWillNeedAnimationReset = false;
-  }
-    
   return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                        aNotify);
 }
 
 nsresult
 HTMLImageElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
                             bool aNotify)
 {
-  if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::src) {
-    CancelImageRequests(aNotify);
-  }
-
   return nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute, aNotify);
 }
 
 nsresult
 HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                              nsIContent* aBindingParent,
                              bool aCompileEventHandlers)
 {
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..df24ac6d3404325e473981930ade85065cf7fb9a
GIT binary patch
literal 844
zc$@)D1GD^zP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004b3#c}2nYxW
zd<bNS00009a7bBm000j<000lL0ajJ30{{R5?ny*JR5*=wlU-<Abr{Bf|C4iak|t@k
znyz1_UD|b9CpwyStJbl)wOETfHyJ}l1+P@RQUvu%@X{{?1uq7I;FT95IyVX`Q#a>W
zH*l4W#u<{PNz9VwG#}^W<0L1?t5qG#bM^8*@B6!Y9%v)~sZWR7dH<ET*YfDQ-@UD+
zw7tRIec8-L-Mt*iY#7<fwOXnA4VT_5w*{yN-Ve=&dp<aHa{PEAtBZKDNbK(-ZdJzT
zQE|zVCdrO>&b>bO@tq&Xo#Dw37Y`VD<Kh#CN5=CNOJw5(mJ@jtVdL&l@%vOP8+RtJ
z&-?ctbLE%5`f(HR;<r~jN?H9E>*5zZgOd|P&R*cpRtL#MfnqdAF}{lF@u3x}h-M2d
zU7YIQ_0*!aayBIc)N=ZX)vMQouRK=b_uDDdE|ux^&sgX-sRT#)>9+`tv>+u9Av<NN
zH&!Lt?|m7#A_FWft?lnDrFrzFXYnVh40Oei?E%6Er;(c#UOh3uYp1VZ$RV^?8d?IO
zDEj~*0VGy(s>c)Hp(D?+Cny*kpJ8n71zf|E=pEaMtqb<=?8Ppd$Yvc+rx&+J-U2uz
z01;V>&4(3AT8;+~%~LWAvbi!#=YJ*{T_H3YWP0WZTfGgoZNHzEaIlfcn1GN0gvI&w
zN*BH@U5I9l(LEzH^a4Bj2BEHF*LCd5I_~5-jNVg74nf&4Qh?<EFpbN})LQ@3xyYIR
zPFdqVpMu9JgK1#b%Gh-smzibpQk|8wO3N~-=l=MzS&e?b86;Qt!jxiGerS~A%I*=R
z@yu+m{`kRAU~H&cxUnde8-y2rWyAE+vdmhoa`|B>T>oDZ72o0K<(7D_Y2>a+IG1f<
z1;P(F$7ZLt?Xv8?z$c&I5RxR>Mm_V9#b0j#*4<qY;N0P0I3(fi5l8`OIrdGA%|vgd
z<`k!+naSNcZ4rM9(A$>jU)YfP$i(Ean>QmzT`s3}TZ?`T+8Lm6&oZ?KZQix+Hva+S
WQ#UA?9#7r?0000<MNUMnLSTYXW|E5l
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/image-allow-credentials.png^headers^
@@ -0,0 +1,2 @@
+Access-Control-Allow-Origin: http://mochi.test:8888
+Access-Control-Allow-Credentials: true
--- a/content/html/content/test/mochitest.ini
+++ b/content/html/content/test/mochitest.ini
@@ -122,16 +122,18 @@ support-files =
   file_iframe_sandbox_top_navigation_fail.html
   file_iframe_sandbox_top_navigation_pass.html
   file_iframe_sandbox_window_navigation_fail.html
   file_iframe_sandbox_worker.js
   file_srcdoc-2.html
   file_srcdoc.html
   form_submit_server.sjs
   image.png
+  image-allow-credentials.png
+  image-allow-credentials.png^headers^
   nnc_lockup.gif
   reflect.js
   wakelock.ogg
   wakelock.ogv
 
 [test_a_text.html]
 [test_anchor_href_cache_invalidation.html]
 [test_applet_attributes_reflection.html]
@@ -338,16 +340,17 @@ support-files =
 [test_bug840877.html]
 [test_bug841466.html]
 [test_bug869040.html]
 [test_bug870787.html]
 [test_bug874758.html]
 [test_bug879319.html]
 [test_bug885024.html]
 [test_bug893537.html]
+[test_change_crossorigin.html]
 [test_checked.html]
 [test_dir_attributes_reflection.html]
 [test_dl_attributes_reflection.html]
 [test_element_prototype.html]
 [test_embed_attributes_reflection.html]
 [test_formData.html]
 [test_formSubmission.html]
 [test_formSubmission2.html]
new file mode 100644
--- /dev/null
+++ b/content/html/content/test/test_change_crossorigin.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=696451
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 696451</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 696451 **/
+
+  SimpleTest.waitForExplicitFinish();
+
+  var img = new Image,
+      canvas = document.createElement("canvas"),
+      ctx = canvas.getContext("2d"),
+      src = "http://example.com/tests/content/html/content/test/image-allow-credentials.png",
+      imgDone = false,
+      imgNotAllowedToLoadDone = false;
+
+  img.src = src;
+  img.crossOrigin = "Anonymous";
+
+  img.addEventListener("load", function() {
+    canvas.width = img.width;
+    canvas.height = img.height;
+    ctx.drawImage( img, 0, 0 );
+    try {
+      canvas.toDataURL("image/png");
+      ok(true, "Image was refetched with setting crossOrigin.");
+    } catch (e) {
+      ok(false, "Image was not refetched after setting crossOrigin.");
+    }
+
+    imgDone = true;
+    if (imgDone && imgNotAllowedToLoadDone) {
+      SimpleTest.finish();
+    }
+  });
+
+  img.addEventListener("error", function (event) {
+    ok(false, "Should be able to load cross origin image with proper headers.");
+
+    imgDone = true;
+    if (imgDone && imgNotAllowedToLoadDone) {
+      SimpleTest.finish();
+    }
+  });
+
+  var imgNotAllowedToLoad = new Image;
+
+  imgNotAllowedToLoad.src = "http://example.com/tests/content/html/content/test/image.png";
+
+  imgNotAllowedToLoad.crossOrigin = "Anonymous";
+
+  imgNotAllowedToLoad.addEventListener("load", function() {
+      ok(false, "Image should not be allowed to load without " +
+                "allow-cross-origin-access headers.");
+
+      imgNotAllowedToLoadDone = true;
+      if (imgDone && imgNotAllowedToLoadDone) {
+        SimpleTest.finish();
+      }
+  });
+
+  imgNotAllowedToLoad.addEventListener("error", function() {
+      ok(true, "Image should not be allowed to load without " +
+               "allow-cross-origin-access headers.");
+      imgNotAllowedToLoadDone = true;
+      if (imgDone && imgNotAllowedToLoadDone) {
+        SimpleTest.finish();
+      }
+  });
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=696451">Mozilla Bug 696451</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/media/directshow/moz.build
+++ b/content/media/directshow/moz.build
@@ -21,17 +21,17 @@ CPP_SOURCES += [
     'DirectShowReader.cpp',
     'DirectShowUtils.cpp',
     'SampleSink.cpp',
     'SourceFilter.cpp',
 ]
 
 # If WebRTC isn't being built, we need to compile the DirectShow base classes so that
 # they're available at link time.
-if not CONFIG['MOZ_WEBRTC_IN_LIBXUL']:
+if not CONFIG['MOZ_WEBRTC']:
     CPP_SOURCES += [
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseFilter.cpp',
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BaseInputPin.cpp',
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/BasePin.cpp',
         TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/windows/MediaType.cpp',
     ]
 
 FAIL_ON_WARNINGS = True
--- a/docshell/base/nsAboutRedirector.cpp
+++ b/docshell/base/nsAboutRedirector.cpp
@@ -45,17 +45,18 @@ static RedirEntry kRedirMap[] = {
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "license", "chrome://global/content/license.html",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT },
     { "neterror", "chrome://global/content/netError.xhtml",
       nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
       nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT },
     { "compartments", "chrome://global/content/aboutCompartments.xhtml",
-      nsIAboutModule::ALLOW_SCRIPT },
+      nsIAboutModule::ALLOW_SCRIPT |
+      nsIAboutModule::HIDE_FROM_ABOUTABOUT },
     { "memory", "chrome://global/content/aboutMemory.xhtml",
       nsIAboutModule::ALLOW_SCRIPT },
     { "addons", "chrome://mozapps/content/extensions/extensions.xul",
       nsIAboutModule::ALLOW_SCRIPT },
     { "newaddon", "chrome://mozapps/content/extensions/newaddon.xul",
       nsIAboutModule::ALLOW_SCRIPT |
       nsIAboutModule::HIDE_FROM_ABOUTABOUT },
     { "support", "chrome://global/content/aboutSupport.xhtml",
--- a/dom/activities/src/ActivityProxy.js
+++ b/dom/activities/src/ActivityProxy.js
@@ -84,17 +84,17 @@ ActivityProxy.prototype = {
         break;
     }
     // We can only get one FireSuccess / FireError message, so cleanup as soon as possible.
     this.cleanup();
   },
 
   cleanup: function actProxy_cleanup() {
     debug("cleanup");
-    if (!this.cleanedUp) {
+    if (cpmm && !this.cleanedUp) {
       cpmm.removeMessageListener("Activity:FireSuccess", this);
       cpmm.removeMessageListener("Activity:FireError", this);
     }
     this.cleanedUp = true;
   },
 
   classID: Components.ID("{ba9bd5cb-76a0-4ecf-a7b3-d2f7c43c5949}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIActivityProxy])
--- a/dom/apps/src/OperatorApps.jsm
+++ b/dom/apps/src/OperatorApps.jsm
@@ -54,18 +54,16 @@ function isFirstRunWithSIM() {
 }
 
 #ifdef MOZ_B2G_RIL
 let iccListener = {
   notifyStkCommand: function() {},
 
   notifyStkSessionEnd: function() {},
 
-  notifyIccCardLockError: function() {},
-
   notifyCardStateChanged: function() {},
 
   notifyIccInfoChanged: function() {
     let iccInfo = iccProvider.iccInfo;
     if (iccInfo && iccInfo.mcc && iccInfo.mnc) {
       debug("******* iccListener cardIccInfo MCC-MNC: " + iccInfo.mcc +
             "-" + iccInfo.mnc);
       iccProvider.unregisterIccMsg(this);
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -49,23 +49,16 @@ IccListener::NotifyStkCommand(const nsAS
 
 NS_IMETHODIMP
 IccListener::NotifyStkSessionEnd()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IccListener::NotifyIccCardLockError(const nsAString & lockType,
-                                    uint32_t retryCount)
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 IccListener::NotifyCardStateChanged()
 {
   return NS_OK;
 }
 
 /**
  *  MobileConnectionListener
  */
--- a/dom/icc/interfaces/moz.build
+++ b/dom/icc/interfaces/moz.build
@@ -1,15 +1,14 @@
 # -*- 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/.
 
 XPIDL_SOURCES += [
     'SimToolKit.idl',
-    'nsIDOMIccCardLockErrorEvent.idl',
     'nsIDOMIccInfo.idl',
     'nsIDOMIccManager.idl',
     'nsIIccProvider.idl',
 ]
 
 XPIDL_MODULE = 'dom_icc'
deleted file mode 100644
--- a/dom/icc/interfaces/nsIDOMIccCardLockErrorEvent.idl
+++ /dev/null
@@ -1,24 +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/. */
-
-#include "nsIDOMEvent.idl"
-
-[scriptable, builtinclass, uuid(47d4db10-a258-11e2-9e96-0800200c9a66)]
-interface nsIDOMIccCardLockErrorEvent : nsIDOMEvent
-{
-  readonly attribute DOMString lockType;
-  readonly attribute long retryCount;
-
-  [noscript] void initIccCardLockErrorEvent(in DOMString aType,
-                                            in boolean aCanBubble,
-                                            in boolean aCancelable,
-                                            in DOMString aLockType,
-                                            in int32_t aRetryCount);
-};
-
-dictionary IccCardLockErrorEventInit : EventInit
-{
-  DOMString  lockType;
-  long       retryCount;
-};
--- a/dom/icc/interfaces/nsIDOMIccManager.idl
+++ b/dom/icc/interfaces/nsIDOMIccManager.idl
@@ -5,17 +5,17 @@
 #include "nsIDOMEventTarget.idl"
 #include "SimToolKit.idl"
 
 interface nsIDOMContact;
 interface nsIDOMDOMRequest;
 interface nsIDOMEventListener;
 interface nsIDOMMozIccInfo;
 
-[scriptable, builtinclass, uuid(904b92cb-dad3-416f-88cf-0291012cf448)]
+[scriptable, builtinclass, uuid(6b5875dc-de44-4681-84a1-9ea12d60fbe2)]
 interface nsIDOMMozIccManager : nsIDOMEventTarget
 {
   /**
    * STK Menu Presentation types.
    */
   const unsigned short STK_MENU_TYPE_NOT_SPECIFIED      = 0x00;
   const unsigned short STK_MENU_TYPE_DATA_VALUES        = 0x01;
   const unsigned short STK_MENU_TYPE_NAVIGATION_OPTIONS = 0x03;
@@ -454,26 +454,16 @@ interface nsIDOMMozIccManager : nsIDOMEv
    *     {
    *       lockType: "pin",
    *       success: true
    *     }
    */
   nsIDOMDOMRequest setCardLock(in jsval info);
 
   /**
-   * The 'icccardlockerror' event is notified whenever 'unlockCardLock' or
-   * 'setCardLock' fails.
-   *
-   * The result will be an object containing information
-   * about the specified lock's status,
-   * e.g. {lockType: "pin", retryCount: 2}.
-   */
-  [implicit_jscontext] attribute jsval onicccardlockerror;
-
-  /**
    * Retrieve the number of remaining tries for unlocking the card.
    *
    * @param lockType
    *        Identifies the lock type, e.g. "pin" for the PIN lock, "puk" for
    *        the PUK lock.
    *
    * @return a DOM Request.
    *         If the lock type is "pin", or "puk", the request's result will be
--- a/dom/icc/interfaces/nsIIccProvider.idl
+++ b/dom/icc/interfaces/nsIIccProvider.idl
@@ -4,23 +4,21 @@
 
 #include "nsISupports.idl"
 
 interface nsIDOMContact;
 interface nsIDOMDOMRequest;
 interface nsIDOMMozIccInfo;
 interface nsIDOMWindow;
 
-[scriptable, uuid(82d25440-c913-11e2-8b8b-0800200c9a66)]
+[scriptable, uuid(87e9ad03-e8e2-40d1-bf28-a6d287c31b93)]
 interface nsIIccListener : nsISupports
 {
   void notifyStkCommand(in DOMString aMessage);
   void notifyStkSessionEnd();
-  void notifyIccCardLockError(in DOMString lockType,
-                              in unsigned long retryCount);
   void notifyCardStateChanged();
   void notifyIccInfoChanged();
 };
 
 /**
  * XPCOM component (in the content process) that provides the ICC information.
  */
 [scriptable, uuid(52fa6780-c913-11e2-8b8b-0800200c9a66)]
--- a/dom/icc/src/IccManager.cpp
+++ b/dom/icc/src/IccManager.cpp
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Services.h"
 #include "nsIDOMClassInfo.h"
-#include "nsIDOMIccCardLockErrorEvent.h"
 #include "nsIDOMIccInfo.h"
 #include "GeneratedEvents.h"
 #include "IccManager.h"
 #include "SimToolKit.h"
 #include "StkCommandEvent.h"
 
 #define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
 
@@ -243,17 +242,16 @@ IccManager::UpdateContact(const nsAStrin
     return NS_ERROR_FAILURE;
   }
 
   return mProvider->UpdateContact(GetOwner(), aContactType, aContact, aPin2, aRequest);
 }
 
 NS_IMPL_EVENT_HANDLER(IccManager, stkcommand)
 NS_IMPL_EVENT_HANDLER(IccManager, stksessionend)
-NS_IMPL_EVENT_HANDLER(IccManager, icccardlockerror)
 NS_IMPL_EVENT_HANDLER(IccManager, cardstatechange)
 NS_IMPL_EVENT_HANDLER(IccManager, iccinfochange)
 
 // nsIIccListener
 
 NS_IMETHODIMP
 IccManager::NotifyStkCommand(const nsAString& aMessage)
 {
@@ -265,31 +263,16 @@ IccManager::NotifyStkCommand(const nsASt
 
 NS_IMETHODIMP
 IccManager::NotifyStkSessionEnd()
 {
   return DispatchTrustedEvent(NS_LITERAL_STRING("stksessionend"));
 }
 
 NS_IMETHODIMP
-IccManager::NotifyIccCardLockError(const nsAString& aLockType, uint32_t aRetryCount)
-{
-  nsCOMPtr<nsIDOMEvent> event;
-  NS_NewDOMIccCardLockErrorEvent(getter_AddRefs(event), this, nullptr, nullptr);
-
-  nsCOMPtr<nsIDOMIccCardLockErrorEvent> ce = do_QueryInterface(event);
-  nsresult rv =
-    ce->InitIccCardLockErrorEvent(NS_LITERAL_STRING("icccardlockerror"),
-                                  false, false, aLockType, aRetryCount);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return DispatchTrustedEvent(ce);
-}
-
-NS_IMETHODIMP
 IccManager::NotifyCardStateChanged()
 {
   return DispatchTrustedEvent(NS_LITERAL_STRING("cardstatechange"));
 }
 
 NS_IMETHODIMP
 IccManager::NotifyIccInfoChanged()
 {
--- a/dom/icc/tests/marionette/test_icc_card_lock.js
+++ b/dom/icc/tests/marionette/test_icc_card_lock.js
@@ -33,43 +33,24 @@ function testPinChangeFailed() {
      pin: "1111",
      newPin: "0000"});
 
   ok(request instanceof DOMRequest,
      "request instanceof " + request.constructor);
 
   request.onerror = function onerror() {
     is(request.error.name, "IncorrectPassword");
+    is(request.error.lockType, "pin");
+    // The default pin retries is 3, failed once becomes to 2
+    is(request.error.retryCount, 2);
 
     resetPinRetries("0000", runNextTest);
   };
 }
 
-/* Test PIN code changes fail notification */
-function testPinChangeFailedNotification() {
-  icc.addEventListener("icccardlockerror", function onicccardlockerror(result) {
-    icc.removeEventListener("icccardlockerror", onicccardlockerror);
-
-    is(result.lockType, "pin");
-    // The default pin retries is 3, failed once becomes to 2
-    is(result.retryCount, 2);
-
-    resetPinRetries("0000", runNextTest);
-  });
-
-  // The default pin is '0000' in emulator
-  let request = icc.setCardLock(
-    {lockType: "pin",
-     pin: "1111",
-     newPin: "0000"});
-
-  ok(request instanceof DOMRequest,
-     "request instanceof " + request.constructor);
-}
-
 /* Test PIN code changes success */
 function testPinChangeSuccess() {
   // The default pin is '0000' in emulator
   let request = icc.setCardLock(
     {lockType: "pin",
      pin: "0000",
      newPin: "0000"});
 
@@ -154,17 +135,16 @@ function testInvalidCardLockRetryCount()
     is(request.error.name, 'GenericFailure',
         'error name is ' + request.error.name);
     runNextTest();
   };
 }
 
 let tests = [
   testPinChangeFailed,
-  testPinChangeFailedNotification,
   testPinChangeSuccess,
   testPinCardLockRetryCount,
   testPukCardLockRetryCount,
   testInvalidCardLockRetryCount
 ];
 
 function runNextTest() {
   let test = tests.shift();
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -60,16 +60,18 @@ const VOICEMAILSTATUS_CID=
 const MOBILECFINFO_CID=
   Components.ID("{a4756f16-e728-4d9f-8baa-8464f894888a}");
 const CELLBROADCASTMESSAGE_CID =
   Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
 const CELLBROADCASTETWSINFO_CID =
   Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
 const DOMMMIERROR_CID =
   Components.ID("{6b204c42-7928-4e71-89ad-f90cd82aff96}");
+const ICCCARDLOCKERROR_CID =
+  Components.ID("{08a71987-408c-44ff-93fd-177c0a85c3dd}");
 
 const RIL_IPC_MSG_NAMES = [
   "RIL:CardStateChanged",
   "RIL:IccInfoChanged",
   "RIL:VoiceInfoChanged",
   "RIL:DataInfoChanged",
   "RIL:GetAvailableNetworks",
   "RIL:NetworkSelectionModeChanged",
@@ -427,16 +429,30 @@ DOMMMIError.prototype = {
                    message,
                    additionalInformation) {
     this.__DOM_IMPL__.init(name, message);
     this.serviceCode = serviceCode;
     this.additionalInformation = additionalInformation;
   },
 };
 
+function IccCardLockError() {
+}
+IccCardLockError.prototype = {
+  classDescription: "IccCardLockError",
+  classID:          ICCCARDLOCKERROR_CID,
+  contractID:       "@mozilla.org/dom/icccardlock-error;1",
+  QueryInterface:   XPCOMUtils.generateQI([Ci.nsISupports]),
+  __init: function(lockType, errorMsg, retryCount) {
+    this.__DOM_IMPL__.init(errorMsg);
+    this.lockType = lockType;
+    this.retryCount = retryCount;
+  },
+};
+
 function RILContentHelper() {
   this.rilContext = {
     cardState:            RIL.GECKO_CARDSTATE_UNKNOWN,
     networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN,
     iccInfo:              null,
     voiceConnectionInfo:  new MobileConnectionInfo(),
     dataConnectionInfo:   new MobileConnectionInfo()
   };
@@ -769,16 +785,18 @@ RILContentHelper.prototype = {
 
   getCardLockState: function getCardLockState(window, lockType) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
     let request = Services.DOMRequest.createRequest(window);
     let requestId = this.getRequestId(request);
+    this._windowsMap[requestId] = window;
+
     cpmm.sendAsyncMessage("RIL:GetCardLockState", {
       clientId: 0,
       data: {
         lockType: lockType,
         requestId: requestId
       }
     });
     return request;
@@ -786,30 +804,34 @@ RILContentHelper.prototype = {
 
   unlockCardLock: function unlockCardLock(window, info) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
     let request = Services.DOMRequest.createRequest(window);
     info.requestId = this.getRequestId(request);
+    this._windowsMap[info.requestId] = window;
+
     cpmm.sendAsyncMessage("RIL:UnlockCardLock", {
       clientId: 0,
       data: info
     });
     return request;
   },
 
   setCardLock: function setCardLock(window, info) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
     let request = Services.DOMRequest.createRequest(window);
     info.requestId = this.getRequestId(request);
+    this._windowsMap[info.requestId] = window;
+
     cpmm.sendAsyncMessage("RIL:SetCardLock", {
       clientId: 0,
       data: info
     });
     return request;
   },
 
   getCardLockRetryCount: function getCardLockRetryCount(window, lockType) {
@@ -1433,16 +1455,29 @@ RILContentHelper.prototype = {
 
   dispatchFireRequestError: function dispatchFireRequestError(requestId, error) {
     let currentThread = Services.tm.currentThread;
 
     currentThread.dispatch(this.fireRequestError.bind(this, requestId, error),
                            Ci.nsIThread.DISPATCH_NORMAL);
   },
 
+  fireRequestDetailedError: function fireRequestDetailedError(requestId, detailedError) {
+    let request = this.takeRequest(requestId);
+    if (!request) {
+      if (DEBUG) {
+        debug("not firing detailed error for id: " + requestId +
+              ", detailedError: " + JSON.stringify(detailedError));
+      }
+      return;
+    }
+
+    Services.DOMRequest.fireDetailedError(request, detailedError);
+  },
+
   receiveMessage: function receiveMessage(msg) {
     let request;
     debug("Received message '" + msg.name + "': " + JSON.stringify(msg.json));
 
     let data = msg.json.data;
     switch (msg.name) {
       case "RIL:CardStateChanged":
         if (this.rilContext.cardState != data.cardState) {
@@ -1490,30 +1525,37 @@ RILContentHelper.prototype = {
                                  RIL.GECKO_NETWORK_SELECTION_AUTOMATIC);
         break;
       case "RIL:VoicemailNotification":
         this.handleVoicemailNotification(data);
         break;
       case "RIL:VoicemailInfoChanged":
         this.updateInfo(data, this.voicemailInfo);
         break;
-      case "RIL:CardLockResult":
+      case "RIL:CardLockResult": {
+        let requestId = data.requestId;
+        let requestWindow = this._windowsMap[requestId];
+        delete this._windowsMap[requestId];
+
         if (data.success) {
           let result = new MobileIccCardLockResult(data);
-          this.fireRequestSuccess(data.requestId, result);
+          this.fireRequestSuccess(requestId, result);
         } else {
           if (data.rilMessageType == "iccSetCardLock" ||
               data.rilMessageType == "iccUnlockCardLock") {
-            this._deliverEvent("_iccListeners",
-                               "notifyIccCardLockError",
-                               [data.lockType, data.retryCount]);
+            let cardLockError = new requestWindow.IccCardLockError(data.lockType,
+                                                                   data.errorMsg,
+                                                                   data.retryCount);
+            this.fireRequestDetailedError(requestId, cardLockError);
+          } else {
+            this.fireRequestError(requestId, data.errorMsg);
           }
-          this.fireRequestError(data.requestId, data.errorMsg);
         }
         break;
+      }
       case "RIL:CardLockRetryCount":
         if (data.success) {
           let result = new MobileIccCardLockRetryCount(data);
           this.fireRequestSuccess(data.requestId, result);
         } else {
           this.fireRequestError(data.requestId, data.errorMsg);
         }
         break;
@@ -1921,10 +1963,11 @@ RILContentHelper.prototype = {
       return false;
     }
 
     return true;
   }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper,
-                                                     DOMMMIError]);
+                                                     DOMMMIError,
+                                                     IccCardLockError]);
 
--- a/dom/system/gonk/RadioInterfaceLayer.manifest
+++ b/dom/system/gonk/RadioInterfaceLayer.manifest
@@ -15,11 +15,13 @@
 # RadioInterfaceLayer.js
 component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js
 contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea}
 category profile-after-change RadioInterfaceLayer @mozilla.org/ril;1
 
 # RILContentHelper.js
 component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js
 component {6b204c42-7928-4e71-89ad-f90cd82aff96} RILContentHelper.js
+component {08a71987-408c-44ff-93fd-177c0a85c3dd} RILContentHelper.js
 contract @mozilla.org/ril/content-helper;1 {472816e1-1fd6-4405-996c-806f9ea68174}
 contract @mozilla.org/dom/mmi-error;1 {6b204c42-7928-4e71-89ad-f90cd82aff96}
+contract @mozilla.org/dom/icccardlock-error;1 {08a71987-408c-44ff-93fd-177c0a85c3dd}
 category profile-after-change RILContentHelper @mozilla.org/ril/content-helper;1
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1060,20 +1060,20 @@ let RIL = {
   },
 
   /**
    * Set screen state.
    *
    * @param on
    *        Boolean indicating whether the screen should be on or off.
    */
-  setScreenState: function setScreenState(on) {
+  setScreenState: function setScreenState(options) {
     Buf.newParcel(REQUEST_SCREEN_STATE);
     Buf.writeInt32(1);
-    Buf.writeInt32(on ? 1 : 0);
+    Buf.writeInt32(options.on ? 1 : 0);
     Buf.sendParcel();
   },
 
   getVoiceRegistrationState: function getVoiceRegistrationState() {
     Buf.simpleRequest(REQUEST_VOICE_REGISTRATION_STATE);
   },
 
   getVoiceRadioTechnology: function getVoiceRadioTechnology() {
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/marionette/test_screen_state.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 10000;
+
+let Services = SpecialPowers.Services;
+
+function testScreenState(on, expected, msg) {
+  // send event to RadioInterface
+  Services.obs.notifyObservers(null, 'screen-state-changed', on);
+  // maybe rild/qemu needs some time to process the event
+  window.setTimeout(function() {
+    runEmulatorCmd('gsm report creg', function(result) {
+      is(result.pop(), 'OK', '\'gsm report creg\' successful');
+      ok(result.indexOf(expected) !== -1, msg);
+      runNextTest();
+    })}, 1000);
+}
+
+function testScreenStateDisabled() {
+  testScreenState('off', '+CREG: 1', 'screen is disabled');
+}
+
+function testScreenStateEnabled() {
+  testScreenState('on', '+CREG: 2', 'screen is enabled');
+}
+
+let tests = [
+  testScreenStateDisabled,
+  testScreenStateEnabled
+];
+
+function runNextTest() {
+  let test = tests.shift();
+  if (!test) {
+    cleanUp();
+    return;
+  }
+
+  test();
+}
+
+function cleanUp() {
+  finish();
+}
+
+runNextTest();
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -275,17 +275,17 @@ var interfaceNamesInGlobalScope =
     "HTMLTableSectionElement",
     "HTMLTemplateElement",
     "HTMLTextAreaElement",
     "HTMLTimeElement",
     "HTMLTitleElement",
     "HTMLUListElement",
     "HTMLUnknownElement",
     "HTMLVideoElement",
-    {name: "IccCardLockErrorEvent", b2g: true},
+    {name: "IccCardLockError", b2g: true},
     "IDBCursor",
     "IDBCursorWithValue",
     "IDBDatabase",
     "IDBFactory",
     "IDBFileHandle",
     "IDBIndex",
     "IDBKeyRange",
     "IDBObjectStore",
new file mode 100644
--- /dev/null
+++ b/dom/webidl/IccCardLockError.webidl
@@ -0,0 +1,12 @@
+/* -*- Mode: IDL; 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/.
+*/
+
+[JSImplementation="@mozilla.org/dom/icccardlock-error;1",
+ Constructor(DOMString lockType, DOMString errorName, short retryCount)]
+interface IccCardLockError : DOMError {
+  readonly attribute DOMString lockType;
+  readonly attribute short retryCount;
+};
deleted file mode 100644
--- a/dom/webidl/IccCardLockErrorEvent.webidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: IDL; 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/.
- */
-
-[Constructor(DOMString type, optional IccCardLockErrorEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
-interface IccCardLockErrorEvent : Event
-{
-  readonly attribute DOMString? lockType;
-  readonly attribute long retryCount;
-};
-
-dictionary IccCardLockErrorEventInit : EventInit
-{
-  DOMString lockType = "";
-  long retryCount = 0;
-};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -499,17 +499,17 @@ if CONFIG['MOZ_B2G_BT']:
         'BluetoothManager.webidl',
         'BluetoothStatusChangedEvent.webidl',
     ]
 
 if CONFIG['MOZ_B2G_RIL']:
     WEBIDL_FILES += [
         'CFStateChangeEvent.webidl',
         'DataErrorEvent.webidl',
-        'IccCardLockErrorEvent.webidl',
+        'IccCardLockError.webidl',
         'MozCellBroadcast.webidl',
         'MozCellBroadcastEvent.webidl',
         'MozEmergencyCbModeEvent.webidl',
         'MozOtaStatusEvent.webidl',
         'MozVoicemailEvent.webidl',
         'MozWifiConnectionInfoEvent.webidl',
         'MozWifiStatusChangeEvent.webidl',
         'USSDReceivedEvent.webidl',
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -435,18 +435,20 @@ public:
       }
     }
 
     // May be null.
     nsIDocument* parentDoc = mWorkerPrivate->GetDocument();
 
     // Use the regular nsScriptLoader for this grunt work! Should be just fine
     // because we're running on the main thread.
+    // Unlike <script> tags, Worker scripts are always decoded as UTF-8,
+    // per spec. So we explicitly pass in the charset hint.
     rv = nsScriptLoader::ConvertToUTF16(aLoadInfo.mChannel, aString, aStringLen,
-                                        EmptyString(), parentDoc,
+                                        NS_LITERAL_STRING("UTF-8"), parentDoc,
                                         aLoadInfo.mScriptText);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     if (aLoadInfo.mScriptText.IsEmpty()) {
       return NS_ERROR_FAILURE;
     }
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/loadEncoding_worker.js
@@ -0,0 +1,7 @@
+/*
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+*/
+// Bug 484305 - Load workers as UTF-8.
+postMessage({ encoding: "KOI8-R", text: "" });
+postMessage({ encoding: "UTF-8", text: "Привет" });
--- a/dom/workers/test/mochitest.ini
+++ b/dom/workers/test/mochitest.ini
@@ -15,16 +15,17 @@ support-files =
   fibonacci_worker.js
   importScripts_worker.js
   importScripts_worker_imported1.js
   importScripts_worker_imported2.js
   importScripts_worker_imported3.js
   importScripts_worker_imported4.js
   instanceof_worker.js
   json_worker.js
+  loadEncoding_worker.js
   location_worker.js
   longThread_worker.js
   multi_sharedWorker_frame.html
   multi_sharedWorker_sharedWorker.js
   navigator_worker.js
   newError_worker.js
   recursion_worker.js
   recursiveOnerror_worker.js
@@ -68,16 +69,17 @@ support-files =
 [test_dataURLWorker.html]
 [test_errorPropagation.html]
 [test_errorwarning.html]
 [test_eventDispatch.html]
 [test_fibonacci.html]
 [test_importScripts.html]
 [test_instanceof.html]
 [test_json.html]
+[test_loadEncoding.html]
 [test_loadError.html]
 [test_location.html]
 [test_longThread.html]
 [test_multi_sharedWorker.html]
 [test_multi_sharedWorker_lifetimes.html]
 [test_navigator.html]
 [test_newError.html]
 [test_recursion.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/test_loadEncoding.html
@@ -0,0 +1,50 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 484305 - Load workers as UTF-8</title>
+  <meta http-equiv="content-type" content="text/html; charset=KOI8-R">
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=484305">Bug 484305 - Load workers as UTF-8</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+var canonical = String.fromCharCode(0x41F, 0x440, 0x438, 0x432, 0x435, 0x442);
+ok(document.inputEncoding === "KOI8-R", "Document encoding is KOI8-R");
+
+// Worker sends two strings, one with `canonical` encoded in KOI8-R and one as UTF-8.
+// Since Worker scripts should always be decoded using UTF-8, even if the owning document's charset is different, the UTF-8 decode should match, while KOI8-R should fail.
+var counter = 0;
+var worker = new Worker("loadEncoding_worker.js");
+worker.onmessage = function(e) {
+  if (e.data.encoding === "KOI8-R") {
+    ok(e.data.text !== canonical, "KOI8-R decoded text should not match");
+  } else if (e.data.encoding === "UTF-8") {
+    ok(e.data.text === canonical, "UTF-8 decoded text should match");
+  }
+  counter++;
+  if (counter === 2)
+    SimpleTest.finish();
+}
+
+worker.onerror = function(e) {
+  ok(false, "Worker error");
+  SimpleTest.finish();
+}
+</script>
+
+</pre>
+</body>
+</html>
--- a/embedding/components/find/src/nsWebBrowserFind.cpp
+++ b/embedding/components/find/src/nsWebBrowserFind.cpp
@@ -40,22 +40,16 @@
 #include "mozilla/dom/Element.h"
 #include "nsISimpleEnumerator.h"
 
 #if DEBUG
 #include "nsIWebNavigation.h"
 #include "nsXPIDLString.h"
 #endif
 
-#if defined(XP_MACOSX) && !defined(__LP64__)
-#include "nsAutoPtr.h"
-#include <Carbon/Carbon.h>
-#endif
-
-
 //*****************************************************************************
 // nsWebBrowserFind
 //*****************************************************************************
 
 nsWebBrowserFind::nsWebBrowserFind() :
     mFindBackwards(false),
     mWrapFind(false),
     mEntireWord(false),
@@ -239,51 +233,23 @@ NS_IMETHODIMP nsWebBrowserFind::FindNext
     return rv;
 }
 
 
 /* attribute wstring searchString; */
 NS_IMETHODIMP nsWebBrowserFind::GetSearchString(PRUnichar * *aSearchString)
 {
     NS_ENSURE_ARG_POINTER(aSearchString);
-#if defined(XP_MACOSX) && !defined(__LP64__)
-    OSStatus err;
-    ScrapRef scrap;
-    err = ::GetScrapByName(kScrapFindScrap, kScrapGetNamedScrap, &scrap);
-    if (err == noErr) {
-        Size byteCount;
-        err = ::GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &byteCount);
-        if (err == noErr) {
-            NS_ASSERTION(byteCount%2 == 0, "byteCount not a multiple of 2");
-            nsAutoArrayPtr<PRUnichar> buffer(new PRUnichar[byteCount/2 + 1]);
-            NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
-            err = ::GetScrapFlavorData(scrap, kScrapFlavorTypeUnicode, &byteCount, buffer.get());
-            if (err == noErr) {
-                buffer[byteCount/2] = PRUnichar('\0');
-                mSearchString.Assign(buffer);
-            }
-        }
-    }    
-#endif
     *aSearchString = ToNewUnicode(mSearchString);
     return NS_OK;
 }
 
 NS_IMETHODIMP nsWebBrowserFind::SetSearchString(const PRUnichar * aSearchString)
 {
     mSearchString.Assign(aSearchString);
-#if defined(XP_MACOSX) && !defined(__LP64__)
-    OSStatus err;
-    ScrapRef scrap;
-    err = ::GetScrapByName(kScrapFindScrap, kScrapClearNamedScrap, &scrap);
-    if (err == noErr) {
-        ::PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone,
-        (mSearchString.Length()*2), aSearchString);
-    }
-#endif
     return NS_OK;
 }
 
 /* attribute boolean findBackwards; */
 NS_IMETHODIMP nsWebBrowserFind::GetFindBackwards(bool *aFindBackwards)
 {
     NS_ENSURE_ARG_POINTER(aFindBackwards);
     *aFindBackwards = mFindBackwards;
--- a/extensions/auth/nsAuthGSSAPI.cpp
+++ b/extensions/auth/nsAuthGSSAPI.cpp
@@ -353,18 +353,18 @@ nsAuthGSSAPI::Init(const char *serviceNa
        return NS_ERROR_NOT_INITIALIZED;
 
     mServiceName = serviceName;
     mServiceFlags = serviceFlags;
 
     static bool sTelemetrySent = false;
     if (!sTelemetrySent) {
         mozilla::Telemetry::Accumulate(
-            mozilla::Telemetry::NTLM_MODULE_USED,
-            serviceFlags | nsIAuthModule::REQ_PROXY_AUTH
+            mozilla::Telemetry::NTLM_MODULE_USED_2,
+            serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
                 ? NTLM_MODULE_KERBEROS_PROXY
                 : NTLM_MODULE_KERBEROS_DIRECT);
         sTelemetrySent = true;
     }
 
     return NS_OK;
 }
 
--- a/extensions/auth/nsAuthSSPI.cpp
+++ b/extensions/auth/nsAuthSSPI.cpp
@@ -273,18 +273,18 @@ nsAuthSSPI::Init(const char *serviceName
                                            &mCred,
                                            &useBefore);
     if (rc != SEC_E_OK)
         return NS_ERROR_UNEXPECTED;
 
     static bool sTelemetrySent = false;
     if (!sTelemetrySent) {
         mozilla::Telemetry::Accumulate(
-            mozilla::Telemetry::NTLM_MODULE_USED,
-            serviceFlags | nsIAuthModule::REQ_PROXY_AUTH
+            mozilla::Telemetry::NTLM_MODULE_USED_2,
+            serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
                 ? NTLM_MODULE_WIN_API_PROXY
                 : NTLM_MODULE_WIN_API_DIRECT);
         sTelemetrySent = true;
     }
 
     LOG(("AcquireCredentialsHandle() succeeded.\n"));
     return NS_OK;
 }
--- a/extensions/auth/nsAuthSambaNTLM.cpp
+++ b/extensions/auth/nsAuthSambaNTLM.cpp
@@ -210,18 +210,18 @@ nsAuthSambaNTLM::Init(const char *servic
                       const PRUnichar *username,
                       const PRUnichar *password)
 {
     NS_ASSERTION(!username && !domain && !password, "unexpected credentials");
 
     static bool sTelemetrySent = false;
     if (!sTelemetrySent) {
         mozilla::Telemetry::Accumulate(
-            mozilla::Telemetry::NTLM_MODULE_USED,
-            serviceFlags | nsIAuthModule::REQ_PROXY_AUTH
+            mozilla::Telemetry::NTLM_MODULE_USED_2,
+            serviceFlags & nsIAuthModule::REQ_PROXY_AUTH
                 ? NTLM_MODULE_SAMBA_AUTH_PROXY
                 : NTLM_MODULE_SAMBA_AUTH_DIRECT);
         sTelemetrySent = true;
     }
 
     return NS_OK;
 }
 
--- a/gfx/2d/convolver.cpp
+++ b/gfx/2d/convolver.cpp
@@ -24,17 +24,16 @@
 // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 // SUCH DAMAGE.
 
 #include "convolver.h"
 
 #include <algorithm>
-#include "nsAlgorithm.h"
 
 #include "skia/SkTypes.h"
 
 // note: SIMD_SSE2 is not enabled because of bugs, apparently
 
 #if defined(SIMD_SSE2)
 #include <emmintrin.h>  // ARCH_CPU_X86_FAMILY was defined in build/config.h
 #endif
--- a/gfx/2d/image_operations.cpp
+++ b/gfx/2d/image_operations.cpp
@@ -30,17 +30,16 @@
 
 #define _USE_MATH_DEFINES
 #include <algorithm>
 #include <cmath>
 #include <limits>
 
 #include "image_operations.h"
 
-#include "nsAlgorithm.h"
 #include "base/stack_container.h"
 #include "convolver.h"
 #include "skia/SkColorPriv.h"
 #include "skia/SkBitmap.h"
 #include "skia/SkRect.h"
 #include "skia/SkFontHost.h"
 
 namespace skia {
--- a/gfx/layers/Compositor.cpp
+++ b/gfx/layers/Compositor.cpp
@@ -34,35 +34,43 @@ Compositor::AssertOnCompositorThread()
 
 void
 Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
                             const gfx::Rect& rect,
                             const gfx::Rect& aClipRect,
                             const gfx::Matrix4x4& aTransform,
                             const gfx::Point& aOffset)
 {
-  if (!(mDiagnosticTypes & DIAGNOSTIC_TILE_BORDERS) && (aFlags & DIAGNOSTIC_TILE)) {
+  if ((aFlags & DIAGNOSTIC_TILE) && !(mDiagnosticTypes & DIAGNOSTIC_TILE_BORDERS)) {
+    return;
+  }
+  if ((aFlags & DIAGNOSTIC_BIGIMAGE) && !(mDiagnosticTypes & DIAGNOSTIC_BIGIMAGE_BORDERS)) {
+    return;
+  }
+  if (!mDiagnosticTypes) {
     return;
   }
 
-  if (!(mDiagnosticTypes & DIAGNOSTIC_LAYER_BORDERS)) {
-    return;
-  }
-
+#ifdef MOZ_B2G
+  int lWidth = 4;
+#elif defined(ANDROID)
+  int lWidth = 10;
+#else
   int lWidth = 2;
+#endif
   float opacity = 0.7;
 
   gfx::Color color;
   if (aFlags & DIAGNOSTIC_CONTENT) {
     color = gfx::Color(0.0, 1.0, 0.0, 1.0); // green
     if (aFlags & DIAGNOSTIC_COMPONENT_ALPHA) {
       color = gfx::Color(0.0, 1.0, 1.0, 1.0); // greenish blue
     }
   } else if (aFlags & DIAGNOSTIC_IMAGE) {
-    color = gfx::Color(0.5, 0.0, 0.0, 1.0); // red
+    color = gfx::Color(1.0, 0.0, 0.0, 1.0); // red
   } else if (aFlags & DIAGNOSTIC_COLOR) {
     color = gfx::Color(0.0, 0.0, 1.0, 1.0); // blue
   } else if (aFlags & DIAGNOSTIC_CONTAINER) {
     color = gfx::Color(0.8, 0.0, 0.8, 1.0); // purple
   }
 
   // make tile borders a bit more transparent to keep layer borders readable.
   if (aFlags & DIAGNOSTIC_TILE || aFlags & DIAGNOSTIC_BIGIMAGE) {
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -160,16 +160,17 @@ ClientLayerManager::EndTransactionIntern
                                            void* aCallbackData,
                                            EndTransactionFlags)
 {
   PROFILER_LABEL("ClientLayerManager", "EndTransactionInternal");
 #ifdef MOZ_LAYERS_HAVE_LOG
   MOZ_LAYERS_LOG(("  ----- (beginning paint)"));
   Log();
 #endif
+  profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_START);
 
   NS_ASSERTION(InConstruction(), "Should be in construction phase");
   mPhase = PHASE_DRAWING;
 
   ClientLayer* root = ClientLayer::ToClientLayer(GetRoot());
 
   mTransactionIncomplete = false;
       
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -1,19 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; 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 "ContainerLayerD3D10.h"
-#include "nsAlgorithm.h"
-#include "gfxUtils.h"
-#include "nsRect.h"
 
-#include "../d3d9/Nv3DVUtils.h"
 #include "ThebesLayerD3D10.h"
 #include "ReadbackProcessor.h"
 
 namespace mozilla {
 namespace layers {
 
 ContainerLayerD3D10::ContainerLayerD3D10(LayerManagerD3D10 *aManager)
   : ContainerLayer(aManager, nullptr)
--- a/gfx/layers/d3d9/ContainerLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ContainerLayerD3D9.cpp
@@ -1,16 +1,15 @@
 /* -*- 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 "ContainerLayerD3D9.h"
-#include "gfxUtils.h"
-#include "nsRect.h"
+
 #include "ThebesLayerD3D9.h"
 #include "ReadbackProcessor.h"
 
 namespace mozilla {
 namespace layers {
 
 ContainerLayerD3D9::ContainerLayerD3D9(LayerManagerD3D9 *aManager)
   : ContainerLayer(aManager, nullptr)
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -597,103 +597,85 @@ nsEventStatus AsyncPanZoomController::On
 
 nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEvent) {
   APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
   if (!mAllowZoom) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   SetState(PINCHING);
-  mLastZoomFocus = aEvent.mFocusPoint;
+  mLastZoomFocus = aEvent.mFocusPoint - mFrameMetrics.mCompositionBounds.TopLeft();
 
   return nsEventStatus_eConsumeNoDefault;
 }
 
 nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
   APZC_LOG("%p got a scale in state %d\n", this, mState);
   if (mState != PINCHING) {
     return nsEventStatus_eConsumeNoDefault;
   }
 
   float prevSpan = aEvent.mPreviousSpan;
   if (fabsf(prevSpan) <= EPSILON || fabsf(aEvent.mCurrentSpan) <= EPSILON) {
     // We're still handling it; we've just decided to throw this event away.
     return nsEventStatus_eConsumeNoDefault;
   }
 
-  ScreenToScreenScale spanRatio(aEvent.mCurrentSpan / aEvent.mPreviousSpan);
+  float spanRatio = aEvent.mCurrentSpan / aEvent.mPreviousSpan;
 
   {
     ReentrantMonitorAutoEnter lock(mMonitor);
 
     CSSToScreenScale userZoom = mFrameMetrics.mZoom;
-    ScreenPoint focusPoint = aEvent.mFocusPoint;
+    ScreenPoint focusPoint = aEvent.mFocusPoint - mFrameMetrics.mCompositionBounds.TopLeft();
+    CSSPoint cssFocusPoint = focusPoint / userZoom;
 
     CSSPoint focusChange = (mLastZoomFocus - focusPoint) / userZoom;
     // If displacing by the change in focus point will take us off page bounds,
     // then reduce the displacement such that it doesn't.
     if (mX.DisplacementWillOverscroll(focusChange.x) != Axis::OVERSCROLL_NONE) {
       focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x);
     }
     if (mY.DisplacementWillOverscroll(focusChange.y) != Axis::OVERSCROLL_NONE) {
       focusChange.y -= mY.DisplacementWillOverscrollAmount(focusChange.y);
     }
     ScrollBy(focusChange);
 
     // When we zoom in with focus, we can zoom too much towards the boundaries
     // that we actually go over them. These are the needed displacements along
     // either axis such that we don't overscroll the boundaries when zooming.
-    gfx::Point neededDisplacement;
+    CSSPoint neededDisplacement;
 
-    bool doScale = (spanRatio > ScreenToScreenScale(1.0) && userZoom < mMaxZoom) ||
-                   (spanRatio < ScreenToScreenScale(1.0) && userZoom > mMinZoom);
+    CSSToScreenScale realMinZoom = mMinZoom;
+    CSSToScreenScale realMaxZoom = mMaxZoom;
+    realMinZoom.scale = std::max(realMinZoom.scale,
+                                 mFrameMetrics.mCompositionBounds.width / mFrameMetrics.mScrollableRect.width);
+    realMinZoom.scale = std::max(realMinZoom.scale,
+                                 mFrameMetrics.mCompositionBounds.height / mFrameMetrics.mScrollableRect.height);
+    if (realMaxZoom < realMinZoom) {
+      realMaxZoom = realMinZoom;
+    }
+
+    bool doScale = (spanRatio > 1.0 && userZoom < realMaxZoom) ||
+                   (spanRatio < 1.0 && userZoom > realMinZoom);
 
     if (doScale) {
-      spanRatio.scale = clamped(spanRatio.scale,
-                                mMinZoom.scale / userZoom.scale,
-                                mMaxZoom.scale / userZoom.scale);
+      spanRatio = clamped(spanRatio,
+                          realMinZoom.scale / userZoom.scale,
+                          realMaxZoom.scale / userZoom.scale);
 
-      switch (mX.ScaleWillOverscroll(spanRatio, focusPoint.x))
-      {
-        case Axis::OVERSCROLL_NONE:
-          break;
-        case Axis::OVERSCROLL_MINUS:
-        case Axis::OVERSCROLL_PLUS:
-          neededDisplacement.x = -mX.ScaleWillOverscrollAmount(spanRatio, focusPoint.x);
-          break;
-        case Axis::OVERSCROLL_BOTH:
-          // If scaling this way will make us overscroll in both directions, then
-          // we must already be at the maximum zoomed out amount. In this case, we
-          // don't want to allow this scaling to go through and instead clamp it
-          // here.
-          doScale = false;
-          break;
-      }
-    }
+      // Note that the spanRatio here should never put us into OVERSCROLL_BOTH because
+      // up above we clamped it.
+      neededDisplacement.x = -mX.ScaleWillOverscrollAmount(spanRatio, cssFocusPoint.x);
+      neededDisplacement.y = -mY.ScaleWillOverscrollAmount(spanRatio, cssFocusPoint.y);
 
-    if (doScale) {
-      switch (mY.ScaleWillOverscroll(spanRatio, focusPoint.y))
-      {
-        case Axis::OVERSCROLL_NONE:
-          break;
-        case Axis::OVERSCROLL_MINUS:
-        case Axis::OVERSCROLL_PLUS:
-          neededDisplacement.y = -mY.ScaleWillOverscrollAmount(spanRatio, focusPoint.y);
-          break;
-        case Axis::OVERSCROLL_BOTH:
-          doScale = false;
-          break;
-      }
-    }
+      ScaleWithFocus(spanRatio, cssFocusPoint);
 
-    if (doScale) {
-      ScaleWithFocus(userZoom * spanRatio, focusPoint);
-
-      if (neededDisplacement != gfx::Point()) {
-        ScrollBy(CSSPoint::FromUnknownPoint(neededDisplacement));
+      if (neededDisplacement != CSSPoint()) {
+        ScrollBy(neededDisplacement);
       }
 
       ScheduleComposite();
       // We don't want to redraw on every scale, so don't use
       // RequestContentRepaint()
     }
 
     mLastZoomFocus = focusPoint;
@@ -972,29 +954,24 @@ void AsyncPanZoomController::CancelAnima
 void AsyncPanZoomController::SetCompositorParent(CompositorParent* aCompositorParent) {
   mCompositorParent = aCompositorParent;
 }
 
 void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
   mFrameMetrics.mScrollOffset += aOffset;
 }
 
-void AsyncPanZoomController::ScaleWithFocus(const CSSToScreenScale& aZoom,
-                                            const ScreenPoint& aFocus) {
-  ScreenToScreenScale zoomFactor(aZoom.scale / mFrameMetrics.mZoom.scale);
-  CSSToScreenScale resolution = mFrameMetrics.mZoom;
-
-  SetZoomAndResolution(aZoom);
-
-  // If the new scale is very small, we risk multiplying in huge rounding
-  // errors, so don't bother adjusting the scroll offset.
-  if (resolution.scale >= 0.01f) {
-    zoomFactor.scale -= 1.0;
-    mFrameMetrics.mScrollOffset += aFocus * zoomFactor / resolution;
-  }
+void AsyncPanZoomController::ScaleWithFocus(float aScale,
+                                            const CSSPoint& aFocus) {
+  SetZoomAndResolution(CSSToScreenScale(mFrameMetrics.mZoom.scale * aScale));
+  // We want to adjust the scroll offset such that the CSS point represented by aFocus remains
+  // at the same position on the screen before and after the change in zoom. The below code
+  // accomplishes this; see https://bugzilla.mozilla.org/show_bug.cgi?id=923431#c6 for an
+  // in-depth explanation of how.
+  mFrameMetrics.mScrollOffset = (mFrameMetrics.mScrollOffset + aFocus) - (aFocus / aScale);
 }
 
 bool AsyncPanZoomController::EnlargeDisplayPortAlongAxis(float aSkateSizeMultiplier,
                                                          double aEstimatedPaintDuration,
                                                          float aCompositionBounds,
                                                          float aVelocity,
                                                          float aAcceleration,
                                                          float* aDisplayPortOffset,
@@ -1345,18 +1322,18 @@ void AsyncPanZoomController::UpdateCompo
   mFrameMetrics.mCompositionBounds = aCompositionBounds;
 
   // If the window had 0 dimensions before, or does now, we don't want to
   // repaint or update the zoom since we'll run into rendering issues and/or
   // divide-by-zero. This manifests itself as the screen flashing. If the page
   // has gone out of view, the buffer will be cleared elsewhere anyways.
   if (aCompositionBounds.width && aCompositionBounds.height &&
       oldCompositionBounds.width && oldCompositionBounds.height) {
-    ScreenToScreenScale adjustmentFactor(float(aCompositionBounds.width) / float(oldCompositionBounds.width));
-    SetZoomAndResolution(mFrameMetrics.mZoom * adjustmentFactor);
+    float adjustmentFactor = float(aCompositionBounds.width) / float(oldCompositionBounds.width);
+    SetZoomAndResolution(CSSToScreenScale(mFrameMetrics.mZoom.scale * adjustmentFactor));
 
     // Repaint on a rotation so that our new resolution gets properly updated.
     RequestContentRepaint();
   }
 }
 
 void AsyncPanZoomController::CancelDefaultPanZoom() {
   mDisableNextTouchBatch = true;
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -354,22 +354,20 @@ protected:
   /**
    * Scrolls the viewport by an X,Y offset.
    */
   void ScrollBy(const CSSPoint& aOffset);
 
   /**
    * Scales the viewport by an amount (note that it multiplies this scale in to
    * the current scale, it doesn't set it to |aScale|). Also considers a focus
-   * point so that the page zooms outward from that point.
-   *
-   * XXX: Fix focus point calculations.
+   * point so that the page zooms inward/outward from that point.
    */
-  void ScaleWithFocus(const mozilla::CSSToScreenScale& aScale,
-                      const ScreenPoint& aFocus);
+  void ScaleWithFocus(float aScale,
+                      const CSSPoint& aFocus);
 
   /**
    * Schedules a composite on the compositor thread. Wrapper for
    * CompositorParent::ScheduleRenderOnCompositorThread().
    */
   void ScheduleComposite();
 
   /**
--- a/gfx/layers/ipc/Axis.cpp
+++ b/gfx/layers/ipc/Axis.cpp
@@ -266,44 +266,35 @@ float Axis::DisplacementWillOverscrollAm
   case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart();
   case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd();
   // Don't handle overscrolled in both directions; a displacement can't cause
   // this, it must have already been zoomed out too far.
   default: return 0;
   }
 }
 
-Axis::Overscroll Axis::ScaleWillOverscroll(ScreenToScreenScale aScale, float aFocus) {
-  float originAfterScale = (GetOrigin() + aFocus) * aScale.scale - aFocus;
+float Axis::ScaleWillOverscrollAmount(float aScale, float aFocus) {
+  float originAfterScale = (GetOrigin() + aFocus) - (aFocus / aScale);
 
   bool both = ScaleWillOverscrollBothSides(aScale);
-  bool minus = originAfterScale < GetPageStart() * aScale.scale;
-  bool plus = (originAfterScale + GetCompositionLength()) > GetPageEnd() * aScale.scale;
+  bool minus = originAfterScale < GetPageStart();
+  bool plus = (originAfterScale + (GetCompositionLength() / aScale)) > GetPageEnd();
 
   if ((minus && plus) || both) {
-    return OVERSCROLL_BOTH;
+    // If we ever reach here it's a bug in the client code.
+    MOZ_ASSERT(false, "In an OVERSCROLL_BOTH condition in ScaleWillOverscrollAmount");
+    return 0;
   }
   if (minus) {
-    return OVERSCROLL_MINUS;
+    return originAfterScale - GetPageStart();
   }
   if (plus) {
-    return OVERSCROLL_PLUS;
+    return originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd();
   }
-  return OVERSCROLL_NONE;
-}
-
-float Axis::ScaleWillOverscrollAmount(ScreenToScreenScale aScale, float aFocus) {
-  float originAfterScale = (GetOrigin() + aFocus) * aScale.scale - aFocus;
-  switch (ScaleWillOverscroll(aScale, aFocus)) {
-  case OVERSCROLL_MINUS: return originAfterScale - GetPageStart() * aScale.scale;
-  case OVERSCROLL_PLUS: return (originAfterScale + GetCompositionLength()) -
-                               NS_lround(GetPageEnd() * aScale.scale);
-  // Don't handle OVERSCROLL_BOTH. Client code is expected to deal with it.
-  default: return 0;
-  }
+  return 0;
 }
 
 float Axis::GetVelocity() {
   return mScrollingDisabled ? 0 : mVelocity;
 }
 
 float Axis::GetAccelerationFactor() {
   return powf(gAccelerationMultiplier, std::max(0, (mAcceleration - 4) * 3));
@@ -333,25 +324,23 @@ float Axis::GetPageStart() {
   return GetRectOffset(pageRect);
 }
 
 float Axis::GetPageLength() {
   CSSRect pageRect = mAsyncPanZoomController->GetFrameMetrics().mScrollableRect;
   return GetRectLength(pageRect);
 }
 
-bool Axis::ScaleWillOverscrollBothSides(ScreenToScreenScale aScale) {
+bool Axis::ScaleWillOverscrollBothSides(float aScale) {
   const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
 
-  CSSRect cssContentRect = metrics.mScrollableRect;
+  CSSToScreenScale scale(metrics.mZoom.scale * aScale);
+  CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale;
 
-  CSSToScreenScale scale = metrics.mZoom * aScale;
-  CSSIntRect cssCompositionBounds = RoundedIn(metrics.mCompositionBounds / scale);
-
-  return GetRectLength(cssContentRect) < GetRectLength(CSSRect(cssCompositionBounds));
+  return GetRectLength(metrics.mScrollableRect) < GetRectLength(cssCompositionBounds);
 }
 
 AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController)
   : Axis(aAsyncPanZoomController)
 {
 
 }
 
--- a/gfx/layers/ipc/Axis.h
+++ b/gfx/layers/ipc/Axis.h
@@ -137,49 +137,38 @@ public:
    * Gets the overscroll state of the axis given an additional displacement.
    * That is to say, if the given displacement is applied, this will tell you
    * whether or not it will overscroll, and in what direction.
    */
   Overscroll DisplacementWillOverscroll(float aDisplacement);
 
   /**
    * If a displacement will overscroll the axis, this returns the amount and in
-   * what direction. Similar to getExcess() but takes a displacement to apply.
+   * what direction. Similar to GetExcess() but takes a displacement to apply.
    */
   float DisplacementWillOverscrollAmount(float aDisplacement);
 
   /**
-   * Gets the overscroll state of the axis given a scaling of the page. That is
-   * to say, if the given scale is applied, this will tell you whether or not
-   * it will overscroll, and in what direction.
+   * If a scale will overscroll the axis, this returns the amount and in what
+   * direction. Similar to GetExcess() but takes a displacement to apply.
    *
    * |aFocus| is the point at which the scale is focused at. We will offset the
    * scroll offset in such a way that it remains in the same place on the page
    * relative.
    */
-  Overscroll ScaleWillOverscroll(ScreenToScreenScale aScale, float aFocus);
-
-  /**
-   * If a scale will overscroll the axis, this returns the amount and in what
-   * direction. Similar to getExcess() but takes a displacement to apply.
-   *
-   * |aFocus| is the point at which the scale is focused at. We will offset the
-   * scroll offset in such a way that it remains in the same place on the page
-   * relative.
-   */
-  float ScaleWillOverscrollAmount(ScreenToScreenScale aScale, float aFocus);
+  float ScaleWillOverscrollAmount(float aScale, float aFocus);
 
   /**
    * Checks if an axis will overscroll in both directions by computing the
    * content rect and checking that its height/width (depending on the axis)
    * does not overextend past the viewport.
    *
    * This gets called by ScaleWillOverscroll().
    */
-  bool ScaleWillOverscrollBothSides(ScreenToScreenScale aScale);
+  bool ScaleWillOverscrollBothSides(float aScale);
 
   float GetOrigin();
   float GetCompositionLength();
   float GetPageStart();
   float GetPageLength();
   float GetCompositionEnd();
   float GetPageEnd();
 
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -96,19 +96,25 @@ CompositorChild::DeallocPLayerTransactio
   return true;
 }
 
 void
 CompositorChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   MOZ_ASSERT(sCompositor == this);
 
+#ifdef MOZ_B2G
+  // Due to poor lifetime management of gralloc (and possibly shmems) we will
+  // crash at some point in the future when we get destroyed due to abnormal
+  // shutdown. Its better just to crash here. On desktop though, we have a chance
+  // of recovering.
   if (aWhy == AbnormalShutdown) {
     NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at CompositorChild");
   }
+#endif
 
   sCompositor = nullptr;
   // We don't want to release the ref to sCompositor here, during
   // cleanup, because that will cause it to be deleted while it's
   // still being used.  So defer the deletion to after it's not in
   // use.
   MessageLoop::current()->PostTask(
     FROM_HERE,
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -542,16 +542,17 @@ CompositorParent::Composite()
   mLayerManager->EndEmptyTransaction();
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   if (mExpectedComposeTime + TimeDuration::FromMilliseconds(15) < TimeStamp::Now()) {
     printf_stderr("Compositor: Composite took %i ms.\n",
                   15 + (int)(TimeStamp::Now() - mExpectedComposeTime).ToMilliseconds());
   }
 #endif
+  profiler_tracing("Paint", "Composite", TRACING_INTERVAL_END);
 }
 
 void
 CompositorParent::ComposeToTarget(DrawTarget* aTarget)
 {
   PROFILER_LABEL("CompositorParent", "ComposeToTarget");
   AutoRestore<bool> override(mOverrideComposeReadiness);
   mOverrideComposeReadiness = true;
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -80,15 +80,21 @@ LayerTransactionChild::DeallocPComposita
 {
   delete actor;
   return true;
 }
 
 void
 LayerTransactionChild::ActorDestroy(ActorDestroyReason why)
 {
+#ifdef MOZ_B2G
+  // Due to poor lifetime management of gralloc (and possibly shmems) we will
+  // crash at some point in the future when we get destroyed due to abnormal
+  // shutdown. Its better just to crash here. On desktop though, we have a chance
+  // of recovering.
   if (why == AbnormalShutdown) {
     NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at LayerTransactionChild");
   }
+#endif
 }
 
 }  // namespace layers
 }  // namespace mozilla
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -182,16 +182,17 @@ LayerTransactionParent::RecvUpdateNoSwap
 }
 
 bool
 LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
                                    const TargetConfig& targetConfig,
                                    const bool& isFirstPaint,
                                    InfallibleTArray<EditReply>* reply)
 {
+  profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START);
   PROFILER_LABEL("LayerTransactionParent", "RecvUpdate");
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp updateStart = TimeStamp::Now();
 #endif
 
   MOZ_LAYERS_LOG(("[ParentSide] received txn with %d edits", cset.Length()));
 
   if (mDestroyed || !layer_manager() || layer_manager()->IsDestroyed()) {
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -534,16 +534,17 @@ ShadowLayerForwarder::EndTransaction(Inf
 
   mWindowOverlayChanged = false;
 
   TargetConfig targetConfig(mTxn->mTargetBounds, mTxn->mTargetRotation, mTxn->mClientBounds, mTxn->mTargetOrientation);
 
   MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
   PlatformSyncBeforeUpdate();
 
+  profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_END);
   if (mTxn->mSwapRequired) {
     MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
     RenderTraceScope rendertrace3("Forward Transaction", "000093");
     if (!mShadowManager->SendUpdate(cset, targetConfig, mIsFirstPaint,
                                     aReplies)) {
       MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
       return false;
     }
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -48,16 +48,21 @@ public:
   TestAsyncPanZoomController(uint64_t aLayersId, MockContentController* aMcc)
     : AsyncPanZoomController(aLayersId, nullptr, aMcc)
   {}
 
   void SetFrameMetrics(const FrameMetrics& metrics) {
     ReentrantMonitorAutoEnter lock(mMonitor);
     mFrameMetrics = metrics;
   }
+
+  FrameMetrics GetFrameMetrics() {
+    ReentrantMonitorAutoEnter lock(mMonitor);
+    return mFrameMetrics;
+  }
 };
 
 class TestAPZCTreeManager : public APZCTreeManager {
 protected:
   void AssertOnCompositorThread() MOZ_OVERRIDE { /* no-op */ }
 };
 
 static
@@ -110,16 +115,122 @@ void ApzcPan(AsyncPanZoomController* apz
 
 TEST(AsyncPanZoomController, Constructor) {
   // RefCounted class can't live in the stack
   nsRefPtr<MockContentController> mcc = new MockContentController();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   apzc->SetFrameMetrics(TestFrameMetrics());
 }
 
+TEST(AsyncPanZoomController, Pinch) {
+  nsRefPtr<MockContentController> mcc = new MockContentController();
+  nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
+
+  FrameMetrics fm;
+  fm.mViewport = CSSRect(0, 0, 980, 480);
+  fm.mCompositionBounds = ScreenIntRect(200, 200, 100, 200);
+  fm.mScrollableRect = CSSRect(0, 0, 980, 1000);
+  fm.mScrollOffset = CSSPoint(300, 300);
+  fm.mZoom = CSSToScreenScale(2.0);
+  apzc->SetFrameMetrics(fm);
+  // the visible area of the document in CSS pixels is x=300 y=300 w=50 h=100
+
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(2);
+  EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
+
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
+                                           0,
+                                           ScreenPoint(250, 300),
+                                           10.0,
+                                           10.0));
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
+                                           0,
+                                           ScreenPoint(250, 300),
+                                           12.5,
+                                           10.0));
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
+                                           0,
+                                           ScreenPoint(250, 300),
+                                           12.5,
+                                           12.5));
+
+  // the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
+  fm = apzc->GetFrameMetrics();
+  EXPECT_EQ(fm.mZoom.scale, 2.5f);
+  EXPECT_EQ(fm.mScrollOffset.x, 305);
+  EXPECT_EQ(fm.mScrollOffset.y, 310);
+
+  // part 2 of the test, move to the top-right corner of the page and pinch and
+  // make sure we stay in the correct spot
+  fm.mZoom = CSSToScreenScale(2.0);
+  fm.mScrollOffset = CSSPoint(930, 5);
+  apzc->SetFrameMetrics(fm);
+  // the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100
+
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
+                                           0,
+                                           ScreenPoint(250, 300),
+                                           10.0,
+                                           10.0));
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
+                                           0,
+                                           ScreenPoint(250, 300),
+                                           5.0,
+                                           10.0));
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
+                                           0,
+                                           ScreenPoint(250, 300),
+                                           5.0,
+                                           5.0));
+
+  // the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200
+  fm = apzc->GetFrameMetrics();
+  EXPECT_EQ(fm.mZoom.scale, 1.0f);
+  EXPECT_EQ(fm.mScrollOffset.x, 880);
+  EXPECT_EQ(fm.mScrollOffset.y, 0);
+}
+
+TEST(AsyncPanZoomController, Overzoom) {
+  nsRefPtr<MockContentController> mcc = new MockContentController();
+  nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
+
+  FrameMetrics fm;
+  fm.mViewport = CSSRect(0, 0, 100, 100);
+  fm.mCompositionBounds = ScreenIntRect(0, 0, 100, 100);
+  fm.mScrollableRect = CSSRect(0, 0, 125, 150);
+  fm.mScrollOffset = CSSPoint(10, 0);
+  fm.mZoom = CSSToScreenScale(1.0);
+  apzc->SetFrameMetrics(fm);
+  // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
+
+  EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(1);
+  EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
+
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
+                                           0,
+                                           ScreenPoint(50, 50),
+                                           10.0,
+                                           10.0));
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_SCALE,
+                                           0,
+                                           ScreenPoint(50, 50),
+                                           5.0,
+                                           10.0));
+  apzc->HandleInputEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
+                                           0,
+                                           ScreenPoint(50, 50),
+                                           5.0,
+                                           5.0));
+
+  fm = apzc->GetFrameMetrics();
+  EXPECT_EQ(fm.mZoom.scale, 0.8f);
+  EXPECT_EQ(fm.mScrollOffset.x, 0);
+  EXPECT_EQ(fm.mScrollOffset.y, 0);
+}
+
 TEST(AsyncPanZoomController, SimpleTransform) {
   TimeStamp testStartTime = TimeStamp::Now();
   // RefCounted class can't live in the stack
   nsRefPtr<MockContentController> mcc = new MockContentController();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   apzc->SetFrameMetrics(TestFrameMetrics());
 
   ScreenPoint pointOut;
--- a/gfx/thebes/gfxCoreTextShaper.cpp
+++ b/gfx/thebes/gfxCoreTextShaper.cpp
@@ -83,25 +83,25 @@ gfxCoreTextShaper::ShapeText(gfxContext 
         startOffset = isRightToLeft ?
             mozilla::ArrayLength(beginRTL) : mozilla::ArrayLength(beginLTR);
         CFMutableStringRef mutableString =
             ::CFStringCreateMutable(kCFAllocatorDefault,
                                     length + startOffset + mozilla::ArrayLength(endBidiWrap));
         ::CFStringAppendCharacters(mutableString,
                                    isRightToLeft ? beginRTL : beginLTR,
                                    startOffset);
-        ::CFStringAppendCharacters(mutableString, aText, length);
+        ::CFStringAppendCharacters(mutableString, reinterpret_cast<const UniChar*>(aText), length);
         ::CFStringAppendCharacters(mutableString,
                                    endBidiWrap, mozilla::ArrayLength(endBidiWrap));
         stringObj = mutableString;
     } else {
         startOffset = 0;
         stringObj = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
-                                                         aText, length,
-                                                         kCFAllocatorNull);
+                                                         reinterpret_cast<const UniChar*>(aText),
+                                                         length, kCFAllocatorNull);
     }
 
     CFDictionaryRef attrObj;
     if (aShapedText->DisableLigatures()) {
         // For letterspacing (or maybe other situations) we need to make a copy of the CTFont
         // with the ligature feature disabled
         CTFontRef ctFont =
             CreateCTFontWithDisabledLigatures(::CTFontGetSize(mCTFont));
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -118,23 +118,23 @@ static const int gAppleWeightToCSSWeight
 };
 
 // cache Cocoa's "shared font manager" for performance
 static NSFontManager *sFontManager;
 
 static void GetStringForNSString(const NSString *aSrc, nsAString& aDist)
 {
     aDist.SetLength([aSrc length]);
-    [aSrc getCharacters:aDist.BeginWriting()];
+    [aSrc getCharacters:reinterpret_cast<unichar*>(aDist.BeginWriting())];
 }
 
 static NSString* GetNSStringForString(const nsAString& aSrc)
 {
-    return [NSString stringWithCharacters:aSrc.BeginReading()
-                     length:aSrc.Length()];
+    return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(aSrc.BeginReading())
+                                   length:aSrc.Length()];
 }
 
 #ifdef PR_LOGGING
 
 #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
                                PR_LOG_DEBUG, args)
 #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
@@ -882,17 +882,17 @@ gfxMacPlatformFontList::GlobalFontFallba
                               kCFCompareCaseInsensitive) != kCFCompareEqualTo)
         {
             nsAutoTArray<UniChar, 1024> buffer;
             CFIndex len = ::CFStringGetLength(familyName);
             buffer.SetLength(len+1);
             ::CFStringGetCharacters(familyName, ::CFRangeMake(0, len),
                                     buffer.Elements());
             buffer[len] = 0;
-            nsDependentString familyName(buffer.Elements(), len);
+            nsDependentString familyName(reinterpret_cast<PRUnichar*>(buffer.Elements()), len);
 
             bool needsBold;  // ignored in the system fallback case
 
             gfxFontFamily *family = FindFamily(familyName);
             if (family) {
                 fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
                 if (fontEntry) {
                     if (fontEntry->TestCharacterMap(aCh)) {
--- a/intl/locale/src/mac/nsDateTimeFormatMac.cpp
+++ b/intl/locale/src/mac/nsDateTimeFormatMac.cpp
@@ -109,17 +109,17 @@ nsresult nsDateTimeFormatMac::FormatTMTi
   NS_ASSERTION(tmTime->tm_wday >= 0, "tm is not set correctly");
 
   // Got the locale for the formatter:
   CFLocaleRef formatterLocale;
   if (!locale) {
     formatterLocale = CFLocaleCopyCurrent();
   } else {
     CFStringRef localeStr = CFStringCreateWithCharacters(nullptr,
-                                                         mLocale.get(),
+                                                         reinterpret_cast<const UniChar*>(mLocale.get()),
                                                          mLocale.Length());
     formatterLocale = CFLocaleCreate(nullptr, localeStr);
     CFRelease(localeStr);
   }
 
   // Get the date style for the formatter:  
   CFDateFormatterStyle dateStyle;
   switch (dateFormatSelector) {
@@ -216,17 +216,17 @@ nsresult nsDateTimeFormatMac::FormatTMTi
                                                                           formatter,
                                                                           absTime);
   
   CFIndex stringLen = CFStringGetLength(formattedDate);
   
   nsAutoTArray<UniChar, 256> stringBuffer;
   if (stringBuffer.SetLength(stringLen + 1)) {
     CFStringGetCharacters(formattedDate, CFRangeMake(0, stringLen), stringBuffer.Elements());
-    stringOut.Assign(stringBuffer.Elements(), stringLen);
+    stringOut.Assign(reinterpret_cast<PRUnichar*>(stringBuffer.Elements()), stringLen);
   }
   
   CFRelease(formattedDate);
   CFRelease(formatter);
   
   return res;
 }
 
--- a/intl/locale/src/nsLocaleService.cpp
+++ b/intl/locale/src/nsLocaleService.cpp
@@ -225,17 +225,17 @@ nsLocaleService::nsLocaleService(void)
     int size = ::CFStringGetLength(userLocaleStr);
     if (buffer.SetLength(size + 1))
     {
         CFRange range = ::CFRangeMake(0, size);
         ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
         buffer[size] = 0;
 
         // Convert the locale string to the format that Mozilla expects
-        nsAutoString xpLocale(buffer.Elements());
+        nsAutoString xpLocale(reinterpret_cast<PRUnichar*>(buffer.Elements()));
         xpLocale.ReplaceChar('_', '-');
 
         nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
         if (NS_SUCCEEDED(rv)) {
             mApplicationLocale = mSystemLocale;
         }
     }
 
--- a/intl/lwbrk/src/nsCarbonBreaker.cpp
+++ b/intl/lwbrk/src/nsCarbonBreaker.cpp
@@ -27,17 +27,17 @@ NS_GetComplexLineBreaks(const PRUnichar*
      
   for (UniCharArrayOffset position = 0; position < aLength;) {
     UniCharArrayOffset offset;
     status = UCFindTextBreak(breakLocator, 
                   kUCTextBreakLineMask, 
                   position == 0 ? kUCTextBreakLeadingEdgeMask : 
                                   (kUCTextBreakLeadingEdgeMask | 
                                    kUCTextBreakIterateMask),
-                  aText, 
+                  reinterpret_cast<const UniChar*>(aText),
                   aLength, 
                   position, 
                   &offset);
     if (status != noErr || offset >= aLength)
       break;        
     aBreakBefore[offset] = true;
     position = offset;
   }
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -3724,22 +3724,25 @@ class _GenerateProtocolActorCode(ipdl.as
             _runtimeAbort('Clone() for ' +
                           p.name +
                           ' has not yet been implemented'),
             StmtReturn(ExprLiteral.NULL)
         ])
 
         othervar = ExprVar('other')
         managertype = Type(_actorName(p.name, self.side), ptr=1)
-        otherstmt = StmtDecl(Decl(managertype,
-                                  othervar.name),
-                             init=ExprCast(sourcevar,
-                                           managertype,
-                                           static=1))
-        clonemanagees.addstmt(otherstmt)
+
+        if len(p.managesStmts):
+            otherstmt = StmtDecl(Decl(managertype,
+                                      othervar.name),
+                                 init=ExprCast(sourcevar,
+                                               managertype,
+                                               static=1))
+            clonemanagees.addstmt(otherstmt)
+
         actorvar = ExprVar('actor')
         for managee in p.managesStmts:
             block = StmtBlock()
             manageeipdltype = managee.decl.type
             actortype = ipdl.type.ActorType(manageeipdltype)
             manageecxxtype = _cxxBareType(actortype, self.side)
             manageearray = p.managedVar(manageeipdltype, self.side)
             abortstmt = StmtIf(ExprBinary(actorvar, '==', ExprLiteral.NULL))
--- a/ipc/ipdl/moz.build
+++ b/ipc/ipdl/moz.build
@@ -4,14 +4,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/.
 
 if CONFIG['MOZ_IPDL_TESTS']:
     DIRS += ['test']
 
 MODULE = 'ipdlgen'
 
+FAIL_ON_WARNINGS = True
+
 LIBXUL_LIBRARY = True
 
 LIBRARY_NAME = 'mozipdlgen_s'
 
 EXPORT_LIBRARY = True
 
--- a/js/public/CallArgs.h
+++ b/js/public/CallArgs.h
@@ -38,17 +38,17 @@
 #include "js/RootingAPI.h"
 #include "js/Value.h"
 
 /* Typedef for native functions called by the JS VM. */
 typedef bool
 (* JSNative)(JSContext *cx, unsigned argc, JS::Value *vp);
 
 /* Typedef for native functions that may be called in parallel. */
-typedef js::ParallelResult
+typedef bool
 (* JSParallelNative)(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp);
 
 /*
  * Typedef for native functions that may be called either in parallel or
  * sequential execution.
  */
 typedef bool
 (* JSThreadSafeNative)(js::ThreadSafeContext *cx, unsigned argc, JS::Value *vp);
@@ -57,17 +57,17 @@ typedef bool
  * Convenience wrappers for passing in ThreadSafeNative to places that expect
  * a JSNative or a JSParallelNative.
  */
 template <JSThreadSafeNative threadSafeNative>
 inline bool
 JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp);
 
 template <JSThreadSafeNative threadSafeNative>
-inline js::ParallelResult
+inline bool
 JSParallelNativeThreadSafeWrapper(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp);
 
 /*
  * Compute |this| for the |vp| inside a JSNative, either boxing primitives or
  * replacing with the global object as necessary.
  *
  * This method will go away at some point: instead use |args.thisv()|.  If the
  * value is an object, no further work is required.  If that value is |null| or
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -479,17 +479,17 @@ obj_lookupSetter(JSContext *cx, unsigned
                 args.rval().set(shape->setterValue());
         }
     }
     return true;
 }
 #endif /* JS_OLD_GETTER_SETTER_METHODS */
 
 /* ES5 15.2.3.2. */
-bool
+static bool
 obj_getPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Step 1. */
     if (args.length() == 0) {
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -315,17 +315,17 @@ TypeEquivalent(JSContext *cx, unsigned i
     nullptr                                                                   \
 },
 
 const Class js::NumericTypeClasses[ScalarTypeRepresentation::TYPE_MAX] = {
     JS_FOR_EACH_SCALAR_TYPE_REPR(BINARYDATA_NUMERIC_CLASSES)
 };
 
 template <typename Domain, typename Input>
-bool
+static bool
 InRange(Input x)
 {
     return std::numeric_limits<Domain>::min() <= x &&
            x <= std::numeric_limits<Domain>::max();
 }
 
 template <>
 bool
@@ -512,17 +512,17 @@ NumericTypeToString(JSContext *cx, unsig
  *   var S = new StructType({...})
  *
  * A.prototype.__proto__ === ArrayType.prototype.prototype (and similar for
  * StructType).
  *
  * This function takes a reference to either ArrayType or StructType and
  * returns a JSObject which can be set as A.prototype.
  */
-JSObject *
+static JSObject *
 SetupAndGetPrototypeObjectForComplexTypeInstance(JSContext *cx,
                                                  HandleObject complexTypeGlobal)
 {
     RootedObject global(cx, cx->compartment()->maybeGlobal());
     RootedValue complexTypePrototypeVal(cx);
     RootedValue complexTypePrototypePrototypeVal(cx);
 
     if (!JSObject::getProperty(cx, complexTypeGlobal, complexTypeGlobal,
--- a/js/src/config/baseconfig.mk
+++ b/js/src/config/baseconfig.mk
@@ -1,18 +1,22 @@
 installdir = $(libdir)/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
 sdkdir = $(libdir)/$(MOZ_APP_NAME)-devel-$(MOZ_APP_VERSION)
 
+ifndef INCLUDED_FUNCTIONS_MK
+include $(topsrcdir)/config/makefiles/functions.mk
+endif
+
 ifneq (,$(filter /%,$(TOP_DIST)))
-DIST = $(TOP_DIST)
+DIST := $(call core_realpath,$(TOP_DIST))
 else
 ifeq (.,$(DEPTH))
-DIST = $(TOP_DIST)
+DIST := $(call core_realpath,$(TOP_DIST))
 else
-DIST = $(DEPTH)/$(TOP_DIST)
+DIST := $(call core_realpath,$(DEPTH)/$(TOP_DIST))
 endif
 endif
 
 # We do magic with OBJ_SUFFIX in config.mk, the following ensures we don't
 # manually use it before config.mk inclusion
 _OBJ_SUFFIX := $(OBJ_SUFFIX)
 OBJ_SUFFIX = $(error config/config.mk needs to be included before using OBJ_SUFFIX)
 
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -59,20 +59,16 @@ CHECK_VARS := \
  $(NULL)
 
 # checks for internal spaces or trailing spaces in the variable
 # named by $x
 check-variable = $(if $(filter-out 0 1,$(words $($(x))z)),$(error Spaces are not allowed in $(x)))
 
 $(foreach x,$(CHECK_VARS),$(check-variable))
 
-ifndef INCLUDED_FUNCTIONS_MK
-include $(topsrcdir)/config/makefiles/functions.mk
-endif
-
 RM = rm -f
 
 # LIBXUL_DIST is not defined under js/src, thus we make it mean DIST there.
 LIBXUL_DIST ?= $(DIST)
 
 # FINAL_TARGET specifies the location into which we copy end-user-shipped
 # build products (typelibs, components, chrome).
 #
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -789,28 +789,28 @@ static const JSFunctionSpec sModuleFunct
   JS_FN("CDataFinalizer", CDataFinalizer::Construct, 2, CTYPESFN_FLAGS),
   JS_FN("open", Library::Open, 1, CTYPESFN_FLAGS),
   JS_FN("cast", CData::Cast, 2, CTYPESFN_FLAGS),
   JS_FN("getRuntime", CData::GetRuntime, 1, CTYPESFN_FLAGS),
   JS_FN("libraryName", Library::Name, 1, CTYPESFN_FLAGS),
   JS_FS_END
 };
 
-JS_ALWAYS_INLINE JSString*
+static JS_ALWAYS_INLINE JSString*
 NewUCString(JSContext* cx, const AutoString& from)
 {
   return JS_NewUCStringCopyN(cx, from.begin(), from.length());
 }
 
 /*
  * Return a size rounded up to a multiple of a power of two.
  *
  * Note: |align| must be a power of 2.
  */
-JS_ALWAYS_INLINE size_t
+static JS_ALWAYS_INLINE size_t
 Align(size_t val, size_t align)
 {
   // Ensure that align is a power of two.
   MOZ_ASSERT(align != 0 && (align & (align - 1)) == 0);
   return ((val - 1) | (align - 1)) + 1;
 }
 
 static ABICode
--- a/js/src/devtools/vprof/vprof.cpp
+++ b/js/src/devtools/vprof/vprof.cpp
@@ -73,17 +73,17 @@ static long glock = LOCK_IS_FREE;
 
 		printf(buf);
 		::OutputDebugStringA(buf);
 	}
 #else
 	#define vprof_printf printf
 #endif
 
-inline static entry* reverse (entry* s)
+static inline entry* reverse (entry* s)
 {
     entry_t e, n, p;
 
     p = NULL;
     for (e = s; e; e = n) {
         n = e->next;
         e->next = p;
         p = e;
@@ -146,17 +146,17 @@ static void dumpProfile (void)
                 }
             }
         }
         vprof_printf ("\n");
     }
     entries = reverse(entries);
 }
 
-inline static entry_t findEntry (char* file, int line)
+static inline entry_t findEntry (char* file, int line)
 {
     for (entry_t e =  entries; e; e = e->next) {
         if ((e->line == line) && (VMPI_strcmp (e->file, file) == 0)) {
             return e;
         }
     }
     return NULL;
 }
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -131,17 +131,17 @@ MaybeCheckEvalFreeVariables(ExclusiveCon
             }
             scope = scope->enclosingScope();
         }
     }
 
     return true;
 }
 
-inline bool
+static inline bool
 CanLazilyParse(ExclusiveContext *cx, const CompileOptions &options)
 {
     return options.canLazilyParse &&
         options.compileAndGo &&
         options.sourcePolicy == CompileOptions::SAVE_SOURCE &&
         !cx->compartment()->debugMode();
 }
 
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3004,20 +3004,29 @@ EmitDestructuringOpsHelper(ExclusiveCont
         } else {
             JS_ASSERT(pn->isKind(PNK_OBJECT));
             JS_ASSERT(pn2->isKind(PNK_COLON));
             pn3 = pn2->pn_left;
             if (pn3->isKind(PNK_NUMBER)) {
                 if (!EmitNumberOp(cx, pn3->pn_dval, bce))
                     return false;
             } else {
+                // The parser already checked for atoms representing indexes and
+                // used PNK_NUMBER instead, but also watch for ids which TI treats
+                // as indexes for simpliciation of downstream analysis.
                 JS_ASSERT(pn3->isKind(PNK_STRING) || pn3->isKind(PNK_NAME));
-                if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, bce))
-                    return false;
-                doElemOp = false;
+                jsid id = NameToId(pn3->pn_atom->asPropertyName());
+                if (id != types::IdToTypeId(id)) {
+                    if (!EmitTree(cx, bce, pn3))
+                        return false;
+                } else {
+                    if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, bce))
+                        return false;
+                    doElemOp = false;
+                }
             }
             pn3 = pn2->pn_right;
         }
 
         if (doElemOp) {
             /*
              * Ok, get the value of the matching property name.  This leaves
              * that value on top of the value being destructured, so the stack
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -186,17 +186,17 @@ FoldBinaryNumeric(ExclusiveContext *cx, 
 
 // Remove a ParseNode, **pnp, from a parse tree, putting another ParseNode,
 // *pn, in its place.
 //
 // pnp points to a ParseNode pointer. This must be the only pointer that points
 // to the parse node being replaced. The replacement, *pn, is unchanged except
 // for its pn_next pointer; updating that is necessary if *pn's new parent is a
 // list node.
-void
+static void
 ReplaceNode(ParseNode **pnp, ParseNode *pn)
 {
     pn->pn_next = (*pnp)->pn_next;
     *pnp = pn;
 }
 
 enum Truthiness { Truthy, Falsy, Unknown };
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2601,17 +2601,17 @@ Parser<ParseHandler>::maybeParseDirectiv
                     if (tokenStream.sawOctalEscape()) {
                         report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL);
                         return false;
                     }
                     pc->sc->strict = true;
                 }
             }
         } else if (directive == context->names().useAsm) {
-            if (pc->sc->isFunctionBox() && !pc->isGenerator())
+            if (pc->sc->isFunctionBox())
                 return asmJS(list);
             return report(ParseWarning, false, pn, JSMSG_USE_ASM_DIRECTIVE_FAIL);
         }
     }
     return true;
 }
 
 /*
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -909,17 +909,17 @@ TokenStream::newToken(ptrdiff_t adjust)
 
 JS_ALWAYS_INLINE JSAtom *
 TokenStream::atomize(ExclusiveContext *cx, CharBuffer &cb)
 {
     return AtomizeChars<CanGC>(cx, cb.begin(), cb.length());
 }
 
 #ifdef DEBUG
-bool
+static bool
 IsTokenSane(Token *tp)
 {
     // Nb: TOK_EOL should never be used in an actual Token;  it should only be
     // returned as a TokenKind from peekTokenSameLine().
     if (tp->type < TOK_ERROR || tp->type >= TOK_LIMIT || tp->type == TOK_EOL)
         return false;
 
     if (tp->pos.end < tp->pos.begin)
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -29,17 +29,17 @@ using namespace mozilla;
 
 template <typename T>
 bool
 CheckNonAddressThing(uintptr_t *w, Rooted<T> *rootp)
 {
     return w >= (uintptr_t*)rootp->address() && w < (uintptr_t*)(rootp->address() + 1);
 }
 
-JS_ALWAYS_INLINE bool
+static JS_ALWAYS_INLINE bool
 CheckStackRootThing(uintptr_t *w, Rooted<void *> *rootp, ThingRootKind kind)
 {
     if (kind == THING_ROOT_BINDINGS)
         return CheckNonAddressThing(w, reinterpret_cast<Rooted<Bindings> *>(rootp));
 
     if (kind == THING_ROOT_PROPERTY_DESCRIPTOR)
         return CheckNonAddressThing(w, reinterpret_cast<Rooted<PropertyDescriptor> *>(rootp));
 
--- a/js/src/gdb/gdb-tests.cpp
+++ b/js/src/gdb/gdb-tests.cpp
@@ -15,25 +15,25 @@ using namespace JS;
 /* The class of the global object. */
 const JSClass global_class = {
     "global", JSCLASS_GLOBAL_FLAGS,
     JS_PropertyStub,  JS_DeletePropertyStub, JS_PropertyStub,  JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
 };
 
 template<typename T>
-inline T *
+static inline T *
 checkPtr(T *ptr)
 {
   if (! ptr)
     abort();
   return ptr;
 }
 
-void
+static void
 checkBool(bool success)
 {
   if (! success)
     abort();
 }
 
 /* The error reporter callback. */
 void reportError(JSContext *cx, const char *message, JSErrorReport *report)
--- a/js/src/jit-test/tests/asm.js/testBasic.js
+++ b/js/src/jit-test/tests/asm.js/testBasic.js
@@ -100,16 +100,17 @@ function assertTypeFailInEval(str)
     }
     assertEq(caught, true);
     options("werror");
 }
 assertTypeFailInEval('function f({}) { "use asm"; function g() {} return g }');
 assertTypeFailInEval('function f({global}) { "use asm"; function g() {} return g }');
 assertTypeFailInEval('function f(global, {imports}) { "use asm"; function g() {} return g }');
 assertTypeFailInEval('function f(g = 2) { "use asm"; function g() {} return g }');
+assertTypeFailInEval('function *f() { "use asm"; function g() {} return g }');
 
 function assertLinkFailInEval(str)
 {
     if (!isAsmJSCompilationAvailable())
         return;
 
     var caught = false;
     var oldOpts = options("werror");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-924690.js
@@ -0,0 +1,25 @@
+x = []
+try {
+    (function() {
+        schedulegc(1);
+        ((function() {
+            return {
+                y: function() {
+                    u() = []
+                }
+            }
+        })())
+    })()
+    watch.call(x, "valueOf", function() {})
+    gc()
+} catch (e) { print(e); }
+try {
+    (function() {
+        x.valueOf =
+        (function() {
+                y();
+        })
+    })()
+    x + 2
+    print('foo')
+} catch (e) { print(e); }
--- a/js/src/jit-test/tests/generators/es6-syntax.js
+++ b/js/src/jit-test/tests/generators/es6-syntax.js
@@ -27,12 +27,8 @@ assertSyntaxError("function* f(...yield)
 // For each.
 assertSyntaxError("for yield");
 assertSyntaxError("for yield (;;) {}");
 assertSyntaxError("for yield (x of y) {}");
 assertSyntaxError("for yield (var i in o) {}");
 
 // Expression bodies.
 assertSyntaxError("function* f() yield 7");
-
-// Asm.js.
-load(libdir + "asm.js");
-assertAsmDirectiveFail("function* f() { 'use asm'; function g() { return 0; } return g; })()")
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug925305.js
@@ -0,0 +1,14 @@
+function testFloat32SetElemIC(a) {
+  for (var i = 0; i < a.length; i++) {
+    var r = Math.fround(Math.random());
+    a[i] = r;
+    assertEq(a[i], r);
+  }
+}
+
+testFloat32SetElemIC(new Array(2048));
+testFloat32SetElemIC(new Array(2048));
+
+enableOsiPointRegisterChecks();
+testFloat32SetElemIC(new Array(2048));
+testFloat32SetElemIC(new Float64Array(2048));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/bug909743.js
@@ -0,0 +1,21 @@
+if (getBuildConfiguration().parallelJS) {
+  function assertParallelExecSucceeds(opFunction) {
+    for (var i = 0; i < 100; ++i) {
+      opFunction({mode:"compile"});
+    }
+  }
+  function assertArraySeqParResultsEq(arr, op, func) {
+    assertParallelExecSucceeds(
+      function (m) { 
+        return arr[op + "Par"].apply(arr, [func, m]); 
+      }
+    );
+  }
+  function range(n, m) {
+    var result = [];
+    for (var i = n; i < m; i++)
+      result.push(i);
+    return result;
+  }
+  assertArraySeqParResultsEq(range(0, 512), "map", function(e) { return e+'x'; });
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/ic-setelement.js
@@ -0,0 +1,135 @@
+load(libdir + "parallelarray-helpers.js");
+
+function set(a, n) {
+  // Padding to prevent inlining.
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  for (var i = 0; i < n; i++)
+    a[i] = i;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+}
+set({}, 1024);
+set({}, 1024);
+function Foo() { }
+set(new Foo, 1024);
+
+function testSetDense() {
+  assertArraySeqParResultsEq(
+    range(0, minItemsTestingThreshold),
+    "map",
+    function (i) {
+      var a1 = [];
+      // Defines .foo
+      set(a1, i+1);
+      return a1[i];
+    });
+}
+
+if (getBuildConfiguration().parallelJS) {
+  testSetDense();
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/parallel/ic-setproperty.js
@@ -0,0 +1,111 @@
+load(libdir + "parallelarray-helpers.js");
+
+function set(o, v) {
+  // Padding to prevent inlining.
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  o.foo = v;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+  var foo = 0;
+}
+set({ foo: 0 }, 42);
+
+function testSetPropertySlot() {
+  assertArraySeqParResultsEq(
+    range(0, minItemsTestingThreshold),
+    "map",
+    function (i) {
+      var o1 = {};
+      var o2 = {};
+      var o3 = {};
+      var o4 = {};
+      // Defines .foo
+      set(o1, i + 1);
+      set(o2, i + 2);
+      set(o3, i + 3);
+      set(o4, i + 4);
+      // Sets .foo
+      set(o1, i + 5);
+      set(o2, i + 6);
+      set(o3, i + 7);
+      set(o4, i + 8);
+      return o1.foo + o2.foo + o3.foo + o4.foo;
+    });
+}
+
+function testSetArrayLength() {
+  assertArraySeqParResultsEq(
+    range(0, minItemsTestingThreshold),
+    "map",
+    function (i) {
+      var a = [];
+      a.length = i;
+      return a.length;
+    });
+}
+
+if (getBuildConfiguration().parallelJS) {
+  testSetPropertySlot();
+  testSetArrayLength();
+}
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -6477,16 +6477,19 @@ EstablishPreconditions(ExclusiveContext 
         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by javascript.options.asmjs in about:config");
 
     if (!parser.options().compileAndGo)
         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Temporarily disabled for event-handler and other cloneable scripts");
 
     if (cx->compartment()->debugMode())
         return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by debugger");
 
+    if (parser.pc->isGenerator())
+        return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by generator context");
+
 #ifdef JS_WORKER_THREADS
     if (ParallelCompilationEnabled(cx)) {
         if (!EnsureWorkerThreadsInitialized(cx))
             return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Failed compilation thread initialization");
     }
 #endif
 
     return true;
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1420,17 +1420,17 @@ jit::FinishBailoutToBaseline(BaselineBai
         return false;
 
     // Create arguments objects for bailed out frames, to maintain the invariant
     // that script->needsArgsObj() implies frame->hasArgsObj().
     RootedScript innerScript(cx, nullptr);
     RootedScript outerScript(cx, nullptr);
 
     JS_ASSERT(cx->currentlyRunningInJit());
-    IonFrameIterator iter(cx->mainThread().ionTop);
+    IonFrameIterator iter(cx);
 
     uint32_t frameno = 0;
     while (frameno < numFrames) {
         JS_ASSERT(!iter.isOptimizedJS());
 
         if (iter.isBaselineJS()) {
             BaselineFrame *frame = iter.baselineFrame();
 
--- a/js/src/jit/BaselineFrame.cpp
+++ b/js/src/jit/BaselineFrame.cpp
@@ -152,17 +152,17 @@ BaselineFrame::initForOsr(StackFrame *fp
     if (cx->compartment()->debugMode()) {
         // In debug mode, update any Debugger.Frame objects for the StackFrame to
         // point to the BaselineFrame.
 
         // The caller pushed a fake return address. ScriptFrameIter, used by the
         // debugger, wants a valid return address, but it's okay to just pick one.
         // In debug mode there's always at least 1 ICEntry (since there are always
         // debug prologue/epilogue calls).
-        IonFrameIterator iter(cx->mainThread().ionTop);
+        IonFrameIterator iter(cx);
         JS_ASSERT(iter.returnAddress() == nullptr);
         BaselineScript *baseline = fp->script()->baselineScript();
         iter.current()->setReturnAddress(baseline->returnAddressForIC(baseline->icEntry(0)));
 
         if (!Debugger::handleBaselineOsr(cx, fp, this))
             return false;
     }
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -18,16 +18,17 @@
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
 #include "jit/VMFunctions.h"
 
 #include "jsboolinlines.h"
 #include "jsscriptinlines.h"
 
+#include "jit/IonFrames-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/ScopeObject-inl.h"
 
 namespace js {
 namespace jit {
 
 #ifdef DEBUG
 void
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -149,17 +149,17 @@ CodeGenerator::CodeGenerator(MIRGenerato
 
 CodeGenerator::~CodeGenerator()
 {
     JS_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
     js_delete(unassociatedScriptCounts_);
 }
 
 typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
-typedef ParallelResult (*StringToNumberParFn)(ForkJoinSlice *, JSString *, double *);
+typedef bool (*StringToNumberParFn)(ForkJoinSlice *, JSString *, double *);
 static const VMFunctionsModal StringToNumberInfo = VMFunctionsModal(
     FunctionInfo<StringToNumberFn>(StringToNumber),
     FunctionInfo<StringToNumberParFn>(StringToNumberPar));
 
 bool
 CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
 {
     ValueOperand operand = ToValue(lir, LValueToInt32::Input);
@@ -644,17 +644,17 @@ CodeGenerator::visitTypeObjectDispatch(L
 
     // Unknown function: jump to fallback block.
     LBlock *fallback = mir->getFallback()->lir();
     masm.jump(fallback->label());
     return true;
 }
 
 typedef JSFlatString *(*IntToStringFn)(ThreadSafeContext *, int);
-typedef ParallelResult (*IntToStringParFn)(ForkJoinSlice *, int, MutableHandleString);
+typedef JSFlatString *(*IntToStringParFn)(ForkJoinSlice *, int);
 static const VMFunctionsModal IntToStringInfo = VMFunctionsModal(
     FunctionInfo<IntToStringFn>(Int32ToString<CanGC>),
     FunctionInfo<IntToStringParFn>(IntToStringPar));
 
 bool
 CodeGenerator::visitIntToString(LIntToString *lir)
 {
     Register input = ToRegister(lir->input());
@@ -671,17 +671,17 @@ CodeGenerator::visitIntToString(LIntToSt
     masm.movePtr(ImmPtr(&GetIonContext()->runtime->staticStrings.intStaticTable), output);
     masm.loadPtr(BaseIndex(output, input, ScalePointer), output);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 typedef JSString *(*DoubleToStringFn)(ThreadSafeContext *, double);
-typedef ParallelResult (*DoubleToStringParFn)(ForkJoinSlice *, double, MutableHandleString);
+typedef JSString *(*DoubleToStringParFn)(ForkJoinSlice *, double);
 static const VMFunctionsModal DoubleToStringInfo = VMFunctionsModal(
     FunctionInfo<DoubleToStringFn>(NumberToString<CanGC>),
     FunctionInfo<DoubleToStringParFn>(DoubleToStringPar));
 
 bool
 CodeGenerator::visitDoubleToString(LDoubleToString *lir)
 {
     FloatRegister input = ToFloatRegister(lir->input());
@@ -985,17 +985,16 @@ CodeGenerator::visitParameter(LParameter
 bool
 CodeGenerator::visitCallee(LCallee *lir)
 {
     // read number of actual arguments from the JS frame.
     Register callee = ToRegister(lir->output());
     Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfCalleeToken());
 
     masm.loadPtr(ptr, callee);
-    masm.clearCalleeTag(callee, gen->info().executionMode());
     return true;
 }
 
 bool
 CodeGenerator::visitStart(LStart *lir)
 {
     return true;
 }
@@ -1850,17 +1849,17 @@ CodeGenerator::visitCallGeneric(LCallGen
     masm.loadBaselineOrIonRaw(objreg, objreg, executionMode, &invoke);
 
     // Nestle the StackPointer up to the argument vector.
     masm.freeStack(unusedStack);
 
     // Construct the IonFramePrefix.
     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), IonFrame_OptimizedJS);
     masm.Push(Imm32(call->numActualArgs()));
-    masm.PushCalleeToken(calleereg, executionMode);
+    masm.Push(calleereg);
     masm.Push(Imm32(descriptor));
 
     // Check whether the provided arguments satisfy target argc.
     masm.load16ZeroExtend(Address(calleereg, offsetof(JSFunction, nargs)), nargsreg);
     masm.cmp32(nargsreg, Imm32(call->numStackArgs()));
     masm.j(Assembler::Above, &thunk);
 
     masm.jump(&makeCall);
@@ -1971,17 +1970,17 @@ CodeGenerator::visitCallKnown(LCallKnown
         masm.loadBaselineOrIonNoArgCheck(objreg, objreg, executionMode, &uncompiled);
 
     // Nestle the StackPointer up to the argument vector.
     masm.freeStack(unusedStack);
 
     // Construct the IonFramePrefix.
     uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), IonFrame_OptimizedJS);
     masm.Push(Imm32(call->numActualArgs()));
-    masm.PushCalleeToken(calleereg, executionMode);
+    masm.Push(calleereg);
     masm.Push(Imm32(descriptor));
 
     // Finally call the function in objreg.
     uint32_t callOffset = masm.callIon(objreg);
     if (!markSafepointAt(callOffset, call))
         return false;
 
     // Increment to remove IonFramePrefix; decrement to fill FrameSizeClass.
@@ -3858,17 +3857,17 @@ CodeGenerator::visitModD(LModD *ins)
     if (gen->compilingAsmJS())
         masm.callWithABI(AsmJSImm_ModD, MacroAssembler::DOUBLE);
     else
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NumberMod), MacroAssembler::DOUBLE);
     return true;
 }
 
 typedef bool (*BinaryFn)(JSContext *, MutableHandleValue, MutableHandleValue, Value *);
-typedef ParallelResult (*BinaryParFn)(ForkJoinSlice *, HandleValue, HandleValue, Value *);
+typedef bool (*BinaryParFn)(ForkJoinSlice *, HandleValue, HandleValue, Value *);
 
 static const VMFunction AddInfo = FunctionInfo<BinaryFn>(js::AddValues);
 static const VMFunction SubInfo = FunctionInfo<BinaryFn>(js::SubValues);
 static const VMFunction MulInfo = FunctionInfo<BinaryFn>(js::MulValues);
 static const VMFunction DivInfo = FunctionInfo<BinaryFn>(js::DivValues);
 static const VMFunction ModInfo = FunctionInfo<BinaryFn>(js::ModValues);
 static const VMFunctionsModal UrshInfo = VMFunctionsModal(
     FunctionInfo<BinaryFn>(js::UrshValues),
@@ -3900,17 +3899,17 @@ CodeGenerator::visitBinaryV(LBinaryV *li
         return callVM(UrshInfo, lir);
 
       default:
         MOZ_ASSUME_UNREACHABLE("Unexpected binary op");
     }
 }
 
 typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, bool *);
-typedef ParallelResult (*StringCompareParFn)(ForkJoinSlice *, HandleString, HandleString, bool *);
+typedef bool (*StringCompareParFn)(ForkJoinSlice *, HandleString, HandleString, bool *);
 static const VMFunctionsModal StringsEqualInfo = VMFunctionsModal(
     FunctionInfo<StringCompareFn>(jit::StringsEqual<true>),
     FunctionInfo<StringCompareParFn>(jit::StringsEqualPar));
 static const VMFunctionsModal StringsNotEqualInfo = VMFunctionsModal(
     FunctionInfo<StringCompareFn>(jit::StringsEqual<false>),
     FunctionInfo<StringCompareParFn>(jit::StringsUnequalPar));
 
 bool
@@ -3972,18 +3971,17 @@ CodeGenerator::visitCompareS(LCompareS *
     Register right = ToRegister(lir->right());
     Register output = ToRegister(lir->output());
     Register temp = ToRegister(lir->temp());
 
     return emitCompareS(lir, op, left, right, output, temp);
 }
 
 typedef bool (*CompareFn)(JSContext *, MutableHandleValue, MutableHandleValue, bool *);
-typedef ParallelResult (*CompareParFn)(ForkJoinSlice *, MutableHandleValue, MutableHandleValue,
-                                       bool *);
+typedef bool (*CompareParFn)(ForkJoinSlice *, MutableHandleValue, MutableHandleValue, bool *);
 static const VMFunctionsModal EqInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(jit::LooselyEqual<true>),
     FunctionInfo<CompareParFn>(jit::LooselyEqualPar));
 static const VMFunctionsModal NeInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(jit::LooselyEqual<false>),
     FunctionInfo<CompareParFn>(jit::LooselyUnequalPar));
 static const VMFunctionsModal StrictEqInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(jit::StrictlyEqual<true>),
@@ -4256,18 +4254,17 @@ CodeGenerator::visitEmulatesUndefinedAnd
 
     Register objreg = ToRegister(lir->input());
 
     testObjectTruthy(objreg, unequal, equal, ToRegister(lir->temp()), ool);
     return true;
 }
 
 typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
-typedef ParallelResult (*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString,
-                                             MutableHandleString);
+typedef JSString *(*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString);
 static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
     FunctionInfo<ConcatStringsFn>(ConcatStrings<CanGC>),
     FunctionInfo<ConcatStringsParFn>(ConcatStringsPar));
 
 bool
 CodeGenerator::emitConcat(LInstruction *lir, Register lhs, Register rhs, Register output)
 {
     OutOfLineCode *ool = oolCallVM(ConcatStringsInfo, lir, (ArgList(), lhs, rhs),
@@ -4452,25 +4449,36 @@ IonCompartment::generateStringConcatStub
     masm.lshiftPtr(Imm32(JSString::LENGTH_SHIFT), temp2);
     masm.orPtr(Imm32(JSString::FIXED_FLAGS), temp2);
     masm.storePtr(temp2, Address(output, JSString::offsetOfLengthAndFlags()));
 
     // Set chars pointer, keep in temp2 for copy loop below.
     masm.computeEffectiveAddress(Address(output, JSShortString::offsetOfInlineStorage()), temp2);
     masm.storePtr(temp2, Address(output, JSShortString::offsetOfChars()));
 
-    // Copy lhs chars. Temp1 still holds the lhs length. Note that this
-    // advances temp2 to point to the next char.
-    masm.loadPtr(Address(lhs, JSString::offsetOfChars()), temp3);
-    CopyStringChars(masm, temp2, temp3, temp1, temp4);
-
-    // Copy rhs chars.
-    masm.loadPtr(Address(rhs, JSString::offsetOfChars()), temp3);
-    masm.loadStringLength(rhs, temp1);
-    CopyStringChars(masm, temp2, temp3, temp1, temp4);
+    {
+        // We use temp4 in this block, which in parallel execution also holds
+        // a live ForkJoinSlice pointer. If we are compiling for parallel
+        // execution, be sure to save and restore the ForkJoinSlice.
+        if (mode == ParallelExecution)
+            masm.push(temp4);
+
+        // Copy lhs chars. Temp1 still holds the lhs length. Note that this
+        // advances temp2 to point to the next char.
+        masm.loadPtr(Address(lhs, JSString::offsetOfChars()), temp3);
+        CopyStringChars(masm, temp2, temp3, temp1, temp4);
+
+        // Copy rhs chars.
+        masm.loadPtr(Address(rhs, JSString::offsetOfChars()), temp3);
+        masm.loadStringLength(rhs, temp1);
+        CopyStringChars(masm, temp2, temp3, temp1, temp4);
+
+        if (mode == ParallelExecution)
+            masm.pop(temp4);
+    }
 
     // Null-terminate.
     masm.store16(Imm32(0), Address(temp2, 0));
     masm.ret();
 
     masm.bind(&failurePopTemps);
     masm.pop(temp2);
     masm.pop(temp1);
@@ -4499,19 +4507,18 @@ CodeGenerator::visitCharCodeAt(LCharCode
     Register index = ToRegister(lir->index());
     Register output = ToRegister(lir->output());
 
     OutOfLineCode *ool = oolCallVM(CharCodeAtInfo, lir, (ArgList(), str, index), StoreRegisterTo(output));
     if (!ool)
         return false;
 
     Address lengthAndFlagsAddr(str, JSString::offsetOfLengthAndFlags());
-    masm.loadPtr(lengthAndFlagsAddr, output);
-
-    masm.branchTest32(Assembler::Zero, output, Imm32(JSString::FLAGS_MASK), ool->entry());
+
+    masm.branchTest32(Assembler::Zero, lengthAndFlagsAddr, Imm32(JSString::FLAGS_MASK), ool->entry());
 
     // getChars
     Address charsAddr(str, JSString::offsetOfChars());
     masm.loadPtr(charsAddr, output);
     masm.load16ZeroExtend(BaseIndex(output, index, TimesTwo, 0), output);
 
     masm.bind(ool->rejoin());
     return true;
@@ -4839,18 +4846,17 @@ 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);
-typedef ParallelResult (*SetElementParFn)(ForkJoinSlice *, HandleObject, HandleValue,
-                                          HandleValue, bool);
+typedef bool (*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;
@@ -5447,19 +5453,18 @@ CodeGenerator::visitRunOncePrologue(LRun
 {
     pushArg(ImmGCPtr(lir->mir()->block()->info().script()));
     return callVM(RunOnceScriptPrologueInfo, lir);
 }
 
 
 typedef JSObject *(*InitRestParameterFn)(JSContext *, uint32_t, Value *, HandleObject,
                                          HandleObject);
-typedef ParallelResult (*InitRestParameterParFn)(ForkJoinSlice *, uint32_t, Value *,
-                                                 HandleObject, HandleObject,
-                                                 MutableHandleObject);
+typedef JSObject *(*InitRestParameterParFn)(ForkJoinSlice *, uint32_t, Value *,
+                                            HandleObject, HandleObject);
 static const VMFunctionsModal InitRestParameterInfo = VMFunctionsModal(
     FunctionInfo<InitRestParameterFn>(InitRestParameter),
     FunctionInfo<InitRestParameterParFn>(InitRestParameterPar));
 
 bool
 CodeGenerator::emitRest(LInstruction *lir, Register array, Register numActuals,
                         Register temp0, Register temp1, unsigned numFormals,
                         JSObject *templateObject)
@@ -6025,16 +6030,54 @@ CodeGenerator::addGetPropertyCache(LInst
         return addCache(ins, allocateCache(cache));
       }
       default:
         MOZ_ASSUME_UNREACHABLE("Bad execution mode");
     }
 }
 
 bool
+CodeGenerator::addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
+                                   PropertyName *name, ConstantOrRegister value, bool strict,
+                                   bool needsTypeBarrier)
+{
+    switch (gen->info().executionMode()) {
+      case SequentialExecution: {
+          SetPropertyIC cache(liveRegs, objReg, name, value, strict, needsTypeBarrier);
+          return addCache(ins, allocateCache(cache));
+      }
+      case ParallelExecution: {
+          SetPropertyParIC cache(objReg, name, value, strict, needsTypeBarrier);
+          return addCache(ins, allocateCache(cache));
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad execution mode");
+    }
+}
+
+bool
+CodeGenerator::addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex,
+                                  Register temp, FloatRegister tempFloat, ValueOperand index,
+                                  ConstantOrRegister value, bool strict)
+{
+    switch (gen->info().executionMode()) {
+      case SequentialExecution: {
+        SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict);
+        return addCache(ins, allocateCache(cache));
+      }
+      case ParallelExecution: {
+        SetElementParIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict);
+        return addCache(ins, allocateCache(cache));
+      }
+      default:
+        MOZ_ASSUME_UNREACHABLE("Bad execution mode");
+    }
+}
+
+bool
 CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     PropertyName *name = ins->mir()->name();
     bool allowGetters = ins->mir()->allowGetters();
     TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
 
@@ -6077,18 +6120,17 @@ CodeGenerator::visitGetPropertyIC(OutOfL
         return false;
     StoreValueTo(ic->output()).generate(this);
     restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
 
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef ParallelResult (*GetPropertyParICFn)(ForkJoinSlice *, size_t, HandleObject,
-                                             MutableHandleValue);
+typedef bool (*GetPropertyParICFn)(ForkJoinSlice *, size_t, HandleObject, MutableHandleValue);
 const VMFunction GetPropertyParIC::UpdateInfo =
     FunctionInfo<GetPropertyParICFn>(GetPropertyParIC::update);
 
 bool
 CodeGenerator::visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic)
 {
     LInstruction *lir = ool->lir();
     saveLive(lir);
@@ -6169,19 +6211,18 @@ CodeGenerator::visitSetElementCacheV(LSe
 {
     Register obj = ToRegister(ins->object());
     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
     Register temp = ToRegister(ins->temp());
     FloatRegister tempFloat = ToFloatRegister(ins->tempFloat());
     ValueOperand index = ToValue(ins, LSetElementCacheV::Index);
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetElementCacheV::Value));
 
-    SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, ins->mir()->strict());
-
-    return addCache(ins, allocateCache(cache));
+    return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
+                              ins->mir()->strict());
 }
 
 bool
 CodeGenerator::visitSetElementCacheT(LSetElementCacheT *ins)
 {
     Register obj = ToRegister(ins->object());
     Register unboxIndex = ToTempUnboxRegister(ins->tempToUnboxIndex());
     Register temp = ToRegister(ins->temp());
@@ -6189,19 +6230,18 @@ CodeGenerator::visitSetElementCacheT(LSe
     ValueOperand index = ToValue(ins, LSetElementCacheT::Index);
     ConstantOrRegister value;
     const LAllocation *tmp = ins->value();
     if (tmp->isConstant())
         value = *tmp->toConstant();
     else
         value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(tmp));
 
-    SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, ins->mir()->strict());
-
-    return addCache(ins, allocateCache(cache));
+    return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
+                              ins->mir()->strict());
 }
 
 typedef bool (*SetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, HandleValue);
 const VMFunction SetElementIC::UpdateInfo =
     FunctionInfo<SetElementICFn>(SetElementIC::update);
 
 bool
 CodeGenerator::visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic)
@@ -6216,18 +6256,40 @@ CodeGenerator::visitSetElementIC(OutOfLi
     if (!callVM(SetElementIC::UpdateInfo, lir))
         return false;
     restoreLive(lir);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
-typedef ParallelResult (*GetElementParICFn)(ForkJoinSlice *, size_t, HandleObject,
-                                            HandleValue, MutableHandleValue);
+typedef bool (*SetElementParICFn)(ForkJoinSlice *, size_t, HandleObject, HandleValue, HandleValue);
+const VMFunction SetElementParIC::UpdateInfo =
+    FunctionInfo<SetElementParICFn>(SetElementParIC::update);
+
+bool
+CodeGenerator::visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic)
+{
+    LInstruction *lir = ool->lir();
+    saveLive(lir);
+
+    pushArg(ic->value());
+    pushArg(ic->index());
+    pushArg(ic->object());
+    pushArg(Imm32(ool->getCacheIndex()));
+    if (!callVM(SetElementParIC::UpdateInfo, lir))
+        return false;
+    restoreLive(lir);
+
+    masm.jump(ool->rejoin());
+    return true;
+}
+
+typedef bool (*GetElementParICFn)(ForkJoinSlice *, size_t, HandleObject, HandleValue,
+                                  MutableHandleValue);
 const VMFunction GetElementParIC::UpdateInfo =
     FunctionInfo<GetElementParICFn>(GetElementParIC::update);
 
 bool
 CodeGenerator::visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic)
 {
     LInstruction *lir = ool->lir();
     saveLive(lir);
@@ -6272,18 +6334,21 @@ CodeGenerator::visitBindNameIC(OutOfLine
     restoreLiveIgnore(lir, StoreRegisterTo(ic->outputReg()).clobbered());
 
     masm.jump(ool->rejoin());
     return true;
 }
 
 typedef bool (*SetPropertyFn)(JSContext *, HandleObject,
                               HandlePropertyName, const HandleValue, bool, jsbytecode *);
-static const VMFunction SetPropertyInfo =
-    FunctionInfo<SetPropertyFn>(SetProperty);
+typedef bool (*SetPropertyParFn)(ForkJoinSlice *, HandleObject,
+                                 HandlePropertyName, const HandleValue, bool, jsbytecode *);
+static const VMFunctionsModal SetPropertyInfo = VMFunctionsModal(
+    FunctionInfo<SetPropertyFn>(SetProperty),
+    FunctionInfo<SetPropertyParFn>(SetPropertyPar));
 
 bool
 CodeGenerator::visitCallSetProperty(LCallSetProperty *ins)
 {
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LCallSetProperty::Value));
 
     const Register objReg = ToRegister(ins->getOperand(0));
 
@@ -6335,36 +6400,34 @@ CodeGenerator::visitCallDeleteElement(LC
 
 bool
 CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
 
-    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value, ins->mir()->strict(),
-                        ins->mir()->needsTypeBarrier());
-    return addCache(ins, allocateCache(cache));
+    return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
+                               ins->mir()->strict(), ins->mir()->needsTypeBarrier());
 }
 
 bool
 CodeGenerator::visitSetPropertyCacheT(LSetPropertyCacheT *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value;
 
     if (ins->getOperand(1)->isConstant())
         value = ConstantOrRegister(*ins->getOperand(1)->toConstant());
     else
         value = TypedOrValueRegister(ins->valueType(), ToAnyRegister(ins->getOperand(1)));
 
-    SetPropertyIC cache(liveRegs, objReg, ins->mir()->name(), value, ins->mir()->strict(),
-                        ins->mir()->needsTypeBarrier());
-    return addCache(ins, allocateCache(cache));
+    return addSetPropertyCache(ins, liveRegs, objReg, ins->mir()->name(), value,
+                               ins->mir()->strict(), ins->mir()->needsTypeBarrier());
 }
 
 typedef bool (*SetPropertyICFn)(JSContext *, size_t, HandleObject, HandleValue);
 const VMFunction SetPropertyIC::UpdateInfo =
     FunctionInfo<SetPropertyICFn>(SetPropertyIC::update);
 
 bool
 CodeGenerator::visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic)
@@ -6378,41 +6441,62 @@ CodeGenerator::visitSetPropertyIC(OutOfL
     if (!callVM(SetPropertyIC::UpdateInfo, lir))
         return false;
     restoreLive(lir);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
+typedef bool (*SetPropertyParICFn)(ForkJoinSlice *, size_t, HandleObject, HandleValue);
+const VMFunction SetPropertyParIC::UpdateInfo =
+    FunctionInfo<SetPropertyParICFn>(SetPropertyParIC::update);
+
+bool
+CodeGenerator::visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic)
+{
+    LInstruction *lir = ool->lir();
+    saveLive(lir);
+
+    pushArg(ic->value());
+    pushArg(ic->object());
+    pushArg(Imm32(ool->getCacheIndex()));
+    if (!callVM(SetPropertyParIC::UpdateInfo, lir))
+        return false;
+    restoreLive(lir);
+
+    masm.jump(ool->rejoin());
+    return true;
+}
+
 typedef bool (*ThrowFn)(JSContext *, HandleValue);
 static const VMFunction ThrowInfo = FunctionInfo<ThrowFn>(js::Throw);
 
 bool
 CodeGenerator::visitThrow(LThrow *lir)
 {
     pushArg(ToValue(lir, LThrow::Value));
     return callVM(ThrowInfo, lir);
 }
 
 typedef bool (*BitNotFn)(JSContext *, HandleValue, int *p);
-typedef ParallelResult (*BitNotParFn)(ForkJoinSlice *, HandleValue, int32_t *);
+typedef bool (*BitNotParFn)(ForkJoinSlice *, HandleValue, int32_t *);
 static const VMFunctionsModal BitNotInfo = VMFunctionsModal(
     FunctionInfo<BitNotFn>(BitNot),
     FunctionInfo<BitNotParFn>(BitNotPar));
 
 bool
 CodeGenerator::visitBitNotV(LBitNotV *lir)
 {
     pushArg(ToValue(lir, LBitNotV::Input));
     return callVM(BitNotInfo, lir);
 }
 
 typedef bool (*BitopFn)(JSContext *, HandleValue, HandleValue, int *p);
-typedef ParallelResult (*BitopParFn)(ForkJoinSlice *, HandleValue, HandleValue, int32_t *);
+typedef bool (*BitopParFn)(ForkJoinSlice *, HandleValue, HandleValue, int32_t *);
 static const VMFunctionsModal BitAndInfo = VMFunctionsModal(
     FunctionInfo<BitopFn>(BitAnd),
     FunctionInfo<BitopParFn>(BitAndPar));
 static const VMFunctionsModal BitOrInfo = VMFunctionsModal(
     FunctionInfo<BitopFn>(BitOr),
     FunctionInfo<BitopParFn>(BitOrPar));
 static const VMFunctionsModal BitXorInfo = VMFunctionsModal(
     FunctionInfo<BitopFn>(BitXor),
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -307,19 +307,21 @@ class CodeGenerator : public CodeGenerat
     bool visitSetPropertyCacheV(LSetPropertyCacheV *ins);
     bool visitSetPropertyCacheT(LSetPropertyCacheT *ins);
     bool visitGetNameCache(LGetNameCache *ins);
     bool visitCallsiteCloneCache(LCallsiteCloneCache *ins);
 
     bool visitGetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyIC> &ic);
     bool visitGetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<GetPropertyParIC> &ic);
     bool visitSetPropertyIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyIC> &ic);
+    bool visitSetPropertyParIC(OutOfLineUpdateCache *ool, DataPtr<SetPropertyParIC> &ic);
     bool visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic);
     bool visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic);
     bool visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic);
+    bool visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic);
     bool visitBindNameIC(OutOfLineUpdateCache *ool, DataPtr<BindNameIC> &ic);
     bool visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic);
     bool visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic);
 
     bool visitAssertRangeI(LAssertRangeI *ins);
     bool visitAssertRangeD(LAssertRangeD *ins);
     bool visitAssertRangeF(LAssertRangeF *ins);
     bool visitAssertRangeV(LAssertRangeV *ins);
@@ -331,16 +333,22 @@ class CodeGenerator : public CodeGenerat
     }
 
   private:
     bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                              PropertyName *name, TypedOrValueRegister output,
                              bool allowGetters);
     bool addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
                             TypedOrValueRegister output, bool monitoredResult);
+    bool addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
+                             PropertyName *name, ConstantOrRegister value, bool strict,
+                             bool needsTypeBarrier);
+    bool addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex, Register temp,
+                            FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
+                            bool strict);
     bool checkForAbortPar(LInstruction *lir);
 
     bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
 
     bool emitAllocateGCThingPar(LInstruction *lir, const Register &objReg, const Register &sliceReg,
                                 const Register &tempReg1, const Register &tempReg2,
                                 JSObject *templateObj);
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2176,17 +2176,17 @@ jit::FastInvoke(JSContext *cx, HandleFun
 
 static void
 InvalidateActivation(FreeOp *fop, uint8_t *ionTop, bool invalidateAll)
 {
     IonSpew(IonSpew_Invalidate, "BEGIN invalidating activation");
 
     size_t frameno = 1;
 
-    for (IonFrameIterator it(ionTop); !it.done(); ++it, ++frameno) {
+    for (IonFrameIterator it(ionTop, SequentialExecution); !it.done(); ++it, ++frameno) {
         JS_ASSERT_IF(frameno == 1, it.type() == IonFrame_Exit);
 
 #ifdef DEBUG
         switch (it.type()) {
           case IonFrame_Exit:
             IonSpew(IonSpew_Invalidate, "#%d exit frame @ %p", frameno, it.fp());
             break;
           case IonFrame_BaselineJS:
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -229,17 +229,17 @@ IsPhiObservable(MPhi *phi, Observability
         }
     }
     return false;
 }
 
 // Handles cases like:
 //    x is phi(a, x) --> a
 //    x is phi(a, a) --> a
-inline MDefinition *
+static inline MDefinition *
 IsPhiRedundant(MPhi *phi)
 {
     MDefinition *first = phi->operandIfRedundant();
     if (first == nullptr)
         return nullptr;
 
     // Propagate the Folded flag if |phi| is replaced with another phi.
     if (phi->isFolded())
@@ -1911,17 +1911,17 @@ AnalyzePoppedThis(JSContext *cx, types::
                   bool *phandled)
 {
     // Determine the effect that a use of the |this| value when calling |new|
     // on a script has on the properties definitely held by the new object.
 
     if (ins->isCallSetProperty()) {
         MCallSetProperty *setprop = ins->toCallSetProperty();
 
-        if (setprop->obj() != thisValue)
+        if (setprop->object() != thisValue)
             return true;
 
         // Don't use GetAtomId here, we need to watch for SETPROP on
         // integer properties and bail out. We can't mark the aggregate
         // JSID_VOID type property as being in a definite slot.
         if (setprop->name() == cx->names().classPrototype ||
             setprop->name() == cx->names().proto ||
             setprop->name() == cx->names().constructor)
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -3955,17 +3955,17 @@ IonBuilder::makeInliningDecision(JSFunct
             IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: callee is not hot.",
                     targetScript->filename(), targetScript->lineno);
             return false;
         }
     }
 
     // TI calls ObjectStateChange to trigger invalidation of the caller.
     types::TypeObjectKey *targetType = types::TypeObjectKey::get(target);
-    targetType->watchStateChange(constraints());
+    targetType->watchStateChangeForInlinedCall(constraints());
 
     return true;
 }
 
 uint32_t
 IonBuilder::selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, BoolVector &choiceSet)
 {
     uint32_t totalSize = 0;
@@ -4638,17 +4638,17 @@ IonBuilder::createThisScriptedSingleton(
     RootedObject targetRoot(cx, target);
     JSObject *templateObject = CreateThisForFunctionWithProto(cx, targetRoot, proto, TenuredObject);
     if (!templateObject)
         return nullptr;
 
     // Trigger recompilation if the templateObject changes.
     types::TypeObjectKey *templateType = types::TypeObjectKey::get(templateObject);
     if (templateType->newScript())
-        templateType->watchStateChange(constraints());
+        templateType->watchStateChangeForNewScriptTemplate(constraints());
 
     MCreateThisWithTemplate *createThis = MCreateThisWithTemplate::New(templateObject);
     current->add(createThis);
 
     return createThis;
 }
 
 MDefinition *
@@ -6881,17 +6881,17 @@ IonBuilder::getTypedArrayElements(MDefin
 {
     if (obj->isConstant() && obj->toConstant()->value().isObject()) {
         TypedArrayObject *tarr = &obj->toConstant()->value().toObject().as<TypedArrayObject>();
         void *data = tarr->viewData();
 
         // The 'data' pointer can change in rare circumstances
         // (ArrayBufferObject::changeContents).
         types::TypeObjectKey *tarrType = types::TypeObjectKey::get(tarr);
-        tarrType->watchStateChange(constraints());
+        tarrType->watchStateChangeForTypedArrayBuffer(constraints());
 
         obj->setFoldedUnchecked();
         return MConstantElements::New(data);
     }
     return MTypedArrayElements::New(obj);
 }
 
 MDefinition *
@@ -7595,38 +7595,38 @@ IonBuilder::jsop_not()
 
     MNot *ins = new MNot(value);
     current->add(ins);
     current->push(ins);
     ins->infer();
     return true;
 }
 
-inline bool
+static inline bool
 TestClassHasAccessorHook(const Class *clasp, bool isGetter)
 {
     if (isGetter && clasp->ops.getGeneric)
         return true;
     if (!isGetter && clasp->ops.setGeneric)
         return true;
     return false;
 }
 
-inline bool
+static inline bool
 TestTypeHasOwnProperty(types::TypeObjectKey *typeObj, PropertyName *name, bool &cont)
 {
     cont = true;
     types::HeapTypeSetKey propSet = typeObj->property(NameToId(name));
     if (!propSet.actualTypes->empty())
         cont = false;
     // Note: Callers must explicitly freeze the property type set later on if optimizing.
     return true;
 }
 
-inline bool
+static inline bool
 TestCommonAccessorProtoChain(JSContext *cx, PropertyName *name,
                              bool isGetter, JSObject *foundProto,
                              JSObject *obj, bool &cont)
 {
     cont = false;
     JSObject *curObj = obj;
     JSObject *stopAt = foundProto->getProto();
     while (curObj != stopAt) {
@@ -7662,17 +7662,17 @@ TestCommonAccessorProtoChain(JSContext *
         }
 
         curObj = curObj->getProto();
     }
     cont = true;
     return true;
 }
 
-inline bool
+static inline bool
 SearchCommonPropFunc(JSContext *cx, types::TemporaryTypeSet *types,
                      PropertyName *name, bool isGetter,
                      JSObject *&found, JSObject *&foundProto, bool &cont)
 {
     cont = false;
     for (unsigned i = 0; i < types->getObjectCount(); i++) {
         RootedObject curObj(cx, types->getSingleObject(i));
 
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -13,19 +13,21 @@
 #include "builtin/TypeRepresentation.h"
 #include "jit/Ion.h"
 #include "jit/IonLinker.h"
 #include "jit/IonSpewer.h"
 #include "jit/Lowering.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
 #endif
+#include "jit/ParallelFunctions.h"
 #include "jit/VMFunctions.h"
 #include "vm/Shape.h"
 
+#include "jit/IonFrames-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
@@ -1219,17 +1221,17 @@ GetPropertyIC::tryAttachNative(JSContext
 
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
     const char *attachKind;
 
     switch (type) {
       case CanAttachReadSlot:
         GenerateReadSlot(cx, ion, masm, attacher, obj, holder,
-                            shape, object(), output());
+                         shape, object(), output());
         attachKind = idempotent() ? "idempotent reading"
                                     : "non idempotent reading";
         break;
       case CanAttachCallGetter:
         masm.setFramePushed(ion->frameSize());
         if (!GenerateCallGetter(cx, ion, masm, attacher, obj, name, holder, shape,
                                 liveRegs_, object(), output(), returnAddr))
         {
@@ -1844,83 +1846,83 @@ GetPropertyParIC::attachTypedArrayLength
     DispatchStubPrepender attacher(*this);
     GenerateTypedArrayLength(cx, masm, attacher, obj, object(), output());
 
     JS_ASSERT(!hasTypedArrayLengthStub_);
     hasTypedArrayLengthStub_ = true;
     return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array length");
 }
 
-ParallelResult
+bool
 GetPropertyParIC::update(ForkJoinSlice *slice, size_t cacheIndex,
                          HandleObject obj, MutableHandleValue vp)
 {
     AutoFlushCache afc("GetPropertyParCache", slice->runtime()->ionRuntime());
 
     IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
     GetPropertyParIC &cache = ion->getCache(cacheIndex).toGetPropertyPar();
 
     // Grab the property early, as the pure path is fast anyways and doesn't
     // need a lock. If we can't do it purely, bail out of parallel execution.
     if (!GetPropertyPure(slice, obj, NameToId(cache.name()), vp.address()))
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
 
     // Avoid unnecessary locking if cannot attach stubs.
     if (!cache.canAttachStub())
-        return TP_SUCCESS;
+        return true;
 
     {
         // Lock the context before mutating the cache. Ideally we'd like to do
         // finer-grained locking, with one lock per cache. However, generating
         // new jitcode uses a global ExecutableAllocator tied to the runtime.
         LockedJSContext cx(slice);
 
         if (cache.canAttachStub()) {
             bool alreadyStubbed;
             if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
-                return TP_FATAL;
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
             if (alreadyStubbed)
-                return TP_SUCCESS;
+                return true;
 
             // See note about the stub limit in GetPropertyCache.
             bool attachedStub = false;
 
             {
                 RootedShape shape(cx);
                 RootedObject holder(cx);
                 RootedPropertyName name(cx, cache.name());
 
                 GetPropertyIC::NativeGetPropCacheability canCache =
                     CanAttachNativeGetProp(cx, cache, obj, name, &holder, &shape);
 
                 if (canCache == GetPropertyIC::CanAttachReadSlot) {
                     if (!cache.attachReadSlot(cx, ion, obj, holder, shape))
-                        return TP_FATAL;
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                     attachedStub = true;
                 }
 
                 if (!attachedStub && canCache == GetPropertyIC::CanAttachArrayLength) {
                     if (!cache.attachArrayLength(cx, ion, obj))
-                        return TP_FATAL;
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                     attachedStub = true;
                 }
             }
 
             if (!attachedStub && !cache.hasTypedArrayLengthStub() &&
                 obj->is<TypedArrayObject>() && slice->names().length == cache.name() &&
                 (cache.output().type() == MIRType_Value || cache.output().type() == MIRType_Int32))
             {
                 if (!cache.attachTypedArrayLength(cx, ion, obj))
-                    return TP_FATAL;
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                 attachedStub = true;
             }
         }
     }
 
-    return TP_SUCCESS;
+    return true;
 }
 
 void
 IonCache::disable()
 {
     reset();
     this->disabled_ = 1;
 }
@@ -1931,108 +1933,112 @@ IonCache::reset()
     this->stubCount_ = 0;
 }
 
 void
 IonCache::destroy()
 {
 }
 
-bool
-SetPropertyIC::attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj,
-                                    HandleShape shape, bool checkTypeset)
+static void
+GenerateSetSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
+                JSObject *obj, Shape *shape, Register object, ConstantOrRegister value,
+                bool needsTypeBarrier, bool checkTypeset)
 {
     JS_ASSERT(obj->isNative());
 
-    MacroAssembler masm(cx);
-    RepatchStubAppender attacher(*this);
-
     Label failures, barrierFailure;
     masm.branchPtr(Assembler::NotEqual,
-                   Address(object(), JSObject::offsetOfShape()),
+                   Address(object, JSObject::offsetOfShape()),
                    ImmGCPtr(obj->lastProperty()), &failures);
 
     // Guard that the incoming value is in the type set for the property
     // if a type barrier is required.
-    if (needsTypeBarrier()) {
+    if (needsTypeBarrier) {
         // We can't do anything that would change the HeapTypeSet, so
         // just guard that it's already there.
 
         // Obtain and guard on the TypeObject of the object.
-        types::TypeObject *type = obj->getType(cx);
+        types::TypeObject *type = obj->type();
         masm.branchPtr(Assembler::NotEqual,
-                       Address(object(), JSObject::offsetOfType()),
+                       Address(object, JSObject::offsetOfType()),
                        ImmGCPtr(type), &failures);
 
         if (checkTypeset) {
-            TypedOrValueRegister valReg = value().reg();
-            types::HeapTypeSet *propTypes = type->maybeGetProperty(NameToId(name()));
+            TypedOrValueRegister valReg = value.reg();
+            types::HeapTypeSet *propTypes = type->maybeGetProperty(shape->propid());
             JS_ASSERT(propTypes);
             JS_ASSERT(!propTypes->unknown());
 
-            Register scratchReg = object();
+            Register scratchReg = object;
             masm.push(scratchReg);
 
             masm.guardTypeSet(valReg, propTypes, scratchReg, &barrierFailure);
-            masm.pop(object());
+            masm.pop(object);
         }
     }
 
     if (obj->isFixedSlot(shape->slot())) {
-        Address addr(object(), JSObject::getFixedSlotOffset(shape->slot()));
+        Address addr(object, JSObject::getFixedSlotOffset(shape->slot()));
 
         if (cx->zone()->needsBarrier())
             masm.callPreBarrier(addr, MIRType_Value);
 
-        masm.storeConstantOrRegister(value(), addr);
+        masm.storeConstantOrRegister(value, addr);
     } else {
-        Register slotsReg = object();
-        masm.loadPtr(Address(object(), JSObject::offsetOfSlots()), slotsReg);
+        Register slotsReg = object;
+        masm.loadPtr(Address(object, JSObject::offsetOfSlots()), slotsReg);
 
         Address addr(slotsReg, obj->dynamicSlotIndex(shape->slot()) * sizeof(Value));
 
         if (cx->zone()->needsBarrier())
             masm.callPreBarrier(addr, MIRType_Value);
 
-        masm.storeConstantOrRegister(value(), addr);
+        masm.storeConstantOrRegister(value, addr);
     }
 
     attacher.jumpRejoin(masm);
 
     if (barrierFailure.used()) {
         masm.bind(&barrierFailure);
-        masm.pop(object());
+        masm.pop(object);
     }
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
-
+}
+
+bool
+SetPropertyIC::attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj,
+                             HandleShape shape, bool checkTypeset)
+{
+    MacroAssembler masm(cx);
+    RepatchStubAppender attacher(*this);
+    GenerateSetSlot(cx, masm, attacher, obj, shape, object(), value(), needsTypeBarrier(),
+                    checkTypeset);
     return linkAndAttachStub(cx, masm, attacher, ion, "setting");
 }
 
 static bool
 IsCacheableSetPropCallNative(HandleObject obj, HandleObject holder, HandleShape shape)
 {
-    if (!obj->isNative())
-        return false;
+    JS_ASSERT(obj->isNative());
 
     if (!shape || !IsCacheableProtoChain(obj, holder))
         return false;
 
     return shape->hasSetterValue() && shape->setterObject() &&
            shape->setterObject()->is<JSFunction>() &&
            shape->setterObject()->as<JSFunction>().isNative();
 }
 
 static bool
-IsCacheableSetPropCallPropertyOp(HandleObject obj, HandleObject holder,
-                                 HandleShape shape)
+IsCacheableSetPropCallPropertyOp(HandleObject obj, HandleObject holder, HandleShape shape)
 {
-    if (!obj->isNative())
-        return false;
+    JS_ASSERT(obj->isNative());
 
     if (!shape)
         return false;
 
     if (!IsCacheableProtoChain(obj, holder))
         return false;
 
     if (shape->hasSlot())
@@ -2390,17 +2396,17 @@ GenerateCallSetter(JSContext *cx, IonScr
     JS_ASSERT(masm.framePushed() == initialStack);
 
     // restoreLive()
     masm.PopRegsInMask(liveRegs);
 
     return true;
 }
 
-bool
+static bool
 IsCacheableDOMProxyUnshadowedSetterCall(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                         MutableHandleObject holder, MutableHandleShape shape,
                                         bool *isSetter)
 {
     JS_ASSERT(IsCacheableDOMProxy(obj));
 
     *isSetter = false;
 
@@ -2477,17 +2483,17 @@ SetPropertyIC::attachDOMProxyUnshadowed(
     // Failure.
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "DOM proxy unshadowed set");
 }
 
 bool
-SetPropertyIC::attachSetterCall(JSContext *cx, IonScript *ion,
+SetPropertyIC::attachCallSetter(JSContext *cx, IonScript *ion,
                                 HandleObject obj, HandleObject holder, HandleShape shape,
                                 void *returnAddr)
 {
     JS_ASSERT(obj->isNative());
 
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
 
@@ -2512,120 +2518,125 @@ SetPropertyIC::attachSetterCall(JSContex
 
     // Jump to next stub.
     masm.bind(&failure);
     attacher.jumpNextStub(masm);
 
     return linkAndAttachStub(cx, masm, attacher, ion, "setter call");
 }
 
-bool
-SetPropertyIC::attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj,
-                                  HandleShape oldShape, HandleShape newShape,
-                                  HandleShape propShape)
+static void
+GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
+                JSObject *obj, Shape *oldShape, Register object, ConstantOrRegister value)
 {
     JS_ASSERT(obj->isNative());
 
-    MacroAssembler masm(cx);
-    RepatchStubAppender attacher(*this);
-
     Label failures;
 
-    /* Guard the type of the object */
-    masm.branchPtr(Assembler::NotEqual, Address(object(), JSObject::offsetOfType()),
+    // Guard the type of the object
+    masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfType()),
                    ImmGCPtr(obj->type()), &failures);
 
-    /* Guard shapes along prototype chain. */
-    masm.branchTestObjShape(Assembler::NotEqual, object(), oldShape, &failures);
+    // Guard shapes along prototype chain.
+    masm.branchTestObjShape(Assembler::NotEqual, object, oldShape, &failures);
 
     Label protoFailures;
-    masm.push(object());    // save object reg because we clobber it
+    masm.push(object);    // save object reg because we clobber it
 
     JSObject *proto = obj->getProto();
-    Register protoReg = object();
+    Register protoReg = object;
     while (proto) {
         Shape *protoShape = proto->lastProperty();
 
         // load next prototype
         masm.loadPtr(Address(protoReg, JSObject::offsetOfType()), protoReg);
         masm.loadPtr(Address(protoReg, offsetof(types::TypeObject, proto)), protoReg);
 
         // Ensure that its shape matches.
         masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, &protoFailures);
 
         proto = proto->getProto();
     }
 
-    masm.pop(object());     // restore object reg
-
-    /* Changing object shape.  Write the object's new shape. */
-    Address shapeAddr(object(), JSObject::offsetOfShape());
+    masm.pop(object);     // restore object reg
+
+    // Changing object shape.  Write the object's new shape.
+    Shape *newShape = obj->lastProperty();
+    Address shapeAddr(object, JSObject::offsetOfShape());
     if (cx->zone()->needsBarrier())
         masm.callPreBarrier(shapeAddr, MIRType_Shape);
     masm.storePtr(ImmGCPtr(newShape), shapeAddr);
 
-    /* Set the value on the object. */
-    if (obj->isFixedSlot(propShape->slot())) {
-        Address addr(object(), JSObject::getFixedSlotOffset(propShape->slot()));
-        masm.storeConstantOrRegister(value(), addr);
+    // Set the value on the object. Since this is an add, obj->lastProperty()
+    // must be the shape of the property we are adding.
+    if (obj->isFixedSlot(newShape->slot())) {
+        Address addr(object, JSObject::getFixedSlotOffset(newShape->slot()));
+        masm.storeConstantOrRegister(value, addr);
     } else {
-        Register slotsReg = object();
-
-        masm.loadPtr(Address(object(), JSObject::offsetOfSlots()), slotsReg);
-
-        Address addr(slotsReg, obj->dynamicSlotIndex(propShape->slot()) * sizeof(Value));
-        masm.storeConstantOrRegister(value(), addr);
+        Register slotsReg = object;
+
+        masm.loadPtr(Address(object, JSObject::offsetOfSlots()), slotsReg);
+
+        Address addr(slotsReg, obj->dynamicSlotIndex(newShape->slot()) * sizeof(Value));
+        masm.storeConstantOrRegister(value, addr);
     }
 
-    /* Success. */
+    // Success.
     attacher.jumpRejoin(masm);
 
-    /* Failure. */
+    // Failure.
     masm.bind(&protoFailures);
-    masm.pop(object());
+    masm.pop(object);
     masm.bind(&failures);
 
     attacher.jumpNextStub(masm);
-
+}
+
+bool
+SetPropertyIC::attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape)
+{
+    MacroAssembler masm(cx);
+    RepatchStubAppender attacher(*this);
+    GenerateAddSlot(cx, masm, attacher, obj, oldShape, object(), value());
     return linkAndAttachStub(cx, masm, attacher, ion, "adding");
 }
 
 static bool
-IsPropertySetInlineable(JSContext *cx, const SetPropertyIC &cache, HandleObject obj,
-                        HandleId id, MutableHandleShape pshape, bool *checkTypeset)
+IsPropertySetInlineable(HandleObject obj, HandleId id, MutableHandleShape pshape,
+                        ConstantOrRegister val, bool needsTypeBarrier, bool *checkTypeset)
 {
-    if (!obj->isNative())
-        return false;
-
-    pshape.set(obj->nativeLookup(cx, id));
+    JS_ASSERT(obj->isNative());
+
+    // Do a pure non-proto chain climbing lookup. See note in
+    // CanAttachNativeGetProp.
+    pshape.set(obj->nativeLookupPure(id));
 
     if (!pshape)
         return false;
 
     if (!pshape->hasSlot())
         return false;
 
     if (!pshape->hasDefaultSetter())
         return false;
 
     if (!pshape->writable())
         return false;
 
     bool shouldCheck = false;
-    types::TypeObject *type = obj->getType(cx);
-    if (cache.needsTypeBarrier() && !type->unknownProperties()) {
+    types::TypeObject *type = obj->type();
+    if (needsTypeBarrier && !type->unknownProperties()) {
         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())))
+                if (!propTypes->hasType(types::GetValueType(val.value())))
                     return false;
                 shouldCheck = false;
             } else {
                 TypedOrValueRegister reg = val.reg();
                 // We can do the same trick as above for primitive types of specialized registers.
                 // TIs handling of objects is complicated enough to warrant a runtime
                 // check, as we can't statically handle the case where the typeset
                 // contains the specific object, but doesn't have ANYOBJECT set.
@@ -2640,89 +2651,121 @@ IsPropertySetInlineable(JSContext *cx, c
     }
 
     *checkTypeset = shouldCheck;
 
     return true;
 }
 
 static bool
-IsPropertyAddInlineable(JSContext *cx, HandleObject obj, HandleId id, uint32_t oldSlots,
-                        MutableHandleShape pShape)
+IsPropertyAddInlineable(HandleObject obj, HandleId id, uint32_t oldSlots, HandleShape oldShape)
 {
-    if (!obj->isNative())
+    JS_ASSERT(obj->isNative());
+
+    // If the shape of the object did not change, then this was not an add.
+    if (obj->lastProperty() == oldShape)
         return false;
 
-    // This is not a Add, the property exists.
-    if (pShape.get())
-        return false;
-
-    RootedShape shape(cx, obj->nativeLookup(cx, id));
+    Shape *shape = obj->nativeLookupPure(id);
     if (!shape || shape->inDictionary() || !shape->hasSlot() || !shape->hasDefaultSetter())
         return false;
 
+    // If we have a shape at this point and the object's shape changed, then
+    // the shape must be the one we just added.
+    JS_ASSERT(shape == obj->lastProperty());
+
     // If object has a non-default resolve hook, don't inline
     if (obj->getClass()->resolve != JS_ResolveStub)
         return false;
 
     // Likewise for a non-default addProperty hook, since we'll need
     // to invoke it.
     if (obj->getClass()->addProperty != JS_PropertyStub)
         return false;
 
     if (!obj->nonProxyIsExtensible() || !shape->writable())
         return false;
 
-    // walk up the object prototype chain and ensure that all prototypes
+    // Walk up the object prototype chain and ensure that all prototypes
     // are native, and that all prototypes have no getter or setter
     // defined on the property
     for (JSObject *proto = obj->getProto(); proto; proto = proto->getProto()) {
-        // if prototype is non-native, don't optimize
+        // If prototype is non-native, don't optimize
         if (!proto->isNative())
             return false;
 
-        // if prototype defines this property in a non-plain way, don't optimize
-        Shape *protoShape = proto->nativeLookup(cx, id);
+        // If prototype defines this property in a non-plain way, don't optimize
+        Shape *protoShape = proto->nativeLookupPure(id);
         if (protoShape && !protoShape->hasDefaultSetter())
             return false;
 
-        // Otherise, if there's no such property, watch out for a resolve hook that would need
-        // to be invoked and thus prevent inlining of property addition.
+        // Otherwise, if there's no such property, watch out for a resolve
+        // hook that would need to be invoked and thus prevent inlining of
+        // property addition.
         if (proto->getClass()->resolve != JS_ResolveStub)
              return false;
     }
 
     // Only add a IC entry if the dynamic slots didn't change when the shapes
     // changed.  Need to ensure that a shape change for a subsequent object
     // won't involve reallocating the slot array.
     if (obj->numDynamicSlots() != oldSlots)
         return false;
 
-    pShape.set(shape);
     return true;
 }
 
+static SetPropertyIC::NativeSetPropCacheability
+CanAttachNativeSetProp(HandleObject obj, HandleId id, ConstantOrRegister val,
+                       bool needsTypeBarrier, MutableHandleObject holder,
+                       MutableHandleShape shape, bool *checkTypeset)
+{
+    if (!obj->isNative())
+        return SetPropertyIC::CanAttachNone;
+
+    // See if the property exists on the object.
+    if (IsPropertySetInlineable(obj, id, shape, val, needsTypeBarrier, checkTypeset))
+        return SetPropertyIC::CanAttachSetSlot;
+
+    // If we couldn't find the property on the object itself, do a full, but
+    // still pure lookup for setters.
+    if (!LookupPropertyPure(obj, id, holder.address(), shape.address()))
+        return SetPropertyIC::CanAttachNone;
+
+    // If the object doesn't have the property, we don't know if we can attach
+    // a stub to add the property until we do the VM call to add.
+    if (!shape)
+        return SetPropertyIC::MaybeCanAttachAddSlot;
+
+    if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
+        IsCacheableSetPropCallNative(obj, holder, shape))
+    {
+        return SetPropertyIC::CanAttachCallSetter;
+    }
+
+    return SetPropertyIC::CanAttachNone;
+}
+
 bool
 SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                       HandleValue value)
 {
     AutoFlushCache afc ("SetPropertyCache", cx->runtime()->ionRuntime());
 
     void *returnAddr;
     RootedScript script(cx, GetTopIonJSScript(cx, &returnAddr));
     IonScript *ion = script->ionScript();
     SetPropertyIC &cache = ion->getCache(cacheIndex).toSetProperty();
     RootedPropertyName name(cx, cache.name());
     RootedId id(cx, AtomToId(name));
-    RootedShape shape(cx);
-    RootedObject holder(cx);
 
     // Stop generating new stubs once we hit the stub count limit, see
     // GetPropertyCache.
     bool inlinable = cache.canAttachStub() && !obj->watched();
+    NativeSetPropCacheability canCache = CanAttachNone;
     bool addedSetterStub = false;
     if (inlinable) {
         if (!addedSetterStub && obj->is<ProxyObject>()) {
             if (IsCacheableDOMProxy(obj)) {
                 DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx, obj, id);
                 if (shadows == ShadowCheckFailed)
                     return false;
                 if (shadows == Shadows) {
@@ -2740,64 +2783,162 @@ SetPropertyIC::update(JSContext *cx, siz
             }
 
             if (!addedSetterStub && !cache.hasGenericProxyStub()) {
                 if (!cache.attachGenericProxy(cx, ion, returnAddr))
                     return false;
                 addedSetterStub = true;
             }
         }
+
+        // Make sure the object de-lazifies its type. We do this here so that
+        // the parallel IC can share code that assumes that native objects all
+        // have a type object.
+        if (obj->isNative() && !obj->getType(cx))
+            return false;
+
         RootedShape shape(cx);
+        RootedObject holder(cx);
         bool checkTypeset;
-        if (!addedSetterStub && IsPropertySetInlineable(cx, cache, obj, id, &shape, &checkTypeset)) {
-            if (!cache.attachNativeExisting(cx, ion, obj, shape, checkTypeset))
+        canCache = CanAttachNativeSetProp(obj, id, cache.value(), cache.needsTypeBarrier(),
+                                          &holder, &shape, &checkTypeset);
+
+        if (!addedSetterStub && canCache == CanAttachSetSlot) {
+            if (!cache.attachSetSlot(cx, ion, obj, shape, checkTypeset))
                 return false;
             addedSetterStub = true;
-        } else if (!addedSetterStub) {
-            RootedObject holder(cx);
-            if (!JSObject::lookupProperty(cx, obj, name, &holder, &shape))
+        }
+
+        if (!addedSetterStub && canCache == CanAttachCallSetter) {
+            if (!cache.attachCallSetter(cx, ion, obj, holder, shape, returnAddr))
                 return false;
-
-            if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
-                IsCacheableSetPropCallNative(obj, holder, shape))
-            {
-                if (!cache.attachSetterCall(cx, ion, obj, holder, shape, returnAddr))
-                    return false;
-                addedSetterStub = true;
-            }
+            addedSetterStub = true;
         }
     }
 
     uint32_t oldSlots = obj->numDynamicSlots();
     RootedShape oldShape(cx, obj->lastProperty());
 
     // Set/Add the property on the object, the inlined cache are setup for the next execution.
     if (!SetProperty(cx, obj, name, value, cache.strict(), cache.pc()))
         return false;
 
     // The property did not exist before, now we can try to inline the property add.
-    if (inlinable && !addedSetterStub && !cache.needsTypeBarrier() &&
-        obj->lastProperty() != oldShape &&
-        IsPropertyAddInlineable(cx, obj, id, oldSlots, &shape))
+    if (!addedSetterStub && canCache == MaybeCanAttachAddSlot &&
+        !cache.needsTypeBarrier() &&
+        IsPropertyAddInlineable(obj, id, oldSlots, oldShape))
     {
-        RootedShape newShape(cx, obj->lastProperty());
-        if (!cache.attachNativeAdding(cx, ion, obj, oldShape, newShape, shape))
+        if (!cache.attachAddSlot(cx, ion, obj, oldShape))
             return false;
     }
 
     return true;
 }
 
 void
 SetPropertyIC::reset()
 {
     RepatchIonCache::reset();
     hasGenericProxyStub_ = false;
 }
 
+bool
+SetPropertyParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                         HandleValue value)
+{
+    JS_ASSERT(slice->isThreadLocal(obj));
+
+    AutoFlushCache afc("SetPropertyParCache", slice->runtime()->ionRuntime());
+
+    IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
+    SetPropertyParIC &cache = ion->getCache(cacheIndex).toSetPropertyPar();
+
+    RootedValue v(slice, value);
+    RootedId id(slice, AtomToId(cache.name()));
+
+    // Avoid unnecessary locking if cannot attach stubs.
+    if (!cache.canAttachStub()) {
+        return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0,
+                                                             &v, cache.strict());
+    }
+
+    SetPropertyIC::NativeSetPropCacheability canCache = SetPropertyIC::CanAttachNone;
+    bool attachedStub = false;
+
+    {
+        LockedJSContext cx(slice);
+
+        if (cache.canAttachStub()) {
+            bool alreadyStubbed;
+            if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+            if (alreadyStubbed) {
+                return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0,
+                                                                     &v, cache.strict());
+            }
+
+            // If the object has a lazy type, we need to de-lazify it, but
+            // this is not safe in parallel.
+            if (obj->hasLazyType())
+                return false;
+
+            {
+                RootedShape shape(slice);
+                RootedObject holder(slice);
+                bool checkTypeset;
+                canCache = CanAttachNativeSetProp(obj, id, cache.value(), cache.needsTypeBarrier(),
+                                                  &holder, &shape, &checkTypeset);
+
+                if (canCache == SetPropertyIC::CanAttachSetSlot) {
+                    if (!cache.attachSetSlot(cx, ion, obj, shape, checkTypeset))
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+                    attachedStub = true;
+                }
+            }
+        }
+    }
+
+    uint32_t oldSlots = obj->numDynamicSlots();
+    RootedShape oldShape(slice, obj->lastProperty());
+
+    if (!baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, cache.strict()))
+        return false;
+
+    if (!attachedStub && canCache == SetPropertyIC::MaybeCanAttachAddSlot &&
+        !cache.needsTypeBarrier() &&
+        IsPropertyAddInlineable(obj, id, oldSlots, oldShape))
+    {
+        LockedJSContext cx(slice);
+        if (cache.canAttachStub() && !cache.attachAddSlot(cx, ion, obj, oldShape))
+            return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+    }
+
+    return true;
+}
+
+bool
+SetPropertyParIC::attachSetSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *shape,
+                                  bool checkTypeset)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    GenerateSetSlot(cx, masm, attacher, obj, shape, object(), value(), needsTypeBarrier(),
+                    checkTypeset);
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel setting");
+}
+
+bool
+SetPropertyParIC::attachAddSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *oldShape)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    GenerateAddSlot(cx, masm, attacher, obj, oldShape, object(), value());
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel adding");
+}
+
 const size_t GetElementIC::MAX_FAILED_UPDATES = 16;
 
 /* static */ bool
 GetElementIC::canAttachGetProp(JSObject *obj, const Value &idval, jsid id)
 {
     uint32_t dummy;
     return (obj->isNative() &&
             idval.isString() &&
@@ -3235,25 +3376,25 @@ GetElementIC::reset()
 {
     RepatchIonCache::reset();
     hasDenseStub_ = false;
     hasStrictArgumentsStub_ = false;
     hasNormalArgumentsStub_ = false;
 }
 
 static bool
-IsElementSetInlineable(HandleObject obj, HandleValue index)
+IsDenseElementSetInlineable(JSObject *obj, const Value &idval)
 {
     if (!obj->is<ArrayObject>())
         return false;
 
     if (obj->watched())
         return false;
 
-    if (!index.isInt32())
+    if (!idval.isInt32())
         return false;
 
     // The object may have a setter definition,
     // either directly, or via a prototype, or via the target object for a prototype
     // which is a proxy, that handles a particular integer write.
     // Scan the prototype and shape chain to make sure that this is not the case.
     JSObject *curObj = obj;
     while (curObj) {
@@ -3266,45 +3407,51 @@ IsElementSetInlineable(HandleObject obj,
             return false;
 
         curObj = curObj->getProto();
     }
 
     return true;
 }
 
-bool
-SetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
+static bool
+IsTypedArrayElementSetInlineable(JSObject *obj, const Value &idval, const Value &value)
+{
+    // Don't bother attaching stubs for assigning strings and objects.
+    return (obj->is<TypedArrayObject>() && idval.isInt32() &&
+            !value.isString() && !value.isObject());
+}
+
+static bool
+GenerateSetDenseElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
+                        JSObject *obj, const Value &idval, Register object, ValueOperand indexVal,
+                        ConstantOrRegister value, Register tempToUnboxIndex, Register temp)
 {
     JS_ASSERT(obj->isNative());
     JS_ASSERT(idval.isInt32());
 
     Label failures;
     Label outOfBounds; // index >= capacity || index > initialized length
 
-    MacroAssembler masm(cx);
-    RepatchStubAppender attacher(*this);
-
     // Guard object is a dense array.
-    RootedShape shape(cx, obj->lastProperty());
+    Shape *shape = obj->lastProperty();
     if (!shape)
         return false;
-    masm.branchTestObjShape(Assembler::NotEqual, object(), shape, &failures);
+    masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
 
     // Ensure the index is an int32 value.
-    ValueOperand indexVal = index();
     masm.branchTestInt32(Assembler::NotEqual, indexVal, &failures);
 
     // Unbox the index.
-    Register index = masm.extractInt32(indexVal, tempToUnboxIndex());
+    Register index = masm.extractInt32(indexVal, tempToUnboxIndex);
 
     {
         // Load obj->elements.
-        Register elements = temp();
-        masm.loadPtr(Address(object(), JSObject::offsetOfElements()), elements);
+        Register elements = temp;
+        masm.loadPtr(Address(object, JSObject::offsetOfElements()), elements);
 
         // Compute the location of the element.
         BaseIndex target(elements, index, TimesEight);
 
         // Guard that we can increase the initialized length.
         Address capacity(elements, ObjectElements::offsetOfCapacity());
         masm.branch32(Assembler::BelowOrEqual, capacity, index, &outOfBounds);
 
@@ -3337,30 +3484,45 @@ SetElementIC::attachDenseElement(JSConte
             // Mark old element.
             masm.bind(&markElem);
             if (cx->zone()->needsBarrier())
                 masm.callPreBarrier(target, MIRType_Value);
         }
 
         // Call post barrier if necessary, and recalculate elements pointer if it got cobbered.
         Register postBarrierScratch = elements;
-        if (masm.maybeCallPostBarrier(object(), value(), postBarrierScratch))
-            masm.loadPtr(Address(object(), JSObject::offsetOfElements()), elements);
+        if (masm.maybeCallPostBarrier(object, value, postBarrierScratch))
+            masm.loadPtr(Address(object, JSObject::offsetOfElements()), elements);
 
         // Store the value.
         masm.bind(&storeElem);
-        masm.storeConstantOrRegister(value(), target);
+        masm.storeConstantOrRegister(value, target);
     }
     attacher.jumpRejoin(masm);
 
     // All failures flow to here.
     masm.bind(&outOfBounds);
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
 
+    return true;
+}
+
+bool
+SetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
+{
+    MacroAssembler masm(cx);
+    RepatchStubAppender attacher(*this);
+    if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
+                                 object(), index(), value(),
+                                 tempToUnboxIndex(), temp()))
+    {
+        return false;
+    }
+
     setHasDenseStub();
     return linkAndAttachStub(cx, masm, attacher, ion, "dense array");
 }
 
 static bool
 GenerateSetTypedArrayElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
                              TypedArrayObject *tarr, Register object,
                              ValueOperand indexVal, ConstantOrRegister value,
@@ -3438,24 +3600,16 @@ GenerateSetTypedArrayElement(JSContext *
         masm.pop(object);
     }
 
     masm.bind(&failures);
     attacher.jumpNextStub(masm);
     return true;
 }
 
-/* static */ bool
-SetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval, const Value &value)
-{
-    // Don't bother attaching stubs for assigning strings and objects.
-    return (obj->is<TypedArrayObject>() && idval.isInt32() &&
-            !value.isString() && !value.isObject());
-}
-
 bool
 SetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr)
 {
     MacroAssembler masm(cx);
     RepatchStubAppender attacher(*this);
     if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
                                       object(), index(), value(),
                                       tempToUnboxIndex(), temp(), tempFloat()))
@@ -3470,22 +3624,22 @@ bool
 SetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
                      HandleValue idval, HandleValue value)
 {
     IonScript *ion = GetTopIonJSScript(cx)->ionScript();
     SetElementIC &cache = ion->getCache(cacheIndex).toSetElement();
 
     bool attachedStub = false;
     if (cache.canAttachStub()) {
-        if (!cache.hasDenseStub() && IsElementSetInlineable(obj, idval)) {
+        if (!cache.hasDenseStub() && IsDenseElementSetInlineable(obj, idval)) {
             if (!cache.attachDenseElement(cx, ion, obj, idval))
                 return false;
             attachedStub = true;
         }
-        if (!attachedStub && canAttachTypedArrayElement(obj, idval, value)) {
+        if (!attachedStub && IsTypedArrayElementSetInlineable(obj, idval, value)) {
             TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
             if (!cache.attachTypedArrayElement(cx, ion, tarr))
                 return false;
         }
     }
 
     if (!SetObjectElement(cx, obj, idval, value, cache.strict()))
         return false;
@@ -3495,16 +3649,86 @@ SetElementIC::update(JSContext *cx, size
 void
 SetElementIC::reset()
 {
     RepatchIonCache::reset();
     hasDenseStub_ = false;
 }
 
 bool
+SetElementParIC::attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj,
+                                    const Value &idval)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
+                                 object(), index(), value(),
+                                 tempToUnboxIndex(), temp()))
+    {
+        return false;
+    }
+
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel dense array");
+}
+
+bool
+SetElementParIC::attachTypedArrayElement(LockedJSContext &cx, IonScript *ion,
+                                         TypedArrayObject *tarr)
+{
+    MacroAssembler masm(cx);
+    DispatchStubPrepender attacher(*this);
+    if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
+                                      object(), index(), value(),
+                                      tempToUnboxIndex(), temp(), tempFloat()))
+    {
+        return false;
+    }
+
+    return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
+}
+
+bool
+SetElementParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                        HandleValue idval, HandleValue value)
+{
+    IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
+    SetElementParIC &cache = ion->getCache(cacheIndex).toSetElementPar();
+
+    // Avoid unnecessary locking if cannot attach stubs.
+    if (!cache.canAttachStub())
+        return SetElementPar(slice, obj, idval, value, cache.strict());
+
+    {
+        LockedJSContext cx(slice);
+
+        if (cache.canAttachStub()) {
+            bool alreadyStubbed;
+            if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+            if (alreadyStubbed)
+                return SetElementPar(slice, obj, idval, value, cache.strict());
+
+            bool attachedStub = false;
+            if (IsDenseElementSetInlineable(obj, idval)) {
+                if (!cache.attachDenseElement(cx, ion, obj, idval))
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+                attachedStub = true;
+            }
+            if (!attachedStub && IsTypedArrayElementSetInlineable(obj, idval, value)) {
+                TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
+                if (!cache.attachTypedArrayElement(cx, ion, tarr))
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
+            }
+        }
+    }
+
+    return SetElementPar(slice, obj, idval, value, cache.strict());
+}
+
+bool
 GetElementParIC::attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj,
                                 const Value &idval, PropertyName *name, JSObject *holder,
                                 Shape *shape)
 {
     MacroAssembler masm(cx);
     DispatchStubPrepender attacher(*this);
 
     // Guard on the index value.
@@ -3535,85 +3759,84 @@ GetElementParIC::attachTypedArrayElement
                                          TypedArrayObject *tarr, const Value &idval)
 {
     MacroAssembler masm(cx);
     DispatchStubPrepender attacher(*this);
     GenerateGetTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output());
     return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
 }
 
-ParallelResult
+bool
 GetElementParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
                         HandleValue idval, MutableHandleValue vp)
 {
     AutoFlushCache afc("GetElementParCache", slice->runtime()->ionRuntime());
 
     IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
     GetElementParIC &cache = ion->getCache(cacheIndex).toGetElementPar();
 
     // Try to get the element early, as the pure path doesn't need a lock. If
     // we can't do it purely, bail out of parallel execution.
     if (!GetObjectElementOperationPure(slice, obj, idval, vp.address()))
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
 
     // Avoid unnecessary locking if cannot attach stubs.
     if (!cache.canAttachStub())
-        return TP_SUCCESS;
+        return true;
 
     {
         LockedJSContext cx(slice);
 
         if (cache.canAttachStub()) {
             bool alreadyStubbed;
             if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
-                return TP_FATAL;
+                return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
             if (alreadyStubbed)
-                return TP_SUCCESS;
+                return true;
 
             jsid id;
             if (!ValueToIdPure(idval, &id))
-                return TP_FATAL;
+                return false;
 
             bool attachedStub = false;
-
             if (cache.monitoredResult() &&
                 GetElementIC::canAttachGetProp(obj, idval, id))
             {
                 RootedShape shape(cx);
                 RootedObject holder(cx);
                 RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
 
                 GetPropertyIC::NativeGetPropCacheability canCache =
                     CanAttachNativeGetProp(cx, cache, obj, name, &holder, &shape);
 
                 if (canCache == GetPropertyIC::CanAttachReadSlot)
                 {
                     if (!cache.attachReadSlot(cx, ion, obj, idval, name, holder, shape))
-                        return TP_FATAL;
+                        return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                     attachedStub = true;
                 }
             }
             if (!attachedStub &&
                 GetElementIC::canAttachDenseElement(obj, idval))
             {
                 if (!cache.attachDenseElement(cx, ion, obj, idval))
-                    return TP_FATAL;
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                 attachedStub = true;
             }
             if (!attachedStub &&
                 GetElementIC::canAttachTypedArrayElement(obj, idval, cache.output()))
             {
                 if (!cache.attachTypedArrayElement(cx, ion, &obj->as<TypedArrayObject>(), idval))
-                    return TP_FATAL;
+                    return slice->setPendingAbortFatal(ParallelBailoutFailedIC);
                 attachedStub = true;
             }
         }
     }
 
-    return TP_SUCCESS;
+    return true;
 }
 
 bool
 BindNameIC::attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain)
 {
     JS_ASSERT(scopeChain->is<GlobalObject>());
 
     MacroAssembler masm(cx);
--- a/js/src/jit/IonCaches.h
+++ b/js/src/jit/IonCaches.h
@@ -24,17 +24,19 @@ namespace jit {
     _(GetProperty)                                              \
     _(SetProperty)                                              \
     _(GetElement)                                               \
     _(SetElement)                                               \
     _(BindName)                                                 \
     _(Name)                                                     \
     _(CallsiteClone)                                            \
     _(GetPropertyPar)                                           \
-    _(GetElementPar)
+    _(GetElementPar)                                            \
+    _(SetPropertyPar)                                           \
+    _(SetElementPar)
 
 // Forward declarations of Cache kinds.
 #define FORWARD_DECLARE(kind) class kind##IC;
 IONCACHE_KIND_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
 class IonCacheVisitor
 {
@@ -673,22 +675,28 @@ class SetPropertyIC : public RepatchIonC
     }
     bool needsTypeBarrier() const {
         return needsTypeBarrier_;
     }
     bool hasGenericProxyStub() const {
         return hasGenericProxyStub_;
     }
 
-    bool attachNativeExisting(JSContext *cx, IonScript *ion, HandleObject obj,
-                              HandleShape shape, bool checkTypeset);
-    bool attachSetterCall(JSContext *cx, IonScript *ion, HandleObject obj,
+    enum NativeSetPropCacheability {
+        CanAttachNone,
+        CanAttachSetSlot,
+        MaybeCanAttachAddSlot,
+        CanAttachCallSetter
+    };
+
+    bool attachSetSlot(JSContext *cx, IonScript *ion, HandleObject obj, HandleShape shape,
+                       bool checkTypeset);
+    bool attachCallSetter(JSContext *cx, IonScript *ion, HandleObject obj,
                           HandleObject holder, HandleShape shape, void *returnAddr);
-    bool attachNativeAdding(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldshape,
-                            HandleShape newshape, HandleShape propshape);
+    bool attachAddSlot(JSContext *cx, IonScript *ion, JSObject *obj, HandleShape oldShape);
     bool attachGenericProxy(JSContext *cx, IonScript *ion, void *returnAddr);
     bool attachDOMProxyShadowed(JSContext *cx, IonScript *ion, HandleObject obj,
                                 void *returnAddr);
     bool attachDOMProxyUnshadowed(JSContext *cx, IonScript *ion, HandleObject obj,
                                   void *returnAddr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue value);
@@ -767,17 +775,17 @@ class GetElementIC : public RepatchIonCa
     bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
     bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
     bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
                                  const Value &idval);
     bool attachArgumentsElement(JSContext *cx, IonScript *ion, JSObject *obj);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
-                MutableHandleValue vp);
+           MutableHandleValue vp);
 
     void incFailedUpdates() {
         failedUpdates_++;
     }
     void resetFailedUpdates() {
         failedUpdates_ = 0;
     }
     bool shouldDisable() const {
@@ -843,18 +851,16 @@ class SetElementIC : public RepatchIonCa
     bool hasDenseStub() const {
         return hasDenseStub_;
     }
     void setHasDenseStub() {
         JS_ASSERT(!hasDenseStub());
         hasDenseStub_ = true;
     }
 
-    static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval, const Value &value);
-
     bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
     bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr);
 
     static bool
     update(JSContext *cx, size_t cacheIndex, HandleObject obj, HandleValue idval,
            HandleValue value);
 };
 
@@ -1044,18 +1050,18 @@ class GetPropertyParIC : public Parallel
     bool allowGetters() const { return false; }
     bool allowArrayLength(Context, HandleObject) const { return true; }
 
     bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, JSObject *holder,
                         Shape *shape);
     bool attachArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
     bool attachTypedArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
 
-    static ParallelResult update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
-                                 MutableHandleValue vp);
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                       MutableHandleValue vp);
 };
 
 class GetElementParIC : public ParallelIonCache
 {
   protected:
     Register object_;
     ConstantOrRegister index_;
     TypedOrValueRegister output_;
@@ -1100,19 +1106,133 @@ class GetElementParIC : public ParallelI
     bool allowArrayLength(Context, HandleObject) const { return false; }
 
     bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval,
                         PropertyName *name, JSObject *holder, Shape *shape);
     bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
     bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr,
                                  const Value &idval);
 
-    static ParallelResult update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj, HandleValue idval,
-                                 MutableHandleValue vp);
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj, HandleValue idval,
+                       MutableHandleValue vp);
+
+};
+
+class SetPropertyParIC : public ParallelIonCache
+{
+  protected:
+    Register object_;
+    PropertyName *name_;
+    ConstantOrRegister value_;
+    bool strict_;
+    bool needsTypeBarrier_;
+
+  public:
+    SetPropertyParIC(Register object, PropertyName *name, ConstantOrRegister value,
+                     bool strict, bool needsTypeBarrier)
+      : object_(object),
+        name_(name),
+        value_(value),
+        strict_(strict),
+        needsTypeBarrier_(needsTypeBarrier)
+    {
+    }
+
+    CACHE_HEADER(SetPropertyPar)
+
+#ifdef JS_CPU_X86
+    // x86 lacks a general purpose scratch register for dispatch caches and
+    // must be given one manually.
+    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
+#endif
+
+    Register object() const {
+        return object_;
+    }
+    PropertyName *name() const {
+        return name_;
+    }
+    ConstantOrRegister value() const {
+        return value_;
+    }
+    bool strict() const {
+        return strict_;
+    }
+    bool needsTypeBarrier() const {
+        return needsTypeBarrier_;
+    }
+
+    bool attachSetSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *shape,
+                       bool checkTypeset);
+    bool attachAddSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, Shape *oldShape);
+
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                       HandleValue value);
+};
 
+class SetElementParIC : public ParallelIonCache
+{
+  protected:
+    Register object_;
+    Register tempToUnboxIndex_;
+    Register temp_;
+    FloatRegister tempFloat_;
+    ValueOperand index_;
+    ConstantOrRegister value_;
+    bool strict_;
+
+  public:
+    SetElementParIC(Register object, Register tempToUnboxIndex, Register temp,
+                    FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
+                    bool strict)
+      : object_(object),
+        tempToUnboxIndex_(tempToUnboxIndex),
+        temp_(temp),
+        tempFloat_(tempFloat),
+        index_(index),
+        value_(value),
+        strict_(strict)
+    {
+    }
+
+    CACHE_HEADER(SetElementPar)
+
+#ifdef JS_CPU_X86
+    // x86 lacks a general purpose scratch register for dispatch caches and
+    // must be given one manually.
+    void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
+#endif
+
+    Register object() const {
+        return object_;
+    }
+    Register tempToUnboxIndex() const {
+        return tempToUnboxIndex_;
+    }
+    Register temp() const {
+        return temp_;
+    }
+    FloatRegister tempFloat() const {
+        return tempFloat_;
+    }
+    ValueOperand index() const {
+        return index_;
+    }
+    ConstantOrRegister value() const {
+        return value_;
+    }
+    bool strict() const {
+        return strict_;
+    }
+
+    bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
+    bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr);
+
+    static bool update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
+                       HandleValue idval, HandleValue value);
 };
 
 #undef CACHE_HEADER
 
 // Implement cache casts now that the compiler can see the inheritance.
 #define CACHE_CASTS(ickind)                                             \
     ickind##IC &IonCache::to##ickind()                                  \
     {                                                                   \
--- a/js/src/jit/IonFrameIterator.h
+++ b/js/src/jit/IonFrameIterator.h
@@ -80,31 +80,34 @@ class IonFrameIterator
     uint8_t *current_;
     FrameType type_;
     uint8_t *returnAddressToFp_;
     size_t frameSize_;
 
   private:
     mutable const SafepointIndex *cachedSafepointIndex_;
     const JitActivation *activation_;
+    ExecutionMode mode_;
 
     void dumpBaseline() const;
 
   public:
-    IonFrameIterator(uint8_t *top)
+    explicit IonFrameIterator(uint8_t *top, ExecutionMode mode)
       : current_(top),
         type_(IonFrame_Exit),
         returnAddressToFp_(nullptr),
         frameSize_(0),
         cachedSafepointIndex_(nullptr),
-        activation_(nullptr)
+        activation_(nullptr),
+        mode_(mode)
     { }
 
-    IonFrameIterator(const ActivationIterator &activations);
-    IonFrameIterator(IonJSFrameLayout *fp);
+    explicit IonFrameIterator(JSContext *cx);
+    explicit IonFrameIterator(const ActivationIterator &activations);
+    explicit IonFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode);
 
     // Current frame information.
     FrameType type() const {
         return type_;
     }
     uint8_t *fp() const {
         return current_;
     }
@@ -146,17 +149,16 @@ class IonFrameIterator
     bool isOOLNative() const;
     bool isOOLPropertyOp() const;
     bool isOOLProxy() const;
     bool isDOMExit() const;
     bool isEntry() const {
         return type_ == IonFrame_Entry;
     }
     bool isFunctionFrame() const;
-    bool isParallelFunctionFrame() const;
 
     bool isConstructing() const;
 
     void *calleeToken() const;
     JSFunction *callee() const;
     JSFunction *maybeCallee() const;
     unsigned numActualArgs() const;
     JSScript *script() const;
--- a/js/src/jit/IonFrames-inl.h
+++ b/js/src/jit/IonFrames-inl.h
@@ -8,16 +8,17 @@
 #define jit_IonFrames_inl_h
 
 #ifdef JS_ION
 
 #include "jit/IonFrames.h"
 
 #include "jit/IonFrameIterator.h"
 #include "jit/LIR.h"
+#include "vm/ForkJoin.h"
 
 #include "jit/IonFrameIterator-inl.h"
 
 namespace js {
 namespace jit {
 
 inline void
 SafepointIndex::resolve()
@@ -64,23 +65,35 @@ IonFrameIterator::exitFrame() const
     JS_ASSERT(type() == IonFrame_Exit);
     JS_ASSERT(!isFakeExitFrame());
     return (IonExitFrameLayout *) fp();
 }
 
 inline BaselineFrame *
 GetTopBaselineFrame(JSContext *cx)
 {
-    IonFrameIterator iter(cx->mainThread().ionTop);
+    IonFrameIterator iter(cx);
     JS_ASSERT(iter.type() == IonFrame_Exit);
     ++iter;
     if (iter.isBaselineStub())
         ++iter;
     JS_ASSERT(iter.isBaselineJS());
     return iter.baselineFrame();
 }
 
+inline JSScript *
+GetTopIonJSScript(JSContext *cx, void **returnAddrOut = nullptr)
+{
+    return GetTopIonJSScript(cx->mainThread().ionTop, returnAddrOut, SequentialExecution);
+}
+
+inline JSScript *
+GetTopIonJSScript(ForkJoinSlice *slice, void **returnAddrOut = nullptr)
+{
+    return GetTopIonJSScript(slice->perThreadData->ionTop, returnAddrOut, ParallelExecution);
+}
+
 } // namespace jit
 } // namespace js
 
 #endif // JS_ION
 
 #endif /* jit_IonFrames_inl_h */
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -27,31 +27,44 @@
 #include "vm/Interpreter.h"
 
 #include "jit/IonFrameIterator-inl.h"
 #include "vm/Probes-inl.h"
 
 namespace js {
 namespace jit {
 
+IonFrameIterator::IonFrameIterator(JSContext *cx)
+  : current_(cx->mainThread().ionTop),
+    type_(IonFrame_Exit),
+    returnAddressToFp_(nullptr),
+    frameSize_(0),
+    cachedSafepointIndex_(nullptr),
+    activation_(nullptr),
+    mode_(SequentialExecution)
+{
+}
+
 IonFrameIterator::IonFrameIterator(const ActivationIterator &activations)
     : current_(activations.jitTop()),
       type_(IonFrame_Exit),
       returnAddressToFp_(nullptr),
       frameSize_(0),
       cachedSafepointIndex_(nullptr),
-      activation_(activations.activation()->asJit())
+      activation_(activations.activation()->asJit()),
+      mode_(SequentialExecution)
 {
 }
 
-IonFrameIterator::IonFrameIterator(IonJSFrameLayout *fp)
+IonFrameIterator::IonFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
   : current_((uint8_t *)fp),
     type_(IonFrame_OptimizedJS),
     returnAddressToFp_(fp->returnAddress()),
-    frameSize_(fp->prevFrameLocalSize())
+    frameSize_(fp->prevFrameLocalSize()),
+    mode_(mode)
 {
 }
 
 bool
 IonFrameIterator::checkInvalidation() const
 {
     IonScript *dummy;
     return checkInvalidation(&dummy);
@@ -60,19 +73,19 @@ IonFrameIterator::checkInvalidation() co
 bool
 IonFrameIterator::checkInvalidation(IonScript **ionScriptOut) const
 {
     uint8_t *returnAddr = returnAddressToFp();
     JSScript *script = this->script();
     // N.B. the current IonScript is not the same as the frame's
     // IonScript if the frame has since been invalidated.
     bool invalidated;
-    if (isParallelFunctionFrame()) {
-        invalidated = !script->hasParallelIonScript() ||
-            !script->parallelIonScript()->containsReturnAddress(returnAddr);
+    if (mode_ == ParallelExecution) {
+        // Parallel execution does not have invalidating bailouts.
+        invalidated = false;
     } else {
         invalidated = !script->hasIonScript() ||
             !script->ionScript()->containsReturnAddress(returnAddr);
     }
     if (!invalidated)
         return false;
 
     int32_t invalidationDataOffset = ((int32_t *) returnAddr)[-1];
@@ -88,26 +101,24 @@ IonFrameIterator::calleeToken() const
 {
     return ((IonJSFrameLayout *) current_)->calleeToken();
 }
 
 JSFunction *
 IonFrameIterator::callee() const
 {
     JS_ASSERT(isScripted());
-    JS_ASSERT(isFunctionFrame() || isParallelFunctionFrame());
-    if (isFunctionFrame())
-        return CalleeTokenToFunction(calleeToken());
-    return CalleeTokenToParallelFunction(calleeToken());
+    JS_ASSERT(isFunctionFrame());
+    return CalleeTokenToFunction(calleeToken());
 }
 
 JSFunction *
 IonFrameIterator::maybeCallee() const
 {
-    if (isScripted() && (isFunctionFrame() || isParallelFunctionFrame()))
+    if (isScripted() && (isFunctionFrame()))
         return callee();
     return nullptr;
 }
 
 bool
 IonFrameIterator::isNative() const
 {
     if (type_ != IonFrame_Exit || isFakeExitFrame())
@@ -148,22 +159,16 @@ IonFrameIterator::isDOMExit() const
 }
 
 bool
 IonFrameIterator::isFunctionFrame() const
 {
     return CalleeTokenIsFunction(calleeToken());
 }
 
-bool
-IonFrameIterator::isParallelFunctionFrame() const
-{
-    return GetCalleeTokenTag(calleeToken()) == CalleeToken_ParallelFunction;
-}
-
 JSScript *
 IonFrameIterator::script() const
 {
     JS_ASSERT(isScripted());
     if (isBaselineJS())
         return baselineFrame()->script();
     JSScript *script = ScriptFromCalleeToken(calleeToken());
     JS_ASSERT(script);
@@ -521,17 +526,17 @@ HandleException(ResumeFromException *rfe
 
     // Clear any Ion return override that's been set.
     // This may happen if a callVM function causes an invalidation (setting the
     // override), and then fails, bypassing the bailout handlers that would
     // otherwise clear the return override.
     if (cx->runtime()->hasIonReturnOverride())
         cx->runtime()->takeIonReturnOverride();
 
-    IonFrameIterator iter(cx->mainThread().ionTop);
+    IonFrameIterator iter(cx);
     while (!iter.isEntry()) {
         bool overrecursed = false;
         if (iter.isOptimizedJS()) {
             // Search each inlined frame for live iterator objects, and close
             // them.
             InlineFrameIterator frames(cx, &iter);
             for (;;) {
                 HandleExceptionIon(cx, frames, rfe, &overrecursed);
@@ -611,24 +616,24 @@ HandleException(ResumeFromException *rfe
 
     rfe->stackPointer = iter.fp();
 }
 
 void
 HandleParallelFailure(ResumeFromException *rfe)
 {
     ForkJoinSlice *slice = ForkJoinSlice::Current();
-    IonFrameIterator iter(slice->perThreadData->ionTop);
+    IonFrameIterator iter(slice->perThreadData->ionTop, ParallelExecution);
 
     parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
 
     while (!iter.isEntry()) {
         if (iter.isScripted()) {
-            slice->bailoutRecord->setCause(ParallelBailoutFailedIC,
-                                           iter.script(), iter.script(), nullptr);
+            slice->bailoutRecord->updateCause(ParallelBailoutUnsupportedVM,
+                                              iter.script(), iter.script(), nullptr);
             break;
         }
         ++iter;
     }
 
     while (!iter.isEntry()) {
         if (iter.isScripted())
             PropagateAbortPar(iter.script(), iter.script());
@@ -849,17 +854,17 @@ MarkBaselineStubFrame(JSTracer *trc, con
         JS_ASSERT(ICStub::CanMakeCalls(stub->kind()));
         stub->trace(trc);
     }
 }
 
 void
 JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
 {
-    IonFrameIterator frames(jitTop());
+    IonFrameIterator frames(jitTop(), SequentialExecution);
 
     if (frames.isFakeExitFrame()) {
         min = reinterpret_cast<uintptr_t *>(frames.fp());
     } else {
         IonExitFrameLayout *exitFrame = frames.exitFrame();
         IonExitFooterFrame *footer = exitFrame->footer();
         const VMFunction *f = footer->function();
         if (exitFrame->isWrapperExit() && f->outParam == Type_Handle) {
@@ -1089,17 +1094,17 @@ AutoTempAllocatorRooter::trace(JSTracer 
 void
 GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
 {
     IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
 
     JSRuntime *rt = cx->runtime();
 
     // Recover the return address.
-    IonFrameIterator it(rt->mainThread.ionTop);
+    IonFrameIterator it(rt->mainThread.ionTop, SequentialExecution);
 
     // If the previous frame is a rectifier frame (maybe unwound),
     // skip past it.
     if (it.prevType() == IonFrame_Rectifier || it.prevType() == IonFrame_Unwound_Rectifier) {
         ++it;
         JS_ASSERT(it.prevType() == IonFrame_BaselineStub ||
                   it.prevType() == IonFrame_BaselineJS ||
                   it.prevType() == IonFrame_OptimizedJS);
@@ -1313,19 +1318,17 @@ IonFrameIterator::ionScript() const
     JS_ASSERT(type() == IonFrame_OptimizedJS);
 
     IonScript *ionScript = nullptr;
     if (checkInvalidation(&ionScript))
         return ionScript;
     switch (GetCalleeTokenTag(calleeToken())) {
       case CalleeToken_Function:
       case CalleeToken_Script:
-        return script()->ionScript();
-      case CalleeToken_ParallelFunction:
-        return script()->parallelIonScript();
+        return mode_ == ParallelExecution ? script()->parallelIonScript() : script()->ionScript();
       default:
         MOZ_ASSUME_UNREACHABLE("unknown callee token type");
     }
 }
 
 const SafepointIndex *
 IonFrameIterator::safepoint() const
 {
--- a/js/src/jit/IonFrames.h
+++ b/js/src/jit/IonFrames.h
@@ -19,76 +19,62 @@
 namespace js {
 namespace jit {
 
 typedef void * CalleeToken;
 
 enum CalleeTokenTag
 {
     CalleeToken_Function = 0x0, // untagged
-    CalleeToken_Script = 0x1,
-    CalleeToken_ParallelFunction = 0x2
+    CalleeToken_Script = 0x1
 };
 
 static inline CalleeTokenTag
 GetCalleeTokenTag(CalleeToken token)
 {
     CalleeTokenTag tag = CalleeTokenTag(uintptr_t(token) & 0x3);
-    JS_ASSERT(tag <= CalleeToken_ParallelFunction);
+    JS_ASSERT(tag <= CalleeToken_Script);
     return tag;
 }
 static inline CalleeToken
 CalleeToToken(JSFunction *fun)
 {
     return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_Function));
 }
 static inline CalleeToken
-CalleeToParallelToken(JSFunction *fun)
-{
-    return CalleeToken(uintptr_t(fun) | uintptr_t(CalleeToken_ParallelFunction));
-}
-static inline CalleeToken
 CalleeToToken(JSScript *script)
 {
     return CalleeToken(uintptr_t(script) | uintptr_t(CalleeToken_Script));
 }
 static inline bool
 CalleeTokenIsFunction(CalleeToken token)
 {
     return GetCalleeTokenTag(token) == CalleeToken_Function;
 }
 static inline JSFunction *
 CalleeTokenToFunction(CalleeToken token)
 {
     JS_ASSERT(CalleeTokenIsFunction(token));
     return (JSFunction *)token;
 }
-static inline JSFunction *
-CalleeTokenToParallelFunction(CalleeToken token)
-{
-    JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_ParallelFunction);
-    return (JSFunction *)(uintptr_t(token) & ~uintptr_t(0x3));
-}
 static inline JSScript *
 CalleeTokenToScript(CalleeToken token)
 {
     JS_ASSERT(GetCalleeTokenTag(token) == CalleeToken_Script);
     return (JSScript *)(uintptr_t(token) & ~uintptr_t(0x3));
 }
 
 static inline JSScript *
 ScriptFromCalleeToken(CalleeToken token)
 {
     switch (GetCalleeTokenTag(token)) {
       case CalleeToken_Script:
         return CalleeTokenToScript(token);
       case CalleeToken_Function:
         return CalleeTokenToFunction(token)->nonLazyScript();
-      case CalleeToken_ParallelFunction:
-        return CalleeTokenToParallelFunction(token)->nonLazyScript();
     }
     MOZ_ASSUME_UNREACHABLE("invalid callee token tag");
 }
 
 // In between every two frames lies a small header describing both frames. This
 // header, minimally, contains a returnAddress word and a descriptor word. The
 // descriptor describes the size and type of the previous frame, whereas the
 // returnAddress describes the address the newer frame (the callee) will return
@@ -281,41 +267,35 @@ void MarkIonCompilerRoots(JSTracer *trc)
 static inline uint32_t
 MakeFrameDescriptor(uint32_t frameSize, FrameType type)
 {
     return (frameSize << FRAMESIZE_SHIFT) | type;
 }
 
 // Returns the JSScript associated with the topmost Ion frame.
 inline JSScript *
-GetTopIonJSScript(PerThreadData *pt, void **returnAddrOut)
+GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode)
 {
-    IonFrameIterator iter(pt->ionTop);
+    IonFrameIterator iter(ionTop, mode);
     JS_ASSERT(iter.type() == IonFrame_Exit);
     ++iter;
 
     JS_ASSERT(iter.returnAddressToFp() != nullptr);
     if (returnAddrOut)
         *returnAddrOut = (void *) iter.returnAddressToFp();
 
     if (iter.isBaselineStub()) {
         ++iter;
         JS_ASSERT(iter.isBaselineJS());
     }
 
     JS_ASSERT(iter.isScripted());
     return iter.script();
 }
 
-inline JSScript *
-GetTopIonJSScript(ThreadSafeContext *cx, void **returnAddrOut = nullptr)
-{
-    return GetTopIonJSScript(cx->perThreadData, returnAddrOut);
-}
-
 } // namespace jit
 } // namespace js
 
 #if defined(JS_CPU_X86) || defined (JS_CPU_X64)
 # include "jit/shared/IonFrames-x86-shared.h"
 #elif defined (JS_CPU_ARM)
 # include "jit/arm/IonFrames-arm.h"
 #else
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -897,21 +897,20 @@ MacroAssembler::compareStrings(JSOp op, 
     branchPtr(Assembler::Equal, result, temp, fail);
     move32(Imm32(op == JSOP_NE || op == JSOP_STRICTNE), result);
 
     bind(&done);
 }
 
 void
 MacroAssembler::checkInterruptFlagsPar(const Register &tempReg,
-                                            Label *fail)
+                                       Label *fail)
 {
     movePtr(ImmPtr(&GetIonContext()->runtime->interrupt), tempReg);
-    load32(Address(tempReg, 0), tempReg);
-    branchTest32(Assembler::NonZero, tempReg, tempReg, fail);
+    branch32(Assembler::NonZero, Address(tempReg, 0), Imm32(0), fail);
 }
 
 void
 MacroAssembler::maybeRemoveOsrFrame(Register scratch)
 {
     // Before we link an exit frame, check for an OSR frame, which is
     // indicative of working inside an existing bailout. In this case, remove
     // the OSR frame, so we don't explode the stack with repeated bailouts.
@@ -1307,66 +1306,17 @@ MacroAssembler::handleFailure(ExecutionM
     }
     MacroAssemblerSpecific::handleFailureWithHandler(handler);
 
     // Doesn't actually emit code, but balances the leave()
     if (sps_)
         sps_->reenter(*this, InvalidReg);
 }
 
-void
-MacroAssembler::pushCalleeToken(Register callee, ExecutionMode mode)
-{
-    // Tag and push a callee, then clear the tag after pushing. This is needed
-    // if we dereference the callee pointer after pushing it as part of a
-    // frame.
-    tagCallee(callee, mode);
-    push(callee);
-    clearCalleeTag(callee, mode);
-}
-
-void
-MacroAssembler::PushCalleeToken(Register callee, ExecutionMode mode)
-{
-    tagCallee(callee, mode);
-    Push(callee);
-    clearCalleeTag(callee, mode);
-}
-
-void
-MacroAssembler::tagCallee(Register callee, ExecutionMode mode)
-{
-    switch (mode) {
-      case SequentialExecution:
-        // CalleeToken_Function is untagged, so we don't need to do anything.
-        return;
-      case ParallelExecution:
-        orPtr(Imm32(CalleeToken_ParallelFunction), callee);
-        return;
-      default:
-        MOZ_ASSUME_UNREACHABLE("No such execution mode");
-    }
-}
-
-void
-MacroAssembler::clearCalleeTag(Register callee, ExecutionMode mode)
-{
-    switch (mode) {
-      case SequentialExecution:
-        // CalleeToken_Function is untagged, so we don't need to do anything.
-        return;
-      case ParallelExecution:
-        andPtr(Imm32(~0x3), callee);
-        return;
-      default:
-        MOZ_ASSUME_UNREACHABLE("No such execution mode");
-    }
-}
-
-void printf0_(const char *output) {
+static void printf0_(const char *output) {
     printf("%s", output);
 }
 
 void
 MacroAssembler::printf(const char *output)
 {
     RegisterSet regs = RegisterSet::Volatile();
     PushRegsInMask(regs);
@@ -1376,17 +1326,17 @@ MacroAssembler::printf(const char *outpu
     setupUnalignedABICall(1, temp);
     movePtr(ImmPtr(output), temp);
     passABIArg(temp);
     callWithABI(JS_FUNC_TO_DATA_PTR(void *, printf0_));
 
     PopRegsInMask(RegisterSet::Volatile());
 }
 
-void printf1_(const char *output, uintptr_t value) {
+static void printf1_(const char *output, uintptr_t value) {
     char *line = JS_sprintf_append(nullptr, output, value);
     printf("%s", line);
     js_free(line);
 }
 
 void
 MacroAssembler::printf(const char *output, Register value)
 {
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -402,18 +402,20 @@ class MacroAssembler : public MacroAssem
     }
 
     template <typename T>
     void storeTypedOrValue(TypedOrValueRegister src, const T &dest) {
         if (src.hasValue()) {
             storeValue(src.valueReg(), dest);
         } else if (IsFloatingPointType(src.type())) {
             FloatRegister reg = src.typedReg().fpu();
-            if (src.type() == MIRType_Float32)
-                convertFloatToDouble(reg, reg);
+            if (src.type() == MIRType_Float32) {
+                convertFloatToDouble(reg, ScratchFloatReg);
+                reg = ScratchFloatReg;
+            }
             storeDouble(reg, dest);
         } else {
             storeValue(ValueTypeFromMIRType(src.type()), src.typedReg().gpr(), dest);
         }
     }
 
     template <typename T>
     void storeConstantOrRegister(ConstantOrRegister src, const T &dest) {
@@ -548,18 +550,20 @@ class MacroAssembler : public MacroAssem
         }
     }
 
     void Push(TypedOrValueRegister v) {
         if (v.hasValue()) {
             Push(v.valueReg());
         } else if (IsFloatingPointType(v.type())) {
             FloatRegister reg = v.typedReg().fpu();
-            if (v.type() == MIRType_Float32)
-                convertFloatToDouble(reg, reg);
+            if (v.type() == MIRType_Float32) {
+                convertFloatToDouble(reg, ScratchFloatReg);
+                reg = ScratchFloatReg;
+            }
             Push(reg);
         } else {
             Push(ValueTypeFromMIRType(v.type()), v.typedReg().gpr());
         }
     }
 
     void Push(ConstantOrRegister v) {
         if (v.constant())
@@ -930,21 +934,16 @@ class MacroAssembler : public MacroAssem
         branchPtr(Assembler::Equal, scratch, ImmPtr(&ProxyObject::callableClass_), slowCheck);
         branchPtr(Assembler::Equal, scratch, ImmPtr(&ProxyObject::uncallableClass_), slowCheck);
         branchPtr(Assembler::Equal, scratch, ImmPtr(&OuterWindowProxyObject::class_), slowCheck);
 
         test32(Address(scratch, Class::offsetOfFlags()), Imm32(JSCLASS_EMULATES_UNDEFINED));
         return truthy ? Assembler::Zero : Assembler::NonZero;
     }
 
-    void pushCalleeToken(Register callee, ExecutionMode mode);
-    void PushCalleeToken(Register callee, ExecutionMode mode);
-    void tagCallee(Register callee, ExecutionMode mode);
-    void clearCalleeTag(Register callee, ExecutionMode mode);
-
   private:
     // These two functions are helpers used around call sites throughout the
     // assembler. They are called from the above call wrappers to emit the
     // necessary instrumentation.
     void leaveSPSFrame() {
         if (!sps_ || !sps_->enabled())
             return;
         // No registers are guaranteed to be available, so push/pop a register
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -4351,60 +4351,72 @@ class LCallDeleteElement : public LCallI
 
     MDeleteElement *mir() const {
         return mir_->toDeleteElement();
     }
 };
 
 // Patchable jump to stubs generated for a SetProperty cache, which stores a
 // boxed value.
-class LSetPropertyCacheV : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
+class LSetPropertyCacheV : public LInstructionHelper<0, 1 + BOX_PIECES, 2>
 {
   public:
     LIR_HEADER(SetPropertyCacheV)
 
-    LSetPropertyCacheV(const LAllocation &object, const LDefinition &slots) {
+    LSetPropertyCacheV(const LAllocation &object, const LDefinition &slots,
+                       const LDefinition &temp) {
         setOperand(0, object);
         setTemp(0, slots);
+        setTemp(1, temp);
     }
 
     static const size_t Value = 1;
 
     const MSetPropertyCache *mir() const {
         return mir_->toSetPropertyCache();
     }
+
+    const LDefinition *tempForDispatchCache() {
+        return getTemp(1);
+    }
 };
 
 // Patchable jump to stubs generated for a SetProperty cache, which stores a
 // value of a known type.
-class LSetPropertyCacheT : public LInstructionHelper<0, 2, 1>
+class LSetPropertyCacheT : public LInstructionHelper<0, 2, 2>
 {
     MIRType valueType_;
 
   public:
     LIR_HEADER(SetPropertyCacheT)
 
     LSetPropertyCacheT(const LAllocation &object, const LDefinition &slots,
-                       const LAllocation &value, MIRType valueType)
+                       const LAllocation &value, const LDefinition &temp,
+                       MIRType valueType)
         : valueType_(valueType)
     {
         setOperand(0, object);
         setOperand(1, value);
         setTemp(0, slots);
+        setTemp(1, temp);
     }
 
     const MSetPropertyCache *mir() const {
         return mir_->toSetPropertyCache();
     }
     MIRType valueType() {
         return valueType_;
     }
     const char *extraName() const {
         return StringFromMIRType(valueType_);
     }
+
+    const LDefinition *tempForDispatchCache() {
+        return getTemp(1);
+    }
 };
 
 class LSetElementCacheV : public LInstructionHelper<0, 1 + 2 * BOX_PIECES, 3>
 {
   public:
     LIR_HEADER(SetElementCacheV);
 
     static const size_t Index = 1;
--- a/js/src/jit/LiveRangeAllocator.cpp
+++ b/js/src/jit/LiveRangeAllocator.cpp
@@ -627,19 +627,38 @@ LiveRangeAllocator<VREG>::buildLivenessI
                         if (LSafepoint *safepoint = ins->safepoint())
                             AddRegisterToSafepoint(safepoint, reg, *temp);
                     } else {
                         JS_ASSERT(!ins->isCall());
                         if (!vregs[temp].getInterval(0)->addRangeAtHead(inputOf(*ins), outputOf(*ins)))
                             return false;
                     }
                 } else {
+                    // Normally temps are considered to cover both the input
+                    // and output of the associated instruction. In some cases
+                    // though we want to use a fixed register as both an input
+                    // and clobbered register in the instruction, so watch for
+                    // this and shorten the temp to cover only the output.
+                    CodePosition from = inputOf(*ins);
+                    if (temp->policy() == LDefinition::PRESET) {
+                        AnyRegister reg = temp->output()->toRegister();
+                        for (LInstruction::InputIterator alloc(**ins); alloc.more(); alloc.next()) {
+                            if (alloc->isUse()) {
+                                LUse *use = alloc->toUse();
+                                if (use->isFixedRegister()) {
+                                    if (GetFixedRegister(vregs[use].def(), use) == reg)
+                                        from = outputOf(*ins);
+                                }
+                            }
+                        }
+                    }
+
                     CodePosition to =
                         ins->isCall() ? outputOf(*ins) : outputOf(*ins).next();
-                    if (!vregs[temp].getInterval(0)->addRangeAtHead(inputOf(*ins), to))
+                    if (!vregs[temp].getInterval(0)->addRangeAtHead(from, to))
                         return false;
                 }
             }
 
             DebugOnly<bool> hasUseRegister = false;
             DebugOnly<bool> hasUseRegisterAtStart = false;
 
             for (LInstruction::InputIterator alloc(**ins); alloc.more(); alloc.next()) {
@@ -679,17 +698,16 @@ LiveRangeAllocator<VREG>::buildLivenessI
 
                     // Don't treat RECOVERED_INPUT uses as keeping the vreg alive.
                     if (use->policy() == LUse::RECOVERED_INPUT)
                         continue;
 
                     CodePosition to;
                     if (forLSRA) {
                         if (use->isFixedRegister()) {
-                            JS_ASSERT(!use->usedAtStart());
                             AnyRegister reg = GetFixedRegister(vregs[use].def(), use);
                             if (!addFixedRangeAtHead(reg, inputOf(*ins), outputOf(*ins)))
                                 return false;
                             to = inputOf(*ins);
 
                             // Fixed intervals are not added to safepoints, so do it
                             // here.
                             LSafepoint *safepoint = ins->safepoint();
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2598,17 +2598,18 @@ LIRGenerator::visitGetPropertyCache(MGet
     JS_ASSERT(ins->object()->type() == MIRType_Object);
     if (ins->type() == MIRType_Value) {
         LGetPropertyCacheV *lir = new LGetPropertyCacheV(useRegister(ins->object()));
         if (!defineBox(lir, ins))
             return false;
         return assignSafepoint(lir, ins);
     }
 
-    LGetPropertyCacheT *lir = newLGetPropertyCacheT(ins);
+    LGetPropertyCacheT *lir = new LGetPropertyCacheT(useRegister(ins->object()),
+                                                     tempForDispatchCache(ins->type()));
     if (!define(lir, ins))
         return false;
     return assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic *ins)
 {
@@ -2651,17 +2652,19 @@ LIRGenerator::visitGetElementCache(MGetE
         JS_ASSERT(ins->index()->type() == MIRType_Value);
         LGetElementCacheV *lir = new LGetElementCacheV(useRegister(ins->object()));
         if (!useBox(lir, LGetElementCacheV::Index, ins->index()))
             return false;
         return defineBox(lir, ins) && assignSafepoint(lir, ins);
     }
 
     JS_ASSERT(ins->index()->type() == MIRType_Int32);
-    LGetElementCacheT *lir = newLGetElementCacheT(ins);
+    LGetElementCacheT *lir = new LGetElementCacheT(useRegister(ins->object()),
+                                                   useRegister(ins->index()),
+                                                   tempForDispatchCache(ins->type()));
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitBindNameCache(MBindNameCache *ins)
 {
     JS_ASSERT(ins->scopeChain()->type() == MIRType_Object);
     JS_ASSERT(ins->type() == MIRType_Object);
@@ -2753,17 +2756,17 @@ LIRGenerator::visitCallGetElement(MCallG
     if (!defineReturn(lir, ins))
         return false;
     return assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitCallSetProperty(MCallSetProperty *ins)
 {
-    LInstruction *lir = new LCallSetProperty(useRegisterAtStart(ins->obj()));
+    LInstruction *lir = new LCallSetProperty(useRegisterAtStart(ins->object()));
     if (!useBoxAtStart(lir, LCallSetProperty::Value, ins->value()))
         return false;
     if (!add(lir, ins))
         return false;
     return assignSafepoint(lir, ins);
 }
 
 bool
@@ -2784,27 +2787,28 @@ LIRGenerator::visitDeleteElement(MDelete
     if(!useBoxAtStart(lir, LCallDeleteElement::Index, ins->index()))
         return false;
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitSetPropertyCache(MSetPropertyCache *ins)
 {
-    LUse obj = useRegisterAtStart(ins->obj());
-    LDefinition slots = tempCopy(ins->obj(), 0);
+    LUse obj = useRegisterAtStart(ins->object());
+    LDefinition slots = tempCopy(ins->object(), 0);
+    LDefinition dispatchTemp = tempForDispatchCache();
 
     LInstruction *lir;
     if (ins->value()->type() == MIRType_Value) {
-        lir = new LSetPropertyCacheV(obj, slots);
+        lir = new LSetPropertyCacheV(obj, slots, dispatchTemp);
         if (!useBox(lir, LSetPropertyCacheV::Value, ins->value()))
             return false;
     } else {
         LAllocation value = useRegisterOrConstant(ins->value());
-        lir = new LSetPropertyCacheT(obj, slots, value, ins->value()->type());
+        lir = new LSetPropertyCacheT(obj, slots, value, dispatchTemp, ins->value()->type());
     }
 
     if (!add(lir, ins))
         return false;
 
     return assignSafepoint(lir, ins);
 }
 
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6961,17 +6961,17 @@ class MSetPropertyInstruction : public M
   protected:
     MSetPropertyInstruction(MDefinition *obj, MDefinition *value, PropertyName *name,
                             bool strict)
       : MBinaryInstruction(obj, value),
         name_(name), strict_(strict), needsBarrier_(true)
     {}
 
   public:
-    MDefinition *obj() const {
+    MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
     PropertyName *name() const {
         return name_;
     }
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -50,17 +50,17 @@ jit::IsThreadLocalObject(ForkJoinSlice *
 static void
 printTrace(const char *prefix, struct IonLIRTraceData *cached)
 {
     fprintf(stderr, "%s / Block %3u / LIR %3u / Mode %u / LIR %s\n",
             prefix,
             cached->blockIndex, cached->lirIndex, cached->execModeInt, cached->lirOpName);
 }
 
-struct IonLIRTraceData seqTraceData;
+static struct IonLIRTraceData seqTraceData;
 #endif
 
 void
 jit::TraceLIR(IonLIRTraceData *current)
 {
 #ifdef DEBUG
     static enum { NotSet, All, Bailouts } traceMode;
 
@@ -120,18 +120,17 @@ jit::CheckOverRecursedPar(ForkJoinSlice 
 
     uintptr_t realStackLimit;
     if (slice->isMainThread())
         realStackLimit = GetNativeStackLimit(slice);
     else
         realStackLimit = slice->perThreadData->ionStackLimit;
 
     if (!JS_CHECK_STACK_SIZE(realStackLimit, &stackDummy_)) {
-        slice->bailoutRecord->setCause(ParallelBailoutOverRecursed,
-                                       nullptr, nullptr, nullptr);
+        slice->bailoutRecord->setCause(ParallelBailoutOverRecursed);
         return false;
     }
 
     return CheckInterruptPar(slice);
 }
 
 bool
 jit::CheckInterruptPar(ForkJoinSlice *slice)
@@ -154,70 +153,77 @@ jit::ExtendArrayPar(ForkJoinSlice *slice
 {
     JSObject::EnsureDenseResult res =
         array->ensureDenseElementsPreservePackedFlag(slice, 0, length);
     if (res != JSObject::ED_OK)
         return nullptr;
     return array;
 }
 
-ParallelResult
+bool
+jit::SetPropertyPar(ForkJoinSlice *slice, HandleObject obj, HandlePropertyName name,
+                    HandleValue value, bool strict, jsbytecode *pc)
+{
+    JS_ASSERT(slice->isThreadLocal(obj));
+
+    if (*pc == JSOP_SETALIASEDVAR) {
+        // See comment in jit::SetProperty.
+        Shape *shape = obj->nativeLookupPure(name);
+        JS_ASSERT(shape && shape->hasSlot());
+        return obj->nativeSetSlotIfHasType(shape, value);
+    }
+
+    // Fail early on hooks.
+    if (obj->getOps()->setProperty)
+        return TP_RETRY_SEQUENTIALLY;
+
+    RootedValue v(slice, value);
+    RootedId id(slice, NameToId(name));
+    return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict);
+}
+
+bool
 jit::SetElementPar(ForkJoinSlice *slice, HandleObject obj, HandleValue index, HandleValue value,
                    bool strict)
 {
     RootedId id(slice);
     if (!ValueToIdPure(index, id.address()))
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
 
     // 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;
+    return baseops::SetPropertyHelper<ParallelExecution>(slice, obj, obj, id, 0, &v, strict);
 }
 
-ParallelResult
-jit::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
-                      MutableHandleString out)
+JSString *
+jit::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right)
 {
-    JSString *str = ConcatStrings<NoGC>(slice, left, right);
-    if (!str)
-        return TP_RETRY_SEQUENTIALLY;
-    out.set(str);
-    return TP_SUCCESS;
+    return ConcatStrings<NoGC>(slice, left, right);
 }
 
-ParallelResult
-jit::IntToStringPar(ForkJoinSlice *slice, int i, MutableHandleString out)
+JSFlatString *
+jit::IntToStringPar(ForkJoinSlice *slice, int i)
 {
-    JSFlatString *str = Int32ToString<NoGC>(slice, i);
-    if (!str)
-        return TP_RETRY_SEQUENTIALLY;
-    out.set(str);
-    return TP_SUCCESS;
+    return Int32ToString<NoGC>(slice, i);
 }
 
-ParallelResult
-jit::DoubleToStringPar(ForkJoinSlice *slice, double d, MutableHandleString out)
+JSString *
+jit::DoubleToStringPar(ForkJoinSlice *slice, double d)
 {
-    JSString *str = NumberToString<NoGC>(slice, d);
-    if (!str)
-        return TP_RETRY_SEQUENTIALLY;
-    out.set(str);
-    return TP_SUCCESS;
+    return NumberToString<NoGC>(slice, d);
 }
 
-ParallelResult
+bool
 jit::StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out)
 {
-    return StringToNumber(slice, str, out) ? TP_SUCCESS : TP_FATAL;
+    return StringToNumber(slice, str, out);
 }
 
 #define PAR_RELATIONAL_OP(OP, EXPECTED)                                         \
 do {                                                                            \
     /* Optimize for two int-tagged operands (typical loop control). */          \
     if (lhs.isInt32() && rhs.isInt32()) {                                       \
         *res = (lhs.toInt32() OP rhs.toInt32()) == EXPECTED;                    \
     } else if (lhs.isNumber() && rhs.isNumber()) {                              \
@@ -232,238 +238,234 @@ do {                                    
         double r = rhs.toNumber();                                              \
         *res = (l OP r) == EXPECTED;                                            \
     } else if (lhs.isNumber() && rhs.isBoolean()) {                             \
         double l = lhs.toNumber();                                              \
         bool r = rhs.toBoolean();                                               \
         *res = (l OP r) == EXPECTED;                                            \
     } else {                                                                    \
         int32_t vsZero;                                                         \
-        ParallelResult ret = CompareMaybeStringsPar(slice, lhs, rhs, &vsZero);  \
-        if (ret != TP_SUCCESS)                                                  \
-            return ret;                                                         \
+        if (!CompareMaybeStringsPar(slice, lhs, rhs, &vsZero))                  \
+            return false;                                                       \
         *res = (vsZero OP 0) == EXPECTED;                                       \
     }                                                                           \
-    return TP_SUCCESS;                                                          \
+    return true;                                                                \
 } while(0)
 
-static ParallelResult
+static bool
 CompareStringsPar(ForkJoinSlice *slice, JSString *left, JSString *right, int32_t *res)
 {
     ScopedThreadSafeStringInspector leftInspector(left);
     ScopedThreadSafeStringInspector rightInspector(right);
     if (!leftInspector.ensureChars(slice) || !rightInspector.ensureChars(slice))
-        return TP_FATAL;
+        return false;
 
-    if (!CompareChars(leftInspector.chars(), left->length(),
-                      rightInspector.chars(), right->length(),
-                      res))
-        return TP_FATAL;
-
-    return TP_SUCCESS;
+    return CompareChars(leftInspector.chars(), left->length(),
+                        rightInspector.chars(), right->length(),
+                        res);
 }
 
-static ParallelResult
+static bool
 CompareMaybeStringsPar(ForkJoinSlice *slice, HandleValue v1, HandleValue v2, int32_t *res)
 {
     if (!v1.isString())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     if (!v2.isString())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     return CompareStringsPar(slice, v1.toString(), v2.toString(), res);
 }
 
 template<bool Equal>
-ParallelResult
+bool
 LooselyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(==, Equal);
 }
 
-ParallelResult
+bool
 js::jit::LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return LooselyEqualImplPar<true>(slice, lhs, rhs, res);
 }
 
-ParallelResult
+bool
 js::jit::LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return LooselyEqualImplPar<false>(slice, lhs, rhs, res);
 }
 
 template<bool Equal>
-ParallelResult
+bool
 StrictlyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     if (lhs.isNumber()) {
         if (rhs.isNumber()) {
             *res = (lhs.toNumber() == rhs.toNumber()) == Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isBoolean()) {
         if (rhs.isBoolean()) {
             *res = (lhs.toBoolean() == rhs.toBoolean()) == Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isNull()) {
         if (rhs.isNull()) {
             *res = Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isUndefined()) {
         if (rhs.isUndefined()) {
             *res = Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isObject()) {
         if (rhs.isObject()) {
             *res = (lhs.toObjectOrNull() == rhs.toObjectOrNull()) == Equal;
-            return TP_SUCCESS;
+            return true;
         }
     } else if (lhs.isString()) {
         if (rhs.isString())
             return LooselyEqualImplPar<Equal>(slice, lhs, rhs, res);
     }
 
     *res = false;
-    return TP_SUCCESS;
+    return true;
 }
 
-ParallelResult
+bool
 js::jit::StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return StrictlyEqualImplPar<true>(slice, lhs, rhs, res);
 }
 
-ParallelResult
+bool
 js::jit::StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return StrictlyEqualImplPar<false>(slice, lhs, rhs, res);
 }
 
-ParallelResult
+bool
 js::jit::LessThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(<, true);
 }
 
-ParallelResult
+bool
 js::jit::LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(<=, true);
 }
 
-ParallelResult
+bool
 js::jit::GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(>, true);
 }
 
-ParallelResult
+bool
 js::jit::GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(>=, true);
 }
 
 template<bool Equal>
-ParallelResult
+bool
 StringsEqualImplPar(ForkJoinSlice *slice, HandleString lhs, HandleString rhs, bool *res)
 {
     int32_t vsZero;
-    ParallelResult ret = CompareStringsPar(slice, lhs, rhs, &vsZero);
-    if (ret != TP_SUCCESS)
+    bool ret = CompareStringsPar(slice, lhs, rhs, &vsZero);
+    if (ret != true)
         return ret;
     *res = (vsZero == 0) == Equal;
-    return TP_SUCCESS;
+    return true;
 }
 
-ParallelResult
+bool
 js::jit::StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *res)
 {
     return StringsEqualImplPar<true>(slice, v1, v2, res);
 }
 
-ParallelResult
+bool
 js::jit::StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *res)
 {
     return StringsEqualImplPar<false>(slice, v1, v2, res);
 }
 
-ParallelResult
+bool
 jit::BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out)
 {
     if (in.isObject())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     int i;
     if (!NonObjectToInt32(slice, in, &i))
-        return TP_FATAL;
+        return false;
     *out = ~i;
-    return TP_SUCCESS;
+    return true;
 }
 
 #define BIT_OP(OP)                                                      \
     JS_BEGIN_MACRO                                                      \
     int32_t left, right;                                                \
     if (lhs.isObject() || rhs.isObject())                               \
         return TP_RETRY_SEQUENTIALLY;                                   \
     if (!NonObjectToInt32(slice, lhs, &left) ||                         \
         !NonObjectToInt32(slice, rhs, &right))                          \
     {                                                                   \
-        return TP_FATAL;                                                \
+        return false;                                                   \
     }                                                                   \
     *out = (OP);                                                        \
-    return TP_SUCCESS;                                                  \
+    return true;                                                        \
     JS_END_MACRO
 
-ParallelResult
+bool
 jit::BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left ^ right);
 }
 
-ParallelResult
+bool
 jit::BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left | right);
 }
 
-ParallelResult
+bool
 jit::BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left & right);
 }
 
-ParallelResult
+bool
 jit::BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left << (right & 31));
 }
 
-ParallelResult
+bool
 jit::BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out)
 {
     BIT_OP(left >> (right & 31));
 }
 
 #undef BIT_OP
 
-ParallelResult
+bool
 jit::UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
                    Value *out)
 {
     uint32_t left;
     int32_t right;
     if (lhs.isObject() || rhs.isObject())
-        return TP_RETRY_SEQUENTIALLY;
+        return false;
     if (!NonObjectToUint32(slice, lhs, &left) || !NonObjectToInt32(slice, rhs, &right))
-        return TP_FATAL;
+        return false;
     left >>= right & 31;
     out->setNumber(uint32_t(left));
-    return TP_SUCCESS;
+    return true;
 }
 
 void
 jit::AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode)
 {
     // Spew before asserts to help with diagnosing failures.
     Spew(SpewBailouts,
@@ -477,18 +479,17 @@ jit::AbortPar(ParallelBailoutCause cause
     JS_ASSERT(InParallelSection());
     JS_ASSERT(outermostScript != nullptr);
     JS_ASSERT(currentScript != nullptr);
     JS_ASSERT(outermostScript->hasParallelIonScript());
 
     ForkJoinSlice *slice = ForkJoinSlice::Current();
 
     JS_ASSERT(slice->bailoutRecord->depth == 0);
-    slice->bailoutRecord->setCause(cause, outermostScript,
-                                   currentScript, bytecode);
+    slice->bailoutRecord->setCause(cause, outermostScript, currentScript, bytecode);
 }
 
 void
 jit::PropagateAbortPar(JSScript *outermostScript, JSScript *currentScript)
 {
     Spew(SpewBailouts,
          "Propagate parallel abort via %p:%s:%d (%p:%s:%d)",
          outermostScript, outermostScript->filename(), outermostScript->lineno,
@@ -543,33 +544,31 @@ jit::CallToUncompiledScriptPar(JSObject 
         }
     } else {
         JS_ASSERT(func->isNative());
         Spew(SpewBailouts, "Call to native function");
     }
 #endif
 }
 
-ParallelResult
+JSObject *
 jit::InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
-                          HandleObject templateObj, HandleObject res,
-                          MutableHandleObject out)
+                          HandleObject templateObj, HandleObject res)
 {
     // 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 > 0) {
         JSObject::EnsureDenseResult edr =
             res->ensureDenseElementsPreservePackedFlag(slice, 0, length);
         if (edr != JSObject::ED_OK)
-            return TP_FATAL;
+            return nullptr;
         res->initDenseElements(0, rest, length);
         res->as<ArrayObject>().setLengthInt32(length);
     }
 
-    out.set(res);
-    return TP_SUCCESS;
+    return res;
 }
--- a/js/src/jit/ParallelFunctions.h
+++ b/js/src/jit/ParallelFunctions.h
@@ -20,55 +20,55 @@ bool CheckOverRecursedPar(ForkJoinSlice 
 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);
+bool SetPropertyPar(ForkJoinSlice *slice, HandleObject obj, HandlePropertyName name,
+                    HandleValue value, bool strict, jsbytecode *pc);
+bool 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);
+JSString *ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right);
+JSFlatString *IntToStringPar(ForkJoinSlice *slice, int i);
+JSString *DoubleToStringPar(ForkJoinSlice *slice, double d);
+bool StringToNumberPar(ForkJoinSlice *slice, JSString *str, double *out);
 
 // Binary and unary operator functions on values. These tend to return
 // RETRY_SEQUENTIALLY if the values are objects.
-ParallelResult StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LessThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
-ParallelResult GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LessThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+bool GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 
-ParallelResult StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
-ParallelResult StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
+bool StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
+bool StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
 
-ParallelResult BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out);
-ParallelResult BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
-ParallelResult BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitNotPar(ForkJoinSlice *slice, HandleValue in, int32_t *out);
+bool BitXorPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitOrPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitAndPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitLshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
+bool BitRshPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs, int32_t *out);
 
-ParallelResult UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
+bool UrshValuesPar(ForkJoinSlice *slice, HandleValue lhs, HandleValue rhs,
                              Value *out);
 
 // Make a new rest parameter in parallel.
-ParallelResult InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
-                                    HandleObject templateObj, HandleObject res,
-                                    MutableHandleObject out);
+JSObject *InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
+                               HandleObject templateObj, HandleObject res);
 
 // Abort and debug tracing functions.
 void AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode);
 void PropagateAbortPar(JSScript *outermostScript, JSScript *currentScript);
 
 void TraceLIR(IonLIRTraceData *current);
 
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -196,17 +196,17 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(FunctionEnvironment) // just a load of func env ptr
     SAFE_OP(TypeBarrier) // causes a bailout if the type is not found: a-ok with us
     SAFE_OP(MonitorTypes) // causes a bailout if the type is not found: a-ok with us
     UNSAFE_OP(PostWriteBarrier)
     SAFE_OP(GetPropertyCache)
     SAFE_OP(GetPropertyPolymorphic)
     UNSAFE_OP(SetPropertyPolymorphic)
     SAFE_OP(GetElementCache)
-    UNSAFE_OP(SetElementCache)
+    WRITE_GUARDED_OP(SetElementCache, object)
     UNSAFE_OP(BindNameCache)
     SAFE_OP(GuardShape)
     SAFE_OP(GuardObjectType)
     SAFE_OP(GuardClass)
     SAFE_OP(AssertRange)
     SAFE_OP(ArrayLength)
     SAFE_OP(TypedArrayLength)
     SAFE_OP(TypedArrayElements)
@@ -231,22 +231,22 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(ClampToUint8)
     SAFE_OP(LoadFixedSlot)
     WRITE_GUARDED_OP(StoreFixedSlot, object)
     UNSAFE_OP(CallGetProperty)
     UNSAFE_OP(GetNameCache)
     UNSAFE_OP(CallGetIntrinsicValue)
     UNSAFE_OP(CallsiteCloneCache)
     UNSAFE_OP(CallGetElement)
-    UNSAFE_OP(CallSetElement)
+    WRITE_GUARDED_OP(CallSetElement, object)
     UNSAFE_OP(CallInitElementArray)
-    UNSAFE_OP(CallSetProperty)
+    WRITE_GUARDED_OP(CallSetProperty, object)
     UNSAFE_OP(DeleteProperty)
     UNSAFE_OP(DeleteElement)
-    UNSAFE_OP(SetPropertyCache)
+    WRITE_GUARDED_OP(SetPropertyCache, object)
     UNSAFE_OP(IteratorStart)
     UNSAFE_OP(IteratorNext)
     UNSAFE_OP(IteratorMore)
     UNSAFE_OP(IteratorEnd)
     SAFE_OP(StringLength)
     SAFE_OP(ArgumentsLength)
     SAFE_OP(GetFrameArgument)
     UNSAFE_OP(SetFrameArgument)
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -2162,17 +2162,17 @@ RemoveTruncatesOnOutput(MInstruction *tr
         MDefinition *def = use.def();
         if (!def->isTruncateToInt32() || !def->isToInt32())
             continue;
 
         def->replaceAllUsesWith(truncated);
     }
 }
 
-void
+static void
 AdjustTruncatedInputs(MInstruction *truncated)
 {
     MBasicBlock *block = truncated->block();
     for (size_t i = 0, e = truncated->numOperands(); i < e; i++) {
         if (!truncated->isOperandTruncated(i))
             continue;
         if (truncated->getOperand(i)->type() == MIRType_Int32)
             continue;
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -14,29 +14,37 @@
 #include "jit/IonFrames.h"
 #include "vm/ArrayObject.h"
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
 
 #include "jsinferinlines.h"
 
 #include "jit/BaselineFrame-inl.h"
+#include "jit/IonFrames-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
 namespace js {
 namespace jit {
 
 // Don't explicitly initialize, it's not guaranteed that this initializer will
 // run before the constructors for static VMFunctions.
 /* static */ VMFunction *VMFunction::functions;
 
+AutoDetectInvalidation::AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript)
+  : cx_(cx),
+    ionScript_(ionScript ? ionScript : GetTopIonJSScript(cx)->ionScript()),
+    rval_(rval),
+    disabled_(false)
+{ }
+
 void
 VMFunction::addToFunctions()
 {
     static bool initialized = false;
     if (!initialized) {
         initialized = true;
         functions = nullptr;
     }
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -22,18 +22,17 @@ namespace jit {
 enum DataType {
     Type_Void,
     Type_Bool,
     Type_Int32,
     Type_Double,
     Type_Pointer,
     Type_Object,
     Type_Value,
-    Type_Handle,
-    Type_ParallelResult
+    Type_Handle
 };
 
 struct PopValues
 {
     uint32_t numValues;
 
     explicit PopValues(uint32_t numValues)
       : numValues(numValues)
@@ -215,20 +214,18 @@ struct VMFunction
         argumentRootTypes(argRootTypes),
         outParamRootType(outParamRootType),
         executionMode(executionMode),
         extraValuesToPop(extraValuesToPop)
     {
         // Check for valid failure/return type.
         JS_ASSERT_IF(outParam != Type_Void && executionMode == SequentialExecution,
                      returnType == Type_Bool);
-        JS_ASSERT_IF(executionMode == ParallelExecution, returnType == Type_ParallelResult);
         JS_ASSERT(returnType == Type_Bool ||
-                  returnType == Type_Object ||
-                  returnType == Type_ParallelResult);
+                  returnType == Type_Object);
     }
 
     VMFunction(const VMFunction &o) {
         init(o);
     }
 
     void init(const VMFunction &o) {
         JS_ASSERT(!wrapped);
@@ -275,17 +272,16 @@ template <> struct TypeToDataType<JSFlat
 template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleString> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandlePropertyName> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleFunction> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<Handle<StaticBlockObject *> > { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleScript> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<HandleValue> { static const DataType result = Type_Handle; };
 template <> struct TypeToDataType<MutableHandleValue> { static const DataType result = Type_Handle; };
-template <> struct TypeToDataType<ParallelResult> { static const DataType result = Type_ParallelResult; };
 
 // Convert argument types to properties of the argument known by the jit.
 template <class T> struct TypeToArgProperties {
     static const uint32_t result =
         (sizeof(T) <= sizeof(void *) ? VMFunction::Word : VMFunction::Double);
 };
 template <> struct TypeToArgProperties<const Value &> {
     static const uint32_t result = TypeToArgProperties<Value>::result | VMFunction::ByRef;
@@ -390,18 +386,18 @@ template <> struct MatchContext<JSContex
 template <> struct MatchContext<ExclusiveContext *> {
     static const ExecutionMode execMode = SequentialExecution;
 };
 template <> struct MatchContext<ForkJoinSlice *> {
     static const ExecutionMode execMode = ParallelExecution;
 };
 template <> struct MatchContext<ThreadSafeContext *> {
     // ThreadSafeContext functions can be called from either mode, but for
-    // calling from parallel they need to be wrapped first to return a
-    // ParallelResult, so we default to SequentialExecution here.
+    // calling from parallel they should be wrapped first, so we default to
+    // SequentialExecution here.
     static const ExecutionMode execMode = SequentialExecution;
 };
 
 #define FOR_EACH_ARGS_1(Macro, Sep, Last) Macro(1) Last(1)
 #define FOR_EACH_ARGS_2(Macro, Sep, Last) FOR_EACH_ARGS_1(Macro, Sep, Sep) Macro(2) Last(2)
 #define FOR_EACH_ARGS_3(Macro, Sep, Last) FOR_EACH_ARGS_2(Macro, Sep, Sep) Macro(3) Last(3)
 #define FOR_EACH_ARGS_4(Macro, Sep, Last) FOR_EACH_ARGS_3(Macro, Sep, Sep) Macro(4) Last(4)
 #define FOR_EACH_ARGS_5(Macro, Sep, Last) FOR_EACH_ARGS_4(Macro, Sep, Sep) Macro(5) Last(5)
@@ -551,22 +547,17 @@ template <class R, class Context, class 
 class AutoDetectInvalidation
 {
     JSContext *cx_;
     IonScript *ionScript_;
     Value *rval_;
     bool disabled_;
 
   public:
-    AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript = nullptr)
-      : cx_(cx),
-        ionScript_(ionScript ? ionScript : GetTopIonJSScript(cx)->ionScript()),
-        rval_(rval),
-        disabled_(false)
-    { }
+    AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript = nullptr);
 
     void disable() {
         JS_ASSERT(!disabled_);
         disabled_ = true;
     }
 
     ~AutoDetectInvalidation() {
         if (!disabled_ && ionScript_->invalidated())
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -1490,17 +1490,17 @@ Assembler::as_movw(Register dest, Imm16 
 }
 BufferOffset
 Assembler::as_movt(Register dest, Imm16 imm, Condition c, Instruction *pos)
 {
     JS_ASSERT(hasMOVWT());
     return writeInst(0x03400000 | c | imm.encode() | RD(dest), (uint32_t*)pos);
 }
 
-const int mull_tag = 0x90;
+static const int mull_tag = 0x90;
 
 BufferOffset
 Assembler::as_genmul(Register dhi, Register dlo, Register rm, Register rn,
                      MULOp op, SetCond_ sc, Condition c)
 {
 
     return writeInst(RN(dhi) | maybeRD(dlo) | RM(rm) | rn.code() | op | sc | c | mull_tag);
 }
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -359,30 +359,16 @@ LIRGeneratorARM::newLTableSwitch(const L
 }
 
 LTableSwitchV *
 LIRGeneratorARM::newLTableSwitchV(MTableSwitch *tableswitch)
 {
     return new LTableSwitchV(temp(), tempFloat(), tableswitch);
 }
 
-LGetPropertyCacheT *
-LIRGeneratorARM::newLGetPropertyCacheT(MGetPropertyCache *ins)
-{
-    return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
-}
-
-LGetElementCacheT *
-LIRGeneratorARM::newLGetElementCacheT(MGetElementCache *ins)
-{
-    return new LGetElementCacheT(useRegister(ins->object()),
-                                 useRegister(ins->index()),
-                                 LDefinition::BogusTemp());
-}
-
 bool
 LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
 {
     JS_ASSERT(ins->obj()->type() == MIRType_Object);
 
     LDefinition tempObj = temp(LDefinition::OBJECT);
     LGuardShape *guard = new LGuardShape(useRegister(ins->obj()), tempObj);
     if (!assignSnapshot(guard, ins->bailoutKind()))
--- a/js/src/jit/arm/Lowering-arm.h
+++ b/js/src/jit/arm/Lowering-arm.h
@@ -30,16 +30,22 @@ class LIRGeneratorARM : public LIRGenera
     // stores and loads; on ARM all registers are okay.
     LAllocation useByteOpRegister(MDefinition *mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir);
 
     inline LDefinition tempToUnbox() {
         return LDefinition::BogusTemp();
     }
 
+    // x64 has a scratch register, so no need for another temp for dispatch
+    // ICs.
+    LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) {
+        return LDefinition::BogusTemp();
+    }
+
     void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex);
     bool defineUntypedPhi(MPhi *phi, size_t lirIndex);
     bool lowerForShift(LInstructionHelper<1, 2, 0> *ins, MDefinition *mir, MDefinition *lhs,
                        MDefinition *rhs);
     bool lowerUrshD(MUrsh *mir);
 
     bool lowerForALU(LInstructionHelper<1, 1, 0> *ins, MDefinition *mir,
                      MDefinition *input);
@@ -63,18 +69,16 @@ class LIRGeneratorARM : public LIRGenera
     bool visitPowHalf(MPowHalf *ins);
     bool visitAsmJSNeg(MAsmJSNeg *ins);
     bool visitAsmJSUDiv(MAsmJSUDiv *ins);
     bool visitAsmJSUMod(MAsmJSUMod *ins);
 
     LTableSwitch *newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
                                   MTableSwitch *ins);
     LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
-    LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
-    LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
 
   public:
     bool visitConstant(MConstant *ins);
     bool visitBox(MBox *box);
     bool visitUnbox(MUnbox *unbox);
     bool visitReturn(MReturn *ret);
     bool lowerPhi(MPhi *phi);
     bool visitGuardShape(MGuardShape *ins);
--- a/js/src/jit/arm/Trampoline-arm.cpp
+++ b/js/src/jit/arm/Trampoline-arm.cpp
@@ -418,17 +418,16 @@ IonRuntime::generateArgumentsRectifier(J
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == r8);
 
     // Copy number of actual arguments into r0
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfNumActualArgs())), r0);
 
     // Load the number of |undefined|s to push into r6.
     masm.ma_ldr(DTRAddr(sp, DtrOffImm(IonRectifierFrameLayout::offsetOfCalleeToken())), r1);
-    masm.clearCalleeTag(r1, mode);
     masm.ma_ldrh(EDtrAddr(r1, EDtrOffImm(offsetof(JSFunction, nargs))), r6);
 
     masm.ma_sub(r6, r8, r2);
 
     masm.moveValue(UndefinedValue(), r5, r4);
 
     masm.ma_mov(sp, r3); // Save %sp.
     masm.ma_mov(sp, r7); // Save %sp again.
@@ -463,17 +462,17 @@ IonRuntime::generateArgumentsRectifier(J
     masm.ma_add(r6, Imm32(1), r6);
     masm.ma_lsl(Imm32(3), r6, r6);
 
     // Construct sizeDescriptor.
     masm.makeFrameDescriptor(r6, IonFrame_Rectifier);
 
     // Construct IonJSFrameLayout.
     masm.ma_push(r0); // actual arguments.
-    masm.pushCalleeToken(r1, mode);
+    masm.ma_push(r1); // callee token
     masm.ma_push(r6); // frame descriptor.
 
     // Call the target function.
     // Note that this code assumes the function is JITted.
     masm.ma_ldr(DTRAddr(r1, DtrOffImm(JSFunction::offsetOfNativeOrScript())), r3);
     masm.loadBaselineOrIonRaw(r3, r3, mode, nullptr);
     masm.ma_callIonHalfPush(r3);
 
@@ -767,19 +766,16 @@ IonRuntime::generateVMWrapper(JSContext 
 
     // Test for failure.
     switch (f.failType()) {
       case Type_Object:
       case Type_Bool:
         // Called functions return bools, which are 0/false and non-zero/true
         masm.branch32(Assembler::Equal, r0, Imm32(0), masm.failureLabel(f.executionMode));
         break;
-      case Type_ParallelResult:
-        masm.branch32(Assembler::NotEqual, r0, Imm32(TP_SUCCESS), masm.failureLabel(f.executionMode));
-        break;
       default:
         MOZ_ASSUME_UNREACHABLE("unknown failure kind");
     }
 
     // Load the outparam and free any allocated stack.
     switch (f.outParam) {
       case Type_Handle:
         masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -337,16 +337,22 @@ LIRGeneratorShared::useKeepaliveOrConsta
 
 LUse
 LIRGeneratorShared::useFixed(MDefinition *mir, Register reg)
 {
     return use(mir, LUse(reg));
 }
 
 LUse
+LIRGeneratorShared::useFixedAtStart(MDefinition *mir, Register reg)
+{
+    return use(mir, LUse(reg, true));
+}
+
+LUse
 LIRGeneratorShared::useFixed(MDefinition *mir, FloatRegister reg)
 {
     return use(mir, LUse(reg));
 }
 
 LUse
 LIRGeneratorShared::useFixed(MDefinition *mir, AnyRegister reg)
 {
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -67,16 +67,17 @@ class LIRGeneratorShared : public MInstr
     inline LUse use(MDefinition *mir, LUse policy);
     inline LUse use(MDefinition *mir);
     inline LUse useAtStart(MDefinition *mir);
     inline LUse useRegister(MDefinition *mir);
     inline LUse useRegisterAtStart(MDefinition *mir);
     inline LUse useFixed(MDefinition *mir, Register reg);
     inline LUse useFixed(MDefinition *mir, FloatRegister reg);
     inline LUse useFixed(MDefinition *mir, AnyRegister reg);
+    inline LUse useFixedAtStart(MDefinition *mir, Register reg);
     inline LAllocation useOrConstant(MDefinition *mir);
     // "Any" is architecture dependent, and will include registers and stack slots on X86,
     // and only registers on ARM.
     inline LAllocation useAny(MDefinition *mir);
     inline LAllocation useAnyOrConstant(MDefinition *mir);
     // "Storable" is architecture dependend, and will include registers and constants on X86
     // and only registers on ARM.
     // this is a generic "things we can expect to write into memory in 1 instruction"
--- a/js/src/jit/shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/shared/Lowering-x86-shared.cpp
@@ -219,19 +219,19 @@ bool
 LIRGeneratorX86Shared::visitAsmJSUDiv(MAsmJSUDiv *div)
 {
     return lowerUDiv(div);
 }
 
 bool
 LIRGeneratorX86Shared::lowerUMod(MInstruction *mod)
 {
-    LUDivOrMod *lir = new LUDivOrMod(useFixed(mod->getOperand(0), eax),
+    LUDivOrMod *lir = new LUDivOrMod(useFixedAtStart(mod->getOperand(0), eax),
                                      useRegister(mod->getOperand(1)),
-                                     LDefinition::BogusTemp());
+                                     tempFixed(eax));
     return defineFixed(lir, mod, LAllocation(AnyRegister(edx)));
 }
 
 bool
 LIRGeneratorX86Shared::visitAsmJSUMod(MAsmJSUMod *mod)
 {
     return lowerUMod(mod);
 }
--- a/js/src/jit/x64/Lowering-x64.cpp
+++ b/js/src/jit/x64/Lowering-x64.cpp
@@ -162,27 +162,13 @@ LIRGeneratorX64::visitAsmJSStoreHeap(MAs
 }
 
 bool
 LIRGeneratorX64::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
 {
     return define(new LAsmJSLoadFuncPtr(useRegister(ins->index()), temp()), ins);
 }
 
-LGetPropertyCacheT *
-LIRGeneratorX64::newLGetPropertyCacheT(MGetPropertyCache *ins)
-{
-    return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
-}
-
-LGetElementCacheT *
-LIRGeneratorX64::newLGetElementCacheT(MGetElementCache *ins)
-{
-    return new LGetElementCacheT(useRegister(ins->object()),
-                                 useRegister(ins->index()),
-                                 LDefinition::BogusTemp());
-}
-
 bool
 LIRGeneratorX64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
 {
     MOZ_ASSUME_UNREACHABLE("NYI");
 }
--- a/js/src/jit/x64/Lowering-x64.h
+++ b/js/src/jit/x64/Lowering-x64.h
@@ -30,18 +30,21 @@ class LIRGeneratorX64 : public LIRGenera
 
     // x86 has constraints on what registers can be formatted for 1-byte
     // stores and loads; on x64 all registers are okay.
     LAllocation useByteOpRegister(MDefinition *mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir);
 
     LDefinition tempToUnbox();
 
-    LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
-    LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
+    // x64 has a scratch register, so no need for another temp for dispatch
+    // ICs.
+    LDefinition tempForDispatchCache(MIRType outputType = MIRType_None) {
+        return LDefinition::BogusTemp();
+    }
 
   public:
     bool visitBox(MBox *box);
     bool visitUnbox(MUnbox *unbox);
     bool visitReturn(MReturn *ret);
     bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
     bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
     bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -1035,41 +1035,40 @@ class MacroAssemblerX64 : public MacroAs
     void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest) {
         convertInt32ToFloat32(operand.valueReg(), dest);
     }
 
     void loadConstantDouble(double d, const FloatRegister &dest);
     void loadConstantFloat32(float f, const FloatRegister &dest);
 
     void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) {
-        const uint64_t IndefiniteIntegerValue = 0x8000000000000000;
-        JS_ASSERT(dest != ScratchReg);
         cvttsd2sq(src, dest);
-        movq(ImmWord(IndefiniteIntegerValue), ScratchReg);
-        cmpq(dest, ScratchReg);
-        j(Assembler::Equal, fail);
+
+        // cvttsd2sq returns 0x8000000000000000 on failure. Test for it by
+        // subtracting 1 and testing overflow (this avoids the need to
+        // materialize that value in a register).
+        cmpq(dest, Imm32(1));
+        j(Assembler::Overflow, fail);
+
         movl(dest, dest); // Zero upper 32-bits.
     }
 
     Condition testInt32Truthy(bool truthy, const ValueOperand &operand) {
         testl(operand.valueReg(), operand.valueReg());
         return truthy ? NonZero : Zero;
     }
     void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
         testl(operand.valueReg(), operand.valueReg());
         j(truthy ? NonZero : Zero, label);
     }
-    // This returns the tag in ScratchReg.
     Condition testStringTruthy(bool truthy, const ValueOperand &value) {
         unboxString(value, ScratchReg);
 
         Operand lengthAndFlags(ScratchReg, JSString::offsetOfLengthAndFlags());
-        movq(lengthAndFlags, ScratchReg);
-        shrq(Imm32(JSString::LENGTH_SHIFT), ScratchReg);
-        testq(ScratchReg, ScratchReg);
+        testq(lengthAndFlags, Imm32(-1 << JSString::LENGTH_SHIFT));
         return truthy ? Assembler::NonZero : Assembler::Zero;
     }
 
 
     void loadInt32OrDouble(const Operand &operand, const FloatRegister &dest) {
         Label notInt32, end;
         branchTestInt32(Assembler::NotEqual, operand, &notInt32);
         convertInt32ToDouble(operand, dest);
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -358,17 +358,16 @@ IonRuntime::generateArgumentsRectifier(J
     MacroAssembler masm(cx);
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == r8);
 
     // Load the number of |undefined|s to push into %rcx.
     masm.loadPtr(Address(rsp, IonRectifierFrameLayout::offsetOfCalleeToken()), rax);
-    masm.clearCalleeTag(rax, mode);
     masm.movzwl(Operand(rax, offsetof(JSFunction, nargs)), rcx);
     masm.subq(r8, rcx);
 
     // Copy the number of actual arguments
     masm.loadPtr(Address(rsp, IonRectifierFrameLayout::offsetOfNumActualArgs()), rdx);
 
     masm.moveValue(UndefinedValue(), r10);
 
@@ -401,17 +400,17 @@ IonRuntime::generateArgumentsRectifier(J
     }
 
     // Construct descriptor.
     masm.subq(rsp, r9);
     masm.makeFrameDescriptor(r9, IonFrame_Rectifier);
 
     // Construct IonJSFrameLayout.
     masm.push(rdx); // numActualArgs
-    masm.pushCalleeToken(rax, mode);
+    masm.push(rax); // callee token
     masm.push(r9); // descriptor
 
     // Call the target function.
     // Note that this code assumes the function is JITted.
     masm.loadPtr(Address(rax, JSFunction::offsetOfNativeOrScript()), rax);
     masm.loadBaselineOrIonRaw(rax, rax, mode, nullptr);
     masm.call(rax);
     uint32_t returnOffset = masm.currentOffset();
@@ -621,20 +620,16 @@ IonRuntime::generateVMWrapper(JSContext 
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, rax, rax, masm.failureLabel(f.executionMode));
         break;
       case Type_Bool:
         masm.testb(rax, rax);
         masm.j(Assembler::Zero, masm.failureLabel(f.executionMode));
         break;
-      case Type_ParallelResult:
-        masm.branchPtr(Assembler::NotEqual, rax, Imm32(TP_SUCCESS),
-                       masm.failureLabel(f.executionMode));
-        break;
       default:
         MOZ_ASSUME_UNREACHABLE("unknown failure kind");
     }
 
     // Load the outparam and free any allocated stack.
     switch (f.outParam) {
       case Type_Handle:
         masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -742,16 +742,39 @@ GetElementParIC::initializeAddCacheState
     // one, it's BogusTemp otherwise.
     JS_ASSERT(ins->isGetElementCacheV() || ins->isGetElementCacheT());
     if (ins->isGetElementCacheV() || ins->toGetElementCacheT()->temp()->isBogusTemp())
         addState->dispatchScratch = output_.scratchReg().gpr();
     else
         addState->dispatchScratch = ToRegister(ins->toGetElementCacheT()->temp());
 }
 
+void
+SetPropertyParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
+{
+    // We don't have an output register to reuse, so we always need a temp.
+    JS_ASSERT(ins->isSetPropertyCacheV() || ins->isSetPropertyCacheT());
+    if (ins->isSetPropertyCacheV())
+        addState->dispatchScratch = ToRegister(ins->toSetPropertyCacheV()->tempForDispatchCache());
+    else
+        addState->dispatchScratch = ToRegister(ins->toSetPropertyCacheT()->tempForDispatchCache());
+}
+
+void
+SetElementParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
+{
+    // We don't have an output register to reuse, but luckily SetElementCache
+    // already needs a temp.
+    JS_ASSERT(ins->isSetElementCacheV() || ins->isSetElementCacheT());
+    if (ins->isSetElementCacheV())
+        addState->dispatchScratch = ToRegister(ins->toSetElementCacheV()->temp());
+    else
+        addState->dispatchScratch = ToRegister(ins->toSetElementCacheT()->temp());
+}
+
 namespace js {
 namespace jit {
 
 class OutOfLineTruncate : public OutOfLineCodeBase<CodeGeneratorX86>
 {
     LTruncateDToInt32 *ins_;
 
   public:
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -9,16 +9,39 @@
 #include "jit/MIR.h"
 #include "jit/x86/Assembler-x86.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+LDefinition
+LIRGeneratorX86::tempForDispatchCache(MIRType outputType)
+{
+    // x86 doesn't have a scratch register and we need one for the
+    // indirect jump for dispatch-style ICs.
+    //
+    // Note that currently we only install dispatch-style ICs for parallel
+    // execution. If this assumption changes, please change it here.
+    if (gen->info().executionMode() != ParallelExecution)
+        return LDefinition::BogusTemp();
+
+    // If we don't have an output register, we need a temp.
+    if (outputType == MIRType_None)
+        return temp();
+
+    // If we have a double output register, we need a temp.
+    if (outputType == MIRType_Double)
+        return temp();
+
+    // Otherwise we have a non-double output register and we can reuse it.
+    return LDefinition::BogusTemp();
+}
+
 bool
 LIRGeneratorX86::useBox(LInstruction *lir, size_t n, MDefinition *mir,
                         LUse::Policy policy, bool useAtStart)
 {
     JS_ASSERT(mir->type() == MIRType_Value);
 
     if (!ensureDefined(mir))
         return false;
@@ -270,35 +293,8 @@ LIRGeneratorX86::visitStoreTypedArrayEle
     return add(lir, ins);
 }
 
 bool
 LIRGeneratorX86::visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins)
 {
     return define(new LAsmJSLoadFuncPtr(useRegisterAtStart(ins->index())), ins);
 }
-
-LGetPropertyCacheT *
-LIRGeneratorX86::newLGetPropertyCacheT(MGetPropertyCache *ins)
-{
-    // Since x86 doesn't have a scratch register and we need one for the
-    // indirect jump for dispatch-style ICs, we need a temporary in the case
-    // of a double output type as we can't get a scratch from the output.
-    LDefinition scratch;
-    if (ins->type() == MIRType_Double)
-        scratch = temp();
-    else
-        scratch = LDefinition::BogusTemp();
-    return new LGetPropertyCacheT(useRegister(ins->object()), scratch);
-}
-
-LGetElementCacheT *
-LIRGeneratorX86::newLGetElementCacheT(MGetElementCache *ins)
-{
-    LDefinition scratch;
-    if (ins->type() == MIRType_Double)
-        scratch = temp();
-    else
-        scratch = LDefinition::BogusTemp();
-    return new LGetElementCacheT(useRegister(ins->object()),
-                                 useRegister(ins->index()),
-                                 scratch);
-}
--- a/js/src/jit/x86/Lowering-x86.h
+++ b/js/src/jit/x86/Lowering-x86.h
@@ -33,22 +33,21 @@ class LIRGeneratorX86 : public LIRGenera
     // give us one of {al,bl,cl,dl}. For now, just useFixed(al).
     LAllocation useByteOpRegister(MDefinition *mir);
     LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition *mir);
 
     inline LDefinition tempToUnbox() {
         return LDefinition::BogusTemp();
     }
 
+    LDefinition tempForDispatchCache(MIRType outputType = MIRType_None);
+
     void lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock *block, size_t lirIndex);
     bool defineUntypedPhi(MPhi *phi, size_t lirIndex);
 
-    LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
-    LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
-
   public:
     bool visitBox(MBox *box);
     bool visitUnbox(MUnbox *unbox);
     bool visitReturn(MReturn *ret);
     bool visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
     bool visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
     bool visitAsmJSStoreHeap(MAsmJSStoreHeap *ins);
     bool visitAsmJSLoadFuncPtr(MAsmJSLoadFuncPtr *ins);
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -874,26 +874,32 @@ class MacroAssemblerX86 : public MacroAs
     }
 
     void loadConstantDouble(double d, const FloatRegister &dest);
     void addConstantDouble(double d, const FloatRegister &dest);
     void loadConstantFloat32(float f, const FloatRegister &dest);
     void addConstantFloat32(float f, const FloatRegister &dest);
 
     void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) {
-        const uint32_t IndefiniteIntegerValue = 0x80000000;
         cvttsd2si(src, dest);
-        cmpl(dest, Imm32(IndefiniteIntegerValue));
-        j(Assembler::Equal, fail);
+
+        // cvttsd2si returns 0x80000000 on failure. Test for it by
+        // subtracting 1 and testing overflow (this permits the use of a
+        // smaller immediate field).
+        cmpl(dest, Imm32(1));
+        j(Assembler::Overflow, fail);
     }
     void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail) {
-        const uint32_t IndefiniteIntegerValue = 0x80000000;
         cvttss2si(src, dest);
-        cmpl(dest, Imm32(IndefiniteIntegerValue));
-        j(Assembler::Equal, fail);
+
+        // cvttss2si returns 0x80000000 on failure. Test for it by
+        // subtracting 1 and testing overflow (this permits the use of a
+        // smaller immediate field).
+        cmpl(dest, Imm32(1));
+        j(Assembler::Overflow, fail);
     }
 
     Condition testInt32Truthy(bool truthy, const ValueOperand &operand) {
         testl(operand.payloadReg(), operand.payloadReg());
         return truthy ? NonZero : Zero;
     }
     void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
         testl(operand.payloadReg(), operand.payloadReg());
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -348,17 +348,16 @@ IonRuntime::generateArgumentsRectifier(J
     MacroAssembler masm(cx);
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     JS_ASSERT(ArgumentsRectifierReg == esi);
 
     // Load the number of |undefined|s to push into %ecx.
     masm.loadPtr(Address(esp, IonRectifierFrameLayout::offsetOfCalleeToken()), eax);
-    masm.clearCalleeTag(eax, mode);
     masm.movzwl(Operand(eax, offsetof(JSFunction, nargs)), ecx);
     masm.subl(esi, ecx);
 
     // Copy the number of actual arguments.
     masm.loadPtr(Address(esp, IonRectifierFrameLayout::offsetOfNumActualArgs()), edx);
 
     masm.moveValue(UndefinedValue(), ebx, edi);
 
@@ -401,17 +400,17 @@ IonRuntime::generateArgumentsRectifier(J
 
     // Construct descriptor, accounting for pushed frame pointer above
     masm.lea(Operand(FramePointer, sizeof(void*)), ebx);
     masm.subl(esp, ebx);
     masm.makeFrameDescriptor(ebx, IonFrame_Rectifier);
 
     // Construct IonJSFrameLayout.
     masm.push(edx); // number of actual arguments
-    masm.pushCalleeToken(eax, mode);
+    masm.push(eax); // callee token
     masm.push(ebx); // descriptor
 
     // Call the target function.
     // Note that this assumes the function is JITted.
     masm.loadPtr(Address(eax, JSFunction::offsetOfNativeOrScript()), eax);
     masm.loadBaselineOrIonRaw(eax, eax, mode, nullptr);
     masm.call(eax);
     uint32_t returnOffset = masm.currentOffset();
@@ -655,20 +654,16 @@ IonRuntime::generateVMWrapper(JSContext 
     switch (f.failType()) {
       case Type_Object:
         masm.branchTestPtr(Assembler::Zero, eax, eax, masm.failureLabel(f.executionMode));
         break;
       case Type_Bool:
         masm.testb(eax, eax);
         masm.j(Assembler::Zero, masm.failureLabel(f.executionMode));
         break;
-      case Type_ParallelResult:
-        masm.branchPtr(Assembler::NotEqual, eax, Imm32(TP_SUCCESS),
-                       masm.failureLabel(f.executionMode));
-        break;
       default:
         MOZ_ASSUME_UNREACHABLE("unknown failure kind");
     }
 
     // Load the outparam and free any allocated stack.
     switch (f.outParam) {
       case Type_Handle:
         masm.popRooted(f.outParamRootType, ReturnReg, JSReturnOperand);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3762,17 +3762,17 @@ JS_Enumerate(JSContext *cx, JSObject *ob
 
 /*
  * XXX reverse iterator for properties, unreverse and meld with jsinterp.c's
  *     prop_iterator_class somehow...
  * + preserve the obj->enumerate API while optimizing the native object case
  * + native case here uses a JSShape *, but that iterates in reverse!
  * + so we make non-native match, by reverse-iterating after JS_Enumerating
  */
-const uint32_t JSSLOT_ITER_INDEX = 0;
+static const uint32_t JSSLOT_ITER_INDEX = 0;
 
 static void
 prop_iter_finalize(FreeOp *fop, JSObject *obj)
 {
     void *pdata = obj->getPrivate();
     if (!pdata)
         return;
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -128,17 +128,17 @@ js::StringIsArrayIndex(JSLinearString *s
         JS_ASSERT(index <= MAX_ARRAY_INDEX);
         *indexp = index;
         return true;
     }
 
     return false;
 }
 
-bool
+static bool
 DoubleIndexToId(JSContext *cx, double index, MutableHandleId id)
 {
     if (index == uint32_t(index))
         return IndexToId(cx, uint32_t(index), id);
 
     Value tmp = DoubleValue(index);
     return ValueToId<CanGC>(cx, HandleValue::fromMarkedLocation(&tmp), id);
 }
@@ -754,27 +754,30 @@ js::WouldDefinePastNonwritableLength(Thr
 
     if (arr->lengthIsWritable()) {
         *definesPast = false;
         return true;
     }
 
     *definesPast = true;
 
+    // Error in strict mode code or warn with strict option.
+    unsigned flags = strict ? JSREPORT_ERROR : (JSREPORT_STRICT | JSREPORT_WARNING);
+    if (cx->isForkJoinSlice())
+        return cx->asForkJoinSlice()->reportError(ParallelBailoutUnsupportedVM, flags);
+
     if (!cx->isJSContext())
         return true;
 
     JSContext *ncx = cx->asJSContext();
 
     if (!strict && !ncx->hasExtraWarningsOption())
         return true;
 
-    // Error in strict mode code or warn with strict option.
     // XXX include the index and maybe array length in the error message
-    unsigned flags = strict ? JSREPORT_ERROR : (JSREPORT_STRICT | JSREPORT_WARNING);
     return JS_ReportErrorFlagsAndNumber(ncx, flags, js_GetErrorMessage, nullptr,
                                         JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH);
 }
 
 static bool
 array_addProperty(JSContext *cx, HandleObject obj, HandleId id,
                   MutableHandleValue vp)
 {
@@ -1432,17 +1435,17 @@ NumDigitsBase10(uint32_t n)
      * Algorithm taken from
      * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
      */
     uint32_t log2 = CeilingLog2(n);
     uint32_t t = log2 * 1233 >> 12;
     return t - (n < powersOf10[t]) + 1;
 }
 
-inline bool
+static inline bool
 CompareLexicographicInt32(JSContext *cx, const Value &a, const Value &b, bool *lessOrEqualp)
 {
     int32_t aint = a.toInt32();
     int32_t bint = b.toInt32();
 
     /*
      * If both numbers are equal ... trivial
      * If only one of both is negative --> arithmetic comparison as char code
@@ -1477,17 +1480,17 @@ CompareLexicographicInt32(JSContext *cx,
             JS_ASSERT((digitsb - digitsa) < ArrayLength(powersOf10));
             *lessOrEqualp = (uint64_t(auint) * powersOf10[digitsb - digitsa] <= uint64_t(buint));
         }
     }
 
     return true;
 }
 
-inline bool
+static inline bool
 CompareSubStringValues(JSContext *cx, const jschar *s1, size_t l1,
                        const jschar *s2, size_t l2, bool *lessOrEqualp)
 {
     if (!JS_CHECK_OPERATION_LIMIT(cx))
         return false;
 
     int32_t result;
     if (!s1 || !s2 || !CompareChars(s1, l1, s2, l2, &result))
@@ -1704,17 +1707,17 @@ MatchNumericComparator(JSContext *cx, co
 
     if (arg0 == 1 && arg1 == 0)
         return Match_RightMinusLeft;
 
     return Match_None;
 }
 
 template<typename K, typename C>
-inline bool
+static inline bool
 MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector *vec)
 {
     MOZ_ASSERT(vec->length() >= len);
 
     /* Sort keys. */
     if (!MergeSort(keys, len, scratch, comparator))
         return false;
 
@@ -1997,17 +2000,17 @@ js::array_sort(JSContext *cx, unsigned a
     while (len > n) {
         if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeletePropertyOrThrow(cx, obj, --len))
             return false;
     }
     args.rval().setObject(*obj);
     return true;
 }
 
-JS_ALWAYS_INLINE bool
+static JS_ALWAYS_INLINE bool
 NewbornArrayPushImpl(JSContext *cx, HandleObject obj, const Value &v)
 {
     Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
 
     JS_ASSERT(!v.isMagic());
     JS_ASSERT(arr->lengthIsWritable());
 
     uint32_t length = arr->length();
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -58,17 +58,17 @@ bool_toSource_impl(JSContext *cx, CallAr
 
     JSString *str = sb.finishString();
     if (!str)
         return false;
     args.rval().setString(str);
     return true;
 }
 
-bool
+static bool
 bool_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsBoolean, bool_toSource_impl>(cx, args);
 }
 #endif
 
 JS_ALWAYS_INLINE bool
@@ -77,17 +77,17 @@ bool_toString_impl(JSContext *cx, CallAr
     HandleValue thisv = args.thisv();
     JS_ASSERT(IsBoolean(thisv));
 
     bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox();
     args.rval().setString(js_BooleanToString(cx, b));
     return true;
 }
 
-bool
+static bool
 bool_toString(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsBoolean, bool_toString_impl>(cx, args);
 }
 
 JS_ALWAYS_INLINE bool
 bool_valueOf_impl(JSContext *cx, CallArgs args)
@@ -95,17 +95,17 @@ bool_valueOf_impl(JSContext *cx, CallArg
     HandleValue thisv = args.thisv();
     JS_ASSERT(IsBoolean(thisv));
 
     bool b = thisv.isBoolean() ? thisv.toBoolean() : thisv.toObject().as<BooleanObject>().unbox();
     args.rval().setBoolean(b);
     return true;
 }
 
-bool
+static bool
 bool_valueOf(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsBoolean, bool_valueOf_impl>(cx, args);
 }
 
 static const JSFunctionSpec boolean_methods[] = {
 #if JS_HAS_TOSOURCE
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -344,16 +344,21 @@ PopulateReportBlame(JSContext *cx, JSErr
  * error reporter directly.
  *
  * Furthermore, callers of js_ReportOutOfMemory (viz., malloc) assume a GC does
  * not occur, so GC must be avoided or suppressed.
  */
 void
 js_ReportOutOfMemory(ThreadSafeContext *cxArg)
 {
+    if (cxArg->isForkJoinSlice()) {
+        cxArg->asForkJoinSlice()->setPendingAbortFatal(ParallelBailoutOutOfMemory);
+        return;
+    }
+
     if (!cxArg->isJSContext())
         return;
     JSContext *cx = cxArg->asJSContext();
 
     cx->runtime()->hadOutOfMemory = true;
 
     if (JS_IsRunning(cx)) {
         cx->setPendingException(StringValue(cx->names().outOfMemory));
@@ -413,17 +418,25 @@ void
 js_ReportOverRecursed(ThreadSafeContext *cx)
 {
     js_ReportOverRecursed(cx->maybeJSContext());
 }
 
 void
 js_ReportAllocationOverflow(ThreadSafeContext *cxArg)
 {
-    if (!cxArg || !cxArg->isJSContext())
+    if (!cxArg)
+        return;
+
+    if (cxArg->isForkJoinSlice()) {
+        cxArg->asForkJoinSlice()->setPendingAbortFatal(ParallelBailoutOutOfMemory);
+        return;
+    }
+
+    if (!cxArg->isJSContext())
         return;
     JSContext *cx = cxArg->asJSContext();
 
     AutoSuppressGC suppressGC(cx);
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_ALLOC_OVERFLOW);
 }
 
 /*
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -552,20 +552,20 @@ JSContext::currentScript(jsbytecode **pp
 template <JSThreadSafeNative threadSafeNative>
 inline bool
 JSNativeThreadSafeWrapper(JSContext *cx, unsigned argc, JS::Value *vp)
 {
     return threadSafeNative(cx, argc, vp);
 }
 
 template <JSThreadSafeNative threadSafeNative>
-inline js::ParallelResult
+inline bool
 JSParallelNativeThreadSafeWrapper(js::ForkJoinSlice *slice, unsigned argc, JS::Value *vp)
 {
-    return threadSafeNative(slice, argc, vp) ? js::TP_SUCCESS : js::TP_FATAL;
+    return threadSafeNative(slice, argc, vp);
 }
 
 /* static */ inline JSContext *
 js::ExecutionModeTraits<js::SequentialExecution>::toContextType(ExclusiveContext *cx)
 {
     return cx->asJSContext();
 }
 
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -95,57 +95,57 @@ using JS::GenericNaN;
  *
  *     setDay
  *     before
  *     after
  *     equals
  *     hashCode
  */
 
-inline double
+static inline double
 Day(double t)
 {
     return floor(t / msPerDay);
 }
 
 static double
 TimeWithinDay(double t)
 {
     double result = fmod(t, msPerDay);
     if (result < 0)
         result += msPerDay;
     return result;
 }
 
 /* ES5 15.9.1.3. */
-inline bool
+static inline bool
 IsLeapYear(double year)
 {
     JS_ASSERT(ToInteger(year) == year);
     return fmod(year, 4) == 0 && (fmod(year, 100) != 0 || fmod(year, 400) == 0);
 }
 
-inline double
+static inline double
 DaysInYear(double year)
 {
     if (!IsFinite(year))
         return GenericNaN();
     return IsLeapYear(year) ? 366 : 365;
 }
 
-inline double
+static inline double
 DayFromYear(double y)
 {
     return 365 * (y - 1970) +
            floor((y - 1969) / 4.0) -
            floor((y - 1901) / 100.0) +
            floor((y - 1601) / 400.0);
 }
 
-inline double
+static inline double
 TimeFromYear(double y)
 {
     return DayFromYear(y) * msPerDay;
 }
 
 static double
 YearFromTime(double t)
 {
@@ -166,24 +166,24 @@ YearFromTime(double t)
         y--;
     } else {
         if (t2 + msPerDay * DaysInYear(y) <= t)
             y++;
     }
     return y;
 }
 
-inline int
+static inline int
 DaysInFebruary(double year)
 {
     return IsLeapYear(year) ? 29 : 28;
 }
 
 /* ES5 15.9.1.4. */
-inline double
+static inline double
 DayWithinYear(double t, double year)
 {
     JS_ASSERT_IF(IsFinite(t), YearFromTime(t) == year);
     return Day(t) - DayFromYear(year);
 }
 
 static double
 MonthFromTime(double t)
@@ -277,34 +277,34 @@ WeekDay(double t)
      */
     JS_ASSERT(ToInteger(t) == t);
     int result = (int(Day(t)) + 4) % 7;
     if (result < 0)
         result += 7;
     return result;
 }
 
-inline int
+static inline int
 DayFromMonth(int month, bool isLeapYear)
 {
     /*
      * The following array contains the day of year for the first day of
      * each month, where index 0 is January, and day 0 is January 1.
      */
     static const int firstDayOfMonth[2][13] = {
         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
         {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
     };
 
     JS_ASSERT(0 <= month && month <= 12);
     return firstDayOfMonth[isLeapYear][month];
 }
 
 template<typename T>
-inline int
+static inline int
 DayFromMonth(T month, bool isLeapYear) MOZ_DELETE;
 
 /* ES5 15.9.1.12 (out of order to accommodate DaylightSavingTA). */
 static double
 MakeDay(double year, double month, double date)
 {
     /* Step 1. */
     if (!IsFinite(year) || !IsFinite(month) || !IsFinite(date))
@@ -328,17 +328,17 @@ MakeDay(double year, double month, doubl
 
     double yearday = floor(TimeFromYear(ym) / msPerDay);
     double monthday = DayFromMonth(mn, leap);
 
     return yearday + monthday + dt - 1;
 }
 
 /* ES5 15.9.1.13 (out of order to accommodate DaylightSavingTA). */
-inline double
+static inline double
 MakeDate(double day, double time)
 {
     /* Step 1. */
     if (!IsFinite(day) || !IsFinite(time))
         return GenericNaN();
 
     /* Step 2. */
     return day * msPerDay + time;
--- a/js/src/jsdtoa.cpp
+++ b/js/src/jsdtoa.cpp
@@ -39,18 +39,18 @@ using namespace js;
 #define ULlong uint64_t
 #endif
 */
 
 /*
  * MALLOC gets declared external, and that doesn't work for class members, so
  * wrap.
  */
-inline void* dtoa_malloc(size_t size) { return js_malloc(size); }
-inline void dtoa_free(void* p) { return js_free(p); }
+static inline void* dtoa_malloc(size_t size) { return js_malloc(size); }
+static inline void dtoa_free(void* p) { return js_free(p); }
 
 #define NO_GLOBAL_STATE
 #define NO_ERRNO
 #define MALLOC dtoa_malloc
 #define FREE dtoa_free
 #include "dtoa.c"
 
 /* Mapping of JSDToStrMode -> js_dtoa mode */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -623,26 +623,32 @@ class TypeCompilerConstraint : public Ty
             cx->compartment()->types.addPendingRecompile(cx, compilation);
     }
 
     void newPropertyState(JSContext *cx, TypeSet *source) {
         if (data.invalidateOnNewPropertyState(source))
             cx->compartment()->types.addPendingRecompile(cx, compilation);
     }
 
-    void newObjectState(JSContext *cx, TypeObject *object, bool force) {
-        if (data.invalidateOnNewObjectState(object, force))
+    void newObjectState(JSContext *cx, TypeObject *object) {
+        // Note: Once the object has unknown properties, no more notifications
+        // will be sent on changes to its state, so always invalidate any
+        // associated compilations.
+        if (object->unknownProperties() || data.invalidateOnNewObjectState(object))
             cx->compartment()->types.addPendingRecompile(cx, compilation);
     }
 };
 
 template <typename T>
 bool
 CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileInfo recompileInfo)
 {
+    if (property.actualObject->unknownProperties())
+        return false;
+
     if (!data.constraintHolds(cx, property, expected))
         return false;
 
     property.actualTypes->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
                               /* callExisting = */ false);
     return true;
 }
 
@@ -695,16 +701,17 @@ HeapTypeSetKey
 TypeObjectKey::property(jsid id)
 {
 #ifdef JS_ION
     JSContext *cx = jit::GetIonContext()->cx;
     TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
     if (!type)
         MOZ_CRASH();
     HeapTypeSetKey property;
+    property.actualObject = type;
     property.actualTypes = type->getProperty(cx, id);
     if (!property.actualTypes)
         MOZ_CRASH();
     return property;
 #else
     MOZ_CRASH();
 #endif
 }
@@ -749,17 +756,17 @@ class ConstraintDataFreeze
 {
   public:
     ConstraintDataFreeze() {}
 
     const char *kind() { return "freeze"; }
 
     bool invalidateOnNewType(Type type) { return true; }
     bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
-    bool invalidateOnNewObjectState(TypeObject *object, bool force) { return false; }
+    bool invalidateOnNewObjectState(TypeObject *object) { return false; }
 
     bool constraintHolds(JSContext *cx,
                          const HeapTypeSetKey &property, TemporaryTypeSet *expected)
     {
         return property.actualTypes->isSubset(expected);
     }
 };
 
@@ -914,43 +921,37 @@ HeapTypeSetKey::needsBarrier(CompilerCon
 }
 
 namespace {
 
 // Constraint which triggers recompilation if an object acquires particular flags.
 class ConstraintDataFreezeObjectFlags
 {
   public:
-    // Object being queried.
-    TypeObjectKey *object;
-
     // Flags we are watching for on this object.
     TypeObjectFlags flags;
 
-    ConstraintDataFreezeObjectFlags(TypeObjectKey *object, TypeObjectFlags flags)
-      : object(object), flags(flags)
-    {}
+    ConstraintDataFreezeObjectFlags(TypeObjectFlags flags)
+      : flags(flags)
+    {
+        JS_ASSERT(flags);
+    }
 
     const char *kind() { return "freezeObjectFlags"; }
 
     bool invalidateOnNewType(Type type) { return false; }
     bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
-    bool invalidateOnNewObjectState(TypeObject *object, bool force) {
-        return flags ? object->hasAnyFlags(flags) : force;
+    bool invalidateOnNewObjectState(TypeObject *object) {
+        return object->hasAnyFlags(flags);
     }
 
     bool constraintHolds(JSContext *cx,
                          const HeapTypeSetKey &property, TemporaryTypeSet *expected)
     {
-        // FIXME: There is not yet any way to test if constraints with no
-        // associated flags (i.e. those invalidated via |force|) still hold.
-        TypeObject *type = object->isSingleObject()
-                           ? object->asSingleObject()->type()
-                           : object->asTypeObject();
-        return !type->hasAnyFlags(flags);
+        return !invalidateOnNewObjectState(property.actualObject);
     }
 };
 
 } /* anonymous namespace */
 
 bool
 TypeObjectKey::hasFlags(CompilerConstraintList *constraints, TypeObjectFlags flags)
 {
@@ -960,30 +961,23 @@ TypeObjectKey::hasFlags(CompilerConstrai
     JSContext *cx = jit::GetIonContext()->cx;
     TypeObject *type = isSingleObject() ? asSingleObject()->getType(cx) : asTypeObject();
     if (!type)
         MOZ_CRASH();
     if (type->hasAnyFlags(flags))
         return true;
 
     HeapTypeSetKey objectProperty = property(JSID_EMPTY);
-    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(this, flags)));
+    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(flags)));
     return false;
 #else
     MOZ_CRASH();
 #endif
 }
 
-void
-TypeObjectKey::watchStateChange(CompilerConstraintList *constraints)
-{
-    HeapTypeSetKey objectProperty = property(JSID_EMPTY);
-    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectFlags> >(objectProperty, ConstraintDataFreezeObjectFlags(this, 0)));
-}
-
 bool
 TemporaryTypeSet::hasObjectFlags(CompilerConstraintList *constraints, TypeObjectFlags flags)
 {
     if (unknownObject())
         return true;
 
     /*
      * Treat type sets containing no objects as having all object flags,
@@ -997,34 +991,140 @@ TemporaryTypeSet::hasObjectFlags(Compile
         TypeObjectKey *object = getObject(i);
         if (object && object->hasFlags(constraints, flags))
             return true;
     }
 
     return false;
 }
 
-static inline void
-ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnknown, bool force)
+namespace {
+
+// Constraint which triggers recompilation on any type change in an inlined
+// script. The freeze constraints added to stack type sets will only directly
+// invalidate the script containing those stack type sets. To invalidate code
+// for scripts into which the base script was inlined, ObjectStateChange is used.
+class ConstraintDataFreezeObjectForInlinedCall
+{
+  public:
+    ConstraintDataFreezeObjectForInlinedCall()
+    {}
+
+    const char *kind() { return "freezeObjectForInlinedCall"; }
+
+    bool invalidateOnNewType(Type type) { return false; }
+    bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
+    bool invalidateOnNewObjectState(TypeObject *object) {
+        // We don't keep track of the exact dependencies the caller has on its
+        // inlined scripts' type sets, so always invalidate the caller.
+        return true;
+    }
+
+    bool constraintHolds(JSContext *cx,
+                         const HeapTypeSetKey &property, TemporaryTypeSet *expected)
+    {
+        return true;
+    }
+};
+
+// Constraint which triggers recompilation when the allocation kind of the
+// template object for a type's new script changes.
+class ConstraintDataFreezeObjectForNewScriptTemplate
+{
+    gc::AllocKind allocKind;
+
+  public:
+    ConstraintDataFreezeObjectForNewScriptTemplate(gc::AllocKind allocKind)
+      : allocKind(allocKind)
+    {}
+
+    const char *kind() { return "freezeObjectForNewScriptTemplate"; }
+
+    bool invalidateOnNewType(Type type) { return false; }
+    bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
+    bool invalidateOnNewObjectState(TypeObject *object) {
+        return !object->hasNewScript() || object->newScript()->allocKind != allocKind;
+    }
+
+    bool constraintHolds(JSContext *cx,
+                         const HeapTypeSetKey &property, TemporaryTypeSet *expected)
+    {
+        return !invalidateOnNewObjectState(property.actualObject);
+    }
+};
+
+// Constraint which triggers recompilation when the underlying data pointer for
+// a typed array changes.
+class ConstraintDataFreezeObjectForTypedArrayBuffer
+{
+    void *viewData;
+
+  public:
+    ConstraintDataFreezeObjectForTypedArrayBuffer(void *viewData)
+      : viewData(viewData)
+    {}
+
+    const char *kind() { return "freezeObjectForTypedArrayBuffer"; }
+
+    bool invalidateOnNewType(Type type) { return false; }
+    bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
+    bool invalidateOnNewObjectState(TypeObject *object) {
+        return object->singleton->as<TypedArrayObject>().viewData() != viewData;
+    }
+
+    bool constraintHolds(JSContext *cx,
+                         const HeapTypeSetKey &property, TemporaryTypeSet *expected)
+    {
+        return !invalidateOnNewObjectState(property.actualObject);
+    }
+};
+
+} /* anonymous namespace */
+
+void
+TypeObjectKey::watchStateChangeForInlinedCall(CompilerConstraintList *constraints)
+{
+    HeapTypeSetKey objectProperty = property(JSID_EMPTY);
+    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForInlinedCall> >(objectProperty, ConstraintDataFreezeObjectForInlinedCall()));
+}
+
+void
+TypeObjectKey::watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints)
+{
+    gc::AllocKind kind = asTypeObject()->newScript()->allocKind;
+    HeapTypeSetKey objectProperty = property(JSID_EMPTY);
+    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForNewScriptTemplate> >(objectProperty, ConstraintDataFreezeObjectForNewScriptTemplate(kind)));
+}
+
+void
+TypeObjectKey::watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints)
+{
+    void *viewData = asSingleObject()->as<TypedArrayObject>().viewData();
+    HeapTypeSetKey objectProperty = property(JSID_EMPTY);
+    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForTypedArrayBuffer> >(objectProperty, ConstraintDataFreezeObjectForTypedArrayBuffer(viewData)));
+}
+
+static void
+ObjectStateChange(ExclusiveContext *cxArg, TypeObject *object, bool markingUnknown)
 {
     if (object->unknownProperties())
         return;
 
     /* All constraints listening to state changes are on the empty id. */
     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;
             while (constraint) {
-                constraint->newObjectState(cx, object, force);
+                constraint->newObjectState(cx, object);
                 constraint = constraint->next;
             }
         } else {
             JS_ASSERT(!types->constraintList);
         }
     }
 }
 
@@ -1043,17 +1143,17 @@ class ConstraintDataFreezeConfiguredProp
     {}
 
     const char *kind() { return "freezeConfiguredProperty"; }
 
     bool invalidateOnNewType(Type type) { return false; }
     bool invalidateOnNewPropertyState(TypeSet *property) {
         return property->configuredProperty();
     }
-    bool invalidateOnNewObjectState(TypeObject *object, bool force) { return false; }
+    bool invalidateOnNewObjectState(TypeObject *object) { return false; }
 
     bool constraintHolds(JSContext *cx,
                          const HeapTypeSetKey &property, TemporaryTypeSet *expected)
     {
         // Everywhere compiled code depends on definite properties associated
         // with a type object's newScript, we need to make sure there are
         // constraints in place which will mark those properties as configured
         // should the definite properties be invalidated.
@@ -1323,26 +1423,16 @@ TemporaryTypeSet::propertyNeedsBarrier(C
         HeapTypeSetKey property = type->property(id);
         if (property.needsBarrier(constraints))
             return true;
     }
 
     return false;
 }
 
-/*
- * Force recompilation of any jitcode for the script, or of any other script
- * which this script was inlined into.
- */
-static inline void
-AddPendingRecompile(JSContext *cx, JSScript *script)
-{
-    cx->compartment()->types.addPendingRecompile(cx, script);
-}
-
 namespace {
 
 /*
  * As for TypeConstraintFreeze, but describes an implicit freeze constraint
  * added for stack types within a script. Applies to all compilations of the
  * script, not just a single one.
  */
 class TypeConstraintFreezeStack : public TypeConstraint
@@ -1357,17 +1447,17 @@ class TypeConstraintFreezeStack : public
     const char *kind() { return "freezeStack"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type)
     {
         /*
          * Unlike TypeConstraintFreeze, triggering this constraint once does
          * not disable it on future changes to the type set.
          */
-        AddPendingRecompile(cx, script_);
+        cx->compartment()->types.addPendingRecompile(cx, script_);
     }
 };
 
 } /* anonymous namespace */
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
@@ -1825,18 +1915,16 @@ TypeCompartment::addPendingRecompile(JSC
 
     co->setPendingInvalidation();
 }
 
 void
 TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
 {
     JS_ASSERT(script);
-    if (!constrainedOutputs)
-        return;
 
 #ifdef JS_ION
     CancelOffThreadIonCompile(cx->compartment(), script);
 
     // Let the script warm up again before attempting another compile.
     if (jit::IsBaselineEnabled(cx))
         script->resetUseCount();
 
@@ -1846,17 +1934,17 @@ TypeCompartment::addPendingRecompile(JSC
     if (script->hasParallelIonScript())
         addPendingRecompile(cx, script->parallelIonScript()->recompileInfo());
 #endif
 
     // When one script is inlined into another the caller listens to state
     // changes on the callee's script, so trigger these to force recompilation
     // of any such callers.
     if (script->function() && !script->function()->hasLazyType())
-        ObjectStateChange(cx, script->function()->type(), false, true);
+        ObjectStateChange(cx, script->function()->type(), false);
 }
 
 void
 TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
 {