Merge m-c to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 25 Apr 2014 13:37:42 +0200
changeset 198733 ab40a6469c74e8c03011f34d2ec9271b95c449fe
parent 198732 1eab0ad18dff84556266db47b433d5459050dafb (current diff)
parent 198627 09a19b25b9cf0fd8fba893bfa7ebc28aa99fe32a (diff)
child 198734 e91a5803fa7a7a319a67b7ae324c590b23cb7827
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-c to fx-team
content/canvas/public/nsICanvasGLPrivate.idl
dom/interfaces/xpath/nsIDOMXPathNamespace.idl
--- a/accessible/src/base/AccEvent.cpp
+++ b/accessible/src/base/AccEvent.cpp
@@ -7,17 +7,17 @@
 #include "AccEvent.h"
 
 #include "nsAccUtils.h"
 #include "DocAccessible.h"
 #include "xpcAccEvents.h"
 #include "States.h"
 
 #include "mozilla/EventStateManager.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 static_assert(static_cast<bool>(eNoUserInput) == false &&
               static_cast<bool>(eFromUserInput) == true,
               "EIsFromUserInput cannot be casted to bool");
 
@@ -122,17 +122,17 @@ AccShowEvent::
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // AccTextSelChangeEvent
 ////////////////////////////////////////////////////////////////////////////////
 
 AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
-                                             Selection* aSelection,
+                                             dom::Selection* aSelection,
                                              int32_t aReason) :
   AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget,
            eAutoDetect, eCoalesceTextSelChange),
   mSel(aSelection), mReason(aReason) {}
 
 AccTextSelChangeEvent::~AccTextSelChangeEvent() { }
 
 bool
--- a/accessible/src/base/AccEvent.h
+++ b/accessible/src/base/AccEvent.h
@@ -7,17 +7,19 @@
 #define _AccEvent_H_
 
 #include "nsIAccessibleEvent.h"
 
 #include "mozilla/a11y/Accessible.h"
 
 namespace mozilla {
 
+namespace dom {
 class Selection;
+}
 
 namespace a11y {
 
 class DocAccessible;
 
 // Constants used to point whether the event is from user input.
 enum EIsFromUserInput
 {
@@ -362,17 +364,18 @@ private:
 
 
 /**
  * Accessible text selection change event.
  */
 class AccTextSelChangeEvent : public AccEvent
 {
 public:
-  AccTextSelChangeEvent(HyperTextAccessible* aTarget, Selection* aSelection,
+  AccTextSelChangeEvent(HyperTextAccessible* aTarget,
+                        dom::Selection* aSelection,
                         int32_t aReason);
   virtual ~AccTextSelChangeEvent();
 
   // AccEvent
   static const EventGroup kEventGroup = eTextSelChangeEvent;
   virtual unsigned int GetEventGroups() const
   {
     return AccEvent::GetEventGroups() | (1U << eTextSelChangeEvent);
@@ -381,17 +384,17 @@ public:
   // AccTextSelChangeEvent
 
   /**
    * Return true if the text selection change wasn't caused by pure caret move.
    */
   bool IsCaretMoveOnly() const;
 
 private:
-  nsRefPtr<Selection> mSel;
+  nsRefPtr<dom::Selection> mSel;
   int32_t mReason;
 
   friend class EventQueue;
   friend class SelectionManager;
 };
 
 
 /**
--- a/accessible/src/base/SelectionManager.cpp
+++ b/accessible/src/base/SelectionManager.cpp
@@ -9,21 +9,22 @@
 #include "nsAccessibilityService.h"
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "nsEventShell.h"
 
 #include "nsIAccessibleTypes.h"
 #include "nsIDOMDocument.h"
 #include "nsIPresShell.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
+using mozilla::dom::Selection;
 
 struct mozilla::a11y::SelData MOZ_FINAL
 {
   SelData(Selection* aSel, int32_t aReason) :
     mSel(aSel), mReason(aReason) {}
 
   nsRefPtr<Selection> mSel;
   int16_t mReason;
--- a/accessible/src/generic/HyperTextAccessible-inl.h
+++ b/accessible/src/generic/HyperTextAccessible-inl.h
@@ -37,17 +37,17 @@ HyperTextAccessible::IsValidRange(int32_
     return false;
 
   return endOffset <= static_cast<int32_t>(CharacterCount());
 }
 
 inline bool
 HyperTextAccessible::AddToSelection(int32_t aStartOffset, int32_t aEndOffset)
 {
-  Selection* domSel = DOMSelection();
+  dom::Selection* domSel = DOMSelection();
   return domSel &&
     SetSelectionBoundsAt(domSel->GetRangeCount(), aStartOffset, aEndOffset);
 }
 
 inline void
 HyperTextAccessible::ReplaceText(const nsAString& aText)
 {
   int32_t numChars = CharacterCount();
@@ -144,17 +144,17 @@ HyperTextAccessible::IsCaretAtEndOfLine(
 
 inline already_AddRefed<nsFrameSelection>
 HyperTextAccessible::FrameSelection() const
 {
   nsIFrame* frame = GetFrame();
   return frame ? frame->GetFrameSelection() : nullptr;
 }
 
-inline Selection*
+inline dom::Selection*
 HyperTextAccessible::DOMSelection() const
 {
   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
   return frameSelection ?
     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL) :
     nullptr;
 }
 
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -28,17 +28,17 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIPersistentProperties2.h"
 #include "nsIScrollableFrame.h"
 #include "nsIServiceManager.h"
 #include "nsITextControlElement.h"
 #include "nsTextFragment.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/EventStates.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/MathAlgorithms.h"
 #include "gfxSkipChars.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1112,17 +1112,17 @@ HyperTextAccessible::SetSelectionRange(i
 
   // If accessible is focusable then focus it before setting the selection to
   // neglect control's selection changes on focus if any (for example, inputs
   // that do select all on focus).
   // some input controls
   if (isFocusable)
     TakeFocus();
 
-  Selection* domSel = DOMSelection();
+  dom::Selection* domSel = DOMSelection();
   NS_ENSURE_STATE(domSel);
 
   // Set up the selection.
   for (int32_t idx = domSel->GetRangeCount() - 1; idx > 0; idx--)
     domSel->RemoveRange(domSel->GetRangeAt(idx));
   SetSelectionBoundsAt(0, aStartPos, aEndPos);
 
   // When selection is done, move the focus to the selection if accessible is
@@ -1159,17 +1159,17 @@ HyperTextAccessible::CaretOffset() const
   // is not inside of focused node.
   FocusManager::FocusDisposition focusDisp =
     FocusMgr()->IsInOrContainsFocus(this);
   if (focusDisp == FocusManager::eNone)
     return -1;
 
   // Turn the focus node and offset of the selection into caret hypretext
   // offset.
-  Selection* domSel = DOMSelection();
+  dom::Selection* domSel = DOMSelection();
   NS_ENSURE_TRUE(domSel, -1);
 
   nsINode* focusNode = domSel->GetFocusNode();
   uint32_t focusOffset = domSel->FocusOffset();
 
   // No caret if this DOM node is inside of focused node but the selection's
   // focus point is not inside of this DOM node.
   if (focusDisp == FocusManager::eContainedByFocus) {
@@ -1189,17 +1189,17 @@ int32_t
 HyperTextAccessible::CaretLineNumber()
 {
   // Provide the line number for the caret, relative to the
   // currently focused node. Use a 1-based index
   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
   if (!frameSelection)
     return -1;
 
-  Selection* domSel =
+  dom::Selection* domSel =
     frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL);
   if (!domSel)
     return - 1;
 
   nsINode* caretNode = domSel->GetFocusNode();
   if (!caretNode || !caretNode->IsContent())
     return -1;
 
@@ -1305,17 +1305,17 @@ HyperTextAccessible::GetSelectionDOMRang
                                            nsTArray<nsRange*>* aRanges)
 {
   // Ignore selection if it is not visible.
   nsRefPtr<nsFrameSelection> frameSelection = FrameSelection();
   if (!frameSelection ||
       frameSelection->GetDisplaySelection() <= nsISelectionController::SELECTION_HIDDEN)
     return;
 
-  Selection* domSel = frameSelection->GetSelection(aType);
+  dom::Selection* domSel = frameSelection->GetSelection(aType);
   if (!domSel)
     return;
 
   nsCOMPtr<nsINode> startNode = GetNode();
 
   nsCOMPtr<nsIEditor> editor = GetEditor();
   if (editor) {
     nsCOMPtr<nsIDOMElement> editorRoot;
@@ -1392,17 +1392,17 @@ HyperTextAccessible::SelectionBoundsAt(i
 bool
 HyperTextAccessible::SetSelectionBoundsAt(int32_t aSelectionNum,
                                           int32_t aStartOffset,
                                           int32_t aEndOffset)
 {
   int32_t startOffset = ConvertMagicOffset(aStartOffset);
   int32_t endOffset = ConvertMagicOffset(aEndOffset);
 
-  Selection* domSel = DOMSelection();
+  dom::Selection* domSel = DOMSelection();
   if (!domSel)
     return false;
 
   nsRefPtr<nsRange> range;
   uint32_t rangeCount = domSel->GetRangeCount();
   if (aSelectionNum == rangeCount)
     range = new nsRange(mContent);
   else
@@ -1421,17 +1421,17 @@ HyperTextAccessible::SetSelectionBoundsA
 
   domSel->RemoveRange(range);
   return NS_SUCCEEDED(domSel->AddRange(range));
 }
 
 bool
 HyperTextAccessible::RemoveFromSelection(int32_t aSelectionNum)
 {
-  Selection* domSel = DOMSelection();
+  dom::Selection* domSel = DOMSelection();
   if (!domSel)
     return false;
 
   if (aSelectionNum < 0 || aSelectionNum >= domSel->GetRangeCount())
     return false;
 
   domSel->RemoveRange(domSel->GetRangeAt(aSelectionNum));
   return true;
@@ -1516,17 +1516,17 @@ HyperTextAccessible::EnclosingRange(a11y
   }
 }
 
 void
 HyperTextAccessible::SelectionRanges(nsTArray<a11y::TextRange>* aRanges) const
 {
   NS_ASSERTION(aRanges->Length() != 0, "TextRange array supposed to be empty");
 
-  Selection* sel = DOMSelection();
+  dom::Selection* sel = DOMSelection();
   if (!sel)
     return;
 
   aRanges->SetCapacity(sel->RangeCount());
 
   for (uint32_t idx = 0; idx < sel->RangeCount(); idx++) {
     nsRange* DOMRange = sel->GetRangeAt(idx);
     HyperTextAccessible* startParent =
@@ -1843,17 +1843,17 @@ HyperTextAccessible::GetSpellTextAttribu
                                            int32_t* aHTStartOffset,
                                            int32_t* aHTEndOffset,
                                            nsIPersistentProperties* aAttributes)
 {
   nsRefPtr<nsFrameSelection> fs = FrameSelection();
   if (!fs)
     return NS_OK;
 
-  Selection* domSel = fs->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
+  dom::Selection* domSel = fs->GetSelection(nsISelectionController::SELECTION_SPELLCHECK);
   if (!domSel)
     return NS_OK;
 
   int32_t rangeCount = domSel->GetRangeCount();
   if (rangeCount <= 0)
     return NS_OK;
 
   int32_t startHTOffset = 0, endHTOffset = 0;
--- a/accessible/src/generic/HyperTextAccessible.h
+++ b/accessible/src/generic/HyperTextAccessible.h
@@ -484,17 +484,17 @@ protected:
                              uint32_t aEndRenderedOffset);
 
   // Selection helpers
 
   /**
    * Return frame/DOM selection object for the accessible.
    */
   already_AddRefed<nsFrameSelection> FrameSelection() const;
-  Selection* DOMSelection() const;
+  dom::Selection* DOMSelection() const;
 
   /**
    * Return selection ranges within the accessible subtree.
    */
   void GetSelectionDOMRanges(int16_t aType, nsTArray<nsRange*>* aRanges);
 
   nsresult SetSelectionRange(int32_t aStartPos, int32_t aEndPos);
 
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -81,9 +81,14 @@ contract @mozilla.org/fxaccounts/fxaccou
 # HelperAppDialog.js
 component {710322af-e6ae-4b0c-b2c9-1474a87b077e} HelperAppDialog.js
 contract @mozilla.org/helperapplauncherdialog;1 {710322af-e6ae-4b0c-b2c9-1474a87b077e}
 
 #ifndef MOZ_WIDGET_GONK
 component {c83c02c0-5d43-4e3e-987f-9173b313e880} SimulatorScreen.js
 contract @mozilla.org/simulator-screen;1 {c83c02c0-5d43-4e3e-987f-9173b313e880}
 category profile-after-change SimulatorScreen @mozilla.org/simulator-screen;1
+
+component {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e} OopCommandLine.js
+contract @mozilla.org/commandlinehandler/general-startup;1?type=b2goop {e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e}
+category command-line-handler m-b2goop @mozilla.org/commandlinehandler/general-startup;1?type=b2goop
 #endif
+
new file mode 100644
--- /dev/null
+++ b/b2g/components/OopCommandLine.js
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
+
+function oopCommandlineHandler() {
+}
+
+oopCommandlineHandler.prototype = {
+    handle: function(cmdLine) {
+        let oopFlag = cmdLine.handleFlag("oop", false);
+        if (oopFlag) {
+            /**
+             * Manipulate preferences by adding to the *default* branch.  Adding
+             * to the default branch means the changes we make won"t get written
+             * back to user preferences.
+             */
+            let prefs = Services.prefs
+            let branch = prefs.getDefaultBranch("");
+
+            try {
+                // Turn on all OOP services, making desktop run similar to phone
+                // environment
+                branch.setBoolPref("dom.ipc.tabs.disabled", false);
+                branch.setBoolPref("layers.acceleration.disabled", false);
+                branch.setBoolPref("layers.offmainthreadcomposition.enabled", true);
+                branch.setBoolPref("layers.offmainthreadcomposition.async-animations", true);
+                branch.setBoolPref("layers.async-video.enabled", true);
+                branch.setBoolPref("layers.async-pan-zoom.enabled", true);
+                branch.setCharPref("gfx.content.azure.backends", "cairo");
+            } catch (e) { }
+
+        }
+        if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
+            cmdLine.preventDefault = true;
+        }
+    },
+
+    helpInfo: "  -oop         Use out-of-process model in B2G\n",
+    classID: Components.ID("{e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e}"),
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([oopCommandlineHandler]);
--- a/b2g/components/moz.build
+++ b/b2g/components/moz.build
@@ -20,16 +20,17 @@ EXTRA_COMPONENTS += [
     'SmsProtocolHandler.js',
     'TelProtocolHandler.js',
     'WebappsUpdateTimer.js',
     'YoutubeProtocolHandler.js',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
     EXTRA_COMPONENTS += [
+      'OopCommandLine.js',
       'SimulatorScreen.js'
     ]
 
 EXTRA_PP_COMPONENTS += [
     'B2GComponents.manifest',
     'DirectoryProvider.js',
     'RecoveryService.js',
 ]
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="85f9690323b235f4dcf2901ea2240d3c60fc22a0"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="65fba428f8d76336b33ddd9e15900357953600ba">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="85f9690323b235f4dcf2901ea2240d3c60fc22a0"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/releng-flame.tt
+++ b/b2g/config/flame/releng-flame.tt
@@ -1,7 +1,7 @@
 [
-{"size": 169226356,
-"digest": "f9456848fd661b8be05d6a30607fad4787bcecfe676b53f9a4074653fdda6a377c961038c866c5d83355e3afd89f1a3bd947a142aeaf7dd7d81b6c376185badd",
+{"size": 156447892,
+"digest": "02b2e6bcaff4ccadfd85a75cc1dfb526be7937673ed18b2c6fb7fe2256a725bc778d513e3820d86adaec1636e1771bd0c5663e17bf2d3f1d6b445ff1e0a136f2",
 "filename": "backup-flame.tar.xz",
 "algorithm": "sha512"
 }
 ]
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -13,17 +13,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
@@ -115,17 +115,17 @@
   <project name="platform/system/netd" path="system/netd" revision="ea8103eae5642621ca8202e00620f4ca954ed413"/>
   <project name="platform/system/security" path="system/security" revision="360f51f7af191316cd739f229db1c5f7233be063"/>
   <project name="platform/system/vold" path="system/vold" revision="153df4d067a4149c7d78f1c92fed2ce2bd6a272e"/>
   <default remote="caf" revision="jb_3.2" sync-j="4"/>
   <!-- Flame specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="234ed34543345f58c0d4dcb1aa012de68802b9dc"/>
   <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="9729afa15ae3362db1852eee60422947db614dd6"/>
-  <project name="kernel/msm" path="kernel" revision="b3092c54430df89636fb0670d32058bc63474017"/>
+  <project name="kernel/msm" path="kernel" revision="3f7af9ae7ef30dc1c37972ed0ad957fc64219f31"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="f2914eacee9120680a41463708bb6ee8291749fc"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="fa892235a9bd8983f8b591129fc1a9398f64e514"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
   <project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="dd925f76e4f149c3d5571b80e12f7e24bbe89c59"/>
   <project name="platform/external/dbus" path="external/dbus" revision="ea87119c843116340f5df1d94eaf8275e1055ae8"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="320b05a5761eb2a4816f7529c91ea49422979b55"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="1df6dac11d7370a2fffca8e31d65b80f537faec5"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="807d87d5ff66cb5e0664f6924f612fcdb5e2c453"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "d3ee2aca1f8e4d7e1c721f445d6956d73066126b", 
+    "revision": "2fccee502f455ba2ca7178efa5cf247d90df8afb", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="73b5d6a8773aa048054119bf5b3ca0d005b5494e"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="facd91d31db983a60c7f1035ca01b727c7a1de65"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -134,17 +134,16 @@
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chardet.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_base.xpt
 @BINPATH@/components/content_events.xpt
-@BINPATH@/components/content_canvas.xpt
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
 @BINPATH@/components/diskspacewatcher.xpt
 @BINPATH@/components/docshell.xpt
 @BINPATH@/components/dom.xpt
@@ -427,16 +426,17 @@
 #endif // MOZ_WIDGET_GONK && MOZ_B2G_RIL
 
 #ifndef MOZ_WIDGET_GONK
 @BINPATH@/components/extensions.manifest
 @BINPATH@/components/addonManager.js
 @BINPATH@/components/amContentHandler.js
 @BINPATH@/components/amWebInstallListener.js
 @BINPATH@/components/nsBlocklistService.js
+@BINPATH@/components/OopCommandLine.js
 #endif
 
 #ifdef MOZ_UPDATER
 @BINPATH@/components/nsUpdateService.manifest
 @BINPATH@/components/nsUpdateService.js
 @BINPATH@/components/nsUpdateServiceStub.js
 #endif
 @BINPATH@/components/nsUpdateTimerManager.manifest
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -281,16 +281,20 @@ let SessionHistoryListener = {
     return true;
   },
 
   OnHistoryReload: function (reloadURI, reloadFlags) {
     this.collect();
     return true;
   },
 
+  OnHistoryReplaceEntry: function (index) {
+    this.collect();
+  },
+
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsISHistoryListener,
     Ci.nsISupportsWeakReference
   ])
 };
 
 /**
  * Listens for scroll position changes. Whenever the user scrolls the top-most
--- a/browser/components/sessionstore/src/ContentRestore.jsm
+++ b/browser/components/sessionstore/src/ContentRestore.jsm
@@ -364,16 +364,17 @@ HistoryListener.prototype = {
     this.webNavigation.sessionHistory.removeSHistoryListener(this);
   },
 
   OnHistoryNewEntry: function(newURI) {},
   OnHistoryGoBack: function(backURI) { return true; },
   OnHistoryGoForward: function(forwardURI) { return true; },
   OnHistoryGotoIndex: function(index, gotoURI) { return true; },
   OnHistoryPurge: function(numEntries) { return true; },
+  OnHistoryReplaceEntry: function(index) {},
 
   OnHistoryReload: function(reloadURI, reloadFlags) {
     this.callback();
 
     // Cancel the load.
     return false;
   },
 }
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -2576,16 +2576,22 @@ let SessionStoreInternal = {
       // Ensure the index is in bounds.
       let activeIndex = (tabData.index || tabData.entries.length) - 1;
       activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
       activeIndex = Math.max(activeIndex, 0);
 
       // Save the index in case we updated it above.
       tabData.index = activeIndex + 1;
 
+      // In electrolysis, we may need to change the browser's remote
+      // attribute so that it runs in a content process.
+      let activePageData = tabData.entries[activeIndex] || null;
+      let uri = activePageData ? activePageData.url || null : null;
+      tabbrowser.updateBrowserRemoteness(browser, uri);
+
       // Start a new epoch and include the epoch in the restoreHistory
       // message. If a message is received that relates to a previous epoch, we
       // discard it.
       let epoch = this._nextRestoreEpoch++;
       this._browserEpochs.set(browser.permanentKey, epoch);
 
       // keep the data around to prevent dataloss in case
       // a tab gets closed before it's been properly restored
@@ -2599,22 +2605,16 @@ let SessionStoreInternal = {
         history: {entries: tabData.entries, index: tabData.index},
         scroll: tabData.scroll || null,
         storage: tabData.storage || null,
         formdata: tabData.formdata || null,
         disallow: tabData.disallow || null,
         pageStyle: tabData.pageStyle || null
       });
 
-      // In electrolysis, we may need to change the browser's remote
-      // attribute so that it runs in a content process.
-      let activePageData = tabData.entries[activeIndex] || null;
-      let uri = activePageData ? activePageData.url || null : null;
-      tabbrowser.updateBrowserRemoteness(browser, uri);
-
       browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory",
                                               {tabData: tabData, epoch: epoch});
 
       // Restore tab attributes.
       if ("attributes" in tabData) {
         TabAttributes.set(tab, tabData.attributes);
       }
 
--- a/browser/components/sessionstore/test/browser_sessionHistory.js
+++ b/browser/components/sessionstore/test/browser_sessionHistory.js
@@ -215,21 +215,21 @@ add_task(function test_pushstate_replace
 
   // Check that we have added the history entry.
   SyncHandlers.get(browser).flush();
   let {entries} = JSON.parse(ss.getTabState(tab));
   is(entries.length, 2, "there is another shistory entry");
   is(entries[1].url, "http://example.com/test-entry/", "url is correct");
 
   // Disabled until replaceState invalidation is supported. See Bug 967028.
-  // browser.messageManager.
-  //   sendAsyncMessage("ss-test:historyReplaceState", {url: 'test-entry2/'});
-  // yield promiseContentMessage(browser, "ss-test:historyReplaceState");
+  browser.messageManager.
+    sendAsyncMessage("ss-test:historyReplaceState", {url: 'test-entry2/'});
+  yield promiseContentMessage(browser, "ss-test:historyReplaceState");
 
-  // // Check that we have modified the history entry.
-  // SyncHandlers.get(browser).flush();
-  // let {entries} = JSON.parse(ss.getTabState(tab));
-  // is(entries.length, 2, "there is still two shistory entries");
-  // is(entries[1].url, "http://example.com/test-entry/test-entry2/", "url is correct");
+  // Check that we have modified the history entry.
+  SyncHandlers.get(browser).flush();
+  let {entries} = JSON.parse(ss.getTabState(tab));
+  is(entries.length, 2, "there is still two shistory entries");
+  is(entries[1].url, "http://example.com/test-entry/test-entry2/", "url is correct");
 
   // Cleanup.
   gBrowser.removeTab(tab);
 });
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -165,17 +165,16 @@
 @BINPATH@/browser/components/browser-feeds.xpt
 @BINPATH@/components/caps.xpt
 @BINPATH@/components/chrome.xpt
 @BINPATH@/components/commandhandler.xpt
 @BINPATH@/components/commandlines.xpt
 @BINPATH@/components/composer.xpt
 @BINPATH@/components/content_base.xpt
 @BINPATH@/components/content_events.xpt
-@BINPATH@/components/content_canvas.xpt
 @BINPATH@/components/content_htmldoc.xpt
 @BINPATH@/components/content_html.xpt
 #ifdef MOZ_WEBRTC
 @BINPATH@/components/content_webrtc.xpt
 #endif
 @BINPATH@/components/content_xslt.xpt
 @BINPATH@/components/cookie.xpt
 @BINPATH@/components/directory.xpt
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -104,22 +104,22 @@ struct nsIntMargin;
 template<class E> class nsCOMArray;
 template<class K, class V> class nsDataHashtable;
 template<class K, class V> class nsRefPtrHashtable;
 template<class T> class nsReadingIterator;
 
 namespace mozilla {
 class ErrorResult;
 class EventListenerManager;
-class Selection;
 
 namespace dom {
 class DocumentFragment;
 class Element;
 class EventTarget;
+class Selection;
 } // namespace dom
 
 namespace layers {
 class LayerManager;
 } // namespace layers
 
 // Called back from DeferredFinalize.  Should add 'thing' to the array of smart
 // pointers in 'pointers', creating the array if 'pointers' is null, and return
@@ -2081,17 +2081,17 @@ public:
    * The selection's anchor and focus must both be in the root node passed or a
    * descendant.
    *
    * @param aSelection      Selection to check
    * @param aRoot           Root <input> or <textarea> element
    * @param aOutStartOffset Output start offset
    * @param aOutEndOffset   Output end offset
    */
-  static void GetSelectionInTextControl(mozilla::Selection* aSelection,
+  static void GetSelectionInTextControl(mozilla::dom::Selection* aSelection,
                                         Element* aRoot,
                                         int32_t& aOutStartOffset,
                                         int32_t& aOutEndOffset);
 
   /**
    * Takes a frame for anonymous content within a text control (<input> or
    * <textarea>), and returns an offset in the text content, adjusted for a
    * trailing <br> frame.
--- a/content/base/public/nsIXMLHttpRequest.idl
+++ b/content/base/public/nsIXMLHttpRequest.idl
@@ -326,17 +326,17 @@ interface nsIXMLHttpRequest : nsISupport
   readonly attribute boolean mozAnon;
 
   /**
    * If true, the same origin policy will not be enforced on the request.
    */
   readonly attribute boolean mozSystem;
 };
 
-[scriptable, uuid(840d0d00-e83e-4a29-b3c7-67e96e90a499)]
+[uuid(840d0d00-e83e-4a29-b3c7-67e96e90a499)]
 interface nsIXHRSendable : nsISupports {
   void getSendInfo(out nsIInputStream body,
                    out uint64_t contentLength,
                    out ACString contentType,
                    out ACString charset);
 };
 
 /**
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -45,17 +45,17 @@
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/InternalMutationEvent.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/TextEvents.h"
 #include "nsAString.h"
 #include "nsAttrName.h"
 #include "nsAttrValue.h"
 #include "nsAttrValueInlines.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsChannelPolicy.h"
--- a/content/base/src/nsCopySupport.cpp
+++ b/content/base/src/nsCopySupport.cpp
@@ -44,17 +44,17 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsContentUtils.h"
 #include "nsContentCID.h"
 
 #include "mozilla/ContentEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsresult NS_NewDomSelection(nsISelection **aDomSelection);
 
 static NS_DEFINE_CID(kCClipboardCID,           NS_CLIPBOARD_CID);
 static NS_DEFINE_CID(kCTransferableCID,        NS_TRANSFERABLE_CID);
--- a/content/base/src/nsDocumentEncoder.cpp
+++ b/content/base/src/nsDocumentEncoder.cpp
@@ -33,17 +33,17 @@
 #include "nsIDOMDocument.h"
 #include "nsICharsetConverterManager.h"
 #include "nsGkAtoms.h"
 #include "nsIContent.h"
 #include "nsIParserService.h"
 #include "nsIScriptContext.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsISelectionPrivate.h"
 #include "nsITransferable.h" // for kUnicodeMime
 #include "nsContentUtils.h"
 #include "nsNodeUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsReadableUtils.h"
 #include "nsTArray.h"
 #include "nsIFrame.h"
--- a/content/canvas/public/moz.build
+++ b/content/canvas/public/moz.build
@@ -1,20 +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 += [
-    'nsICanvasGLPrivate.idl',
-]
-
-XPIDL_MODULE = 'content_canvas'
-
 EXPORTS += [
     'nsICanvasRenderingContextInternal.h',
 ]
 
 EXPORTS.mozilla.ipc += [
     'DocumentRendererChild.h',
     'DocumentRendererParent.h',
 ]
deleted file mode 100644
--- a/content/canvas/public/nsICanvasGLPrivate.idl
+++ /dev/null
@@ -1,20 +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/. */
-
-#include "nsISupports.idl"
-
-/* These are private interface that's used to identify
- * specific concrete classes so we know what we can cast.
- */
-
-[scriptable, uuid(eba2aa03-ae19-46e2-bad7-6b966037e22c)]
-interface nsICanvasGLBuffer : nsISupports
-{
-};
-
-[scriptable, uuid(27310aab-1988-43e8-882e-6293c8c9df60)]
-interface nsICanvasGLTexture : nsISupports
-{
-};
--- a/content/html/content/public/nsIPhonetic.idl
+++ b/content/html/content/public/nsIPhonetic.idl
@@ -7,17 +7,16 @@
 
 /** 
  * This interface is used to get the phonetic value of the input text.
  * It can be used to get corresponding phonetic value for ideographic text.
  * The interface can be retrieved by calling QI to the interface 
  * which implements the phonetic interface.
  */
 
-[scriptable, uuid(BC6EA726-AB56-46b6-A21A-AA7B76D6818F)]
-
+[uuid(BC6EA726-AB56-46b6-A21A-AA7B76D6818F)]
 interface nsIPhonetic : nsISupports
 {
   /**
    * phonetic get the phonetic value of the input text
    */
   readonly attribute DOMString phonetic;
 };
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -30,17 +30,17 @@
 #include "nsIEditorObserver.h"
 #include "nsIWidget.h"
 #include "nsIDocumentEncoder.h"
 #include "nsISelectionPrivate.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIEditor.h"
 #include "nsTextEditRules.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/EventListenerManager.h"
 #include "nsContentUtils.h"
 #include "mozilla/Preferences.h"
 #include "nsTextNode.h"
 #include "nsIController.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/ScriptSettings.h"
 
--- a/content/html/document/src/nsHTMLDocument.h
+++ b/content/html/document/src/nsHTMLDocument.h
@@ -229,17 +229,17 @@ public:
   // The XPCOM Get/SetALinkColor work OK for us, since they never throw.
   // The XPCOM Get/SetBgColor work OK for us, since they never throw.
   nsIHTMLCollection* Anchors();
   nsIHTMLCollection* Applets();
   void Clear() const
   {
     // Deprecated
   }
-  mozilla::Selection* GetSelection(mozilla::ErrorResult& aRv);
+  mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aRv);
   // The XPCOM CaptureEvents works fine for us.
   // The XPCOM ReleaseEvents works fine for us.
   // We're picking up GetLocation from Document
   already_AddRefed<nsIDOMLocation> GetLocation() const {
     return nsIDocument::GetLocation();
   }
 
   virtual nsHTMLDocument* AsHTMLDocument() MOZ_OVERRIDE { return this; }
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10866,31 +10866,41 @@ nsDocShell::AddState(JS::Handle<JS::Valu
     // set URIWasModified to true for the current SHEntry (bug 669671).
     bool sameExceptHashes = true, oldURIWasModified = false;
     newURI->EqualsExceptRef(currentURI, &sameExceptHashes);
     oldOSHE->GetURIWasModified(&oldURIWasModified);
     newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
 
     // Step 5: If aReplace is false, indicating that we're doing a pushState
     // rather than a replaceState, notify bfcache that we've added a page to
-    // the history so it can evict content viewers if appropriate.
+    // the history so it can evict content viewers if appropriate. Otherwise
+    // call ReplaceEntry so that we notify nsIHistoryListeners that an entry
+    // was replaced.
+    nsCOMPtr<nsISHistory> rootSH;
+    GetRootSessionHistory(getter_AddRefs(rootSH));
+    NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
+
+    nsCOMPtr<nsISHistoryInternal> internalSH =
+        do_QueryInterface(rootSH);
+    NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
+
     if (!aReplace) {
-        nsCOMPtr<nsISHistory> rootSH;
-        GetRootSessionHistory(getter_AddRefs(rootSH));
-        NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
-
-        nsCOMPtr<nsISHistoryInternal> internalSH =
-            do_QueryInterface(rootSH);
-        NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
-
         int32_t curIndex = -1;
         rv = rootSH->GetIndex(&curIndex);
         if (NS_SUCCEEDED(rv) && curIndex > -1) {
             internalSH->EvictOutOfRangeContentViewers(curIndex);
         }
+    } else {
+        nsCOMPtr<nsISHEntry> rootSHEntry = GetRootSHEntry(newSHEntry);
+
+        int32_t index = -1;
+        rv = rootSH->GetIndexOfEntry(rootSHEntry, &index);
+        if (NS_SUCCEEDED(rv) && index > -1) {
+            internalSH->ReplaceEntry(index, rootSHEntry);
+        }
     }
 
     // Step 6: If the document's URI changed, update document's URI and update
     // global history.
     //
     // We need to call FireOnLocationChange so that the browser's address bar
     // gets updated and the back button is enabled, but we only need to
     // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
--- a/docshell/shistory/public/nsISHistory.idl
+++ b/docshell/shistory/public/nsISHistory.idl
@@ -17,22 +17,22 @@ interface nsISimpleEnumerator;
  * session history component must create a instance of it and set
  * it in the nsIWebNavigation object.
  * This interface is accessible from javascript.
  */
  
 
 %{C++
 #define NS_SHISTORY_CID \
-{0x7294fe9c, 0x14d8, 0x11d5, {0x98, 0x82, 0x00, 0xC0, 0x4f, 0xa0, 0x2f, 0x40}}
+{0x7b807041, 0xe60a, 0x4384, {0x93, 0x5f, 0xaf, 0x30, 0x61, 0xd8, 0xb8, 0x15}}
 
 #define NS_SHISTORY_CONTRACTID "@mozilla.org/browser/shistory;1"
 %}
 
-[scriptable, uuid(b4440e2e-0fc2-11e3-971f-59e799890b3c)]
+[scriptable, uuid(7b807041-e60a-4384-935f-af3061d8b815)]
 interface nsISHistory: nsISupports
 {
   /**
    * A readonly property of the interface that returns 
    * the number of toplevel documents currently available
    * in session history.
    */
    readonly attribute long count;
@@ -142,9 +142,21 @@ interface nsISHistory: nsISupports
    * @see nsISimpleEnumerator
    * @see nsISHEntry
    * @see QueryInterface()
    * @see do_QueryInterface()
    */
    readonly attribute nsISimpleEnumerator SHistoryEnumerator;
 
    void reloadCurrentEntry();
+
+   /**
+   * Called to obtain the index to a given history entry.
+   *
+   * @param aEntry            The entry to obtain the index of.
+   *
+   * @return                  <code>NS_OK</code> index for the history entry
+   *                          is obtained successfully.
+   *                          <code>NS_ERROR_FAILURE</code> Error in obtaining
+   *                          index for the given history entry.
+   */
+   long getIndexOfEntry(in nsISHEntry aEntry);
 };
--- a/docshell/shistory/public/nsISHistoryListener.idl
+++ b/docshell/shistory/public/nsISHistoryListener.idl
@@ -16,17 +16,17 @@ interface nsIURI;
  * A session history listener will be notified when pages are added, removed
  * and loaded from session history. It can prevent any action (except adding
  * a new session history entry) from happening by returning false from the
  * corresponding callback method.
  *
  * A session history listener can be registered on a particular nsISHistory
  * instance via the nsISHistory::addSHistoryListener() method.
  */
-[scriptable, uuid(3b07f591-e8e1-11d4-9882-00c04fa02f40)]
+[scriptable, uuid(125c0833-746a-400e-9b89-d2d18545c08a)]
 interface nsISHistoryListener : nsISupports 
 {
   /**
    * Called when a new document is added to session history. New documents are
    * added to session history by docshell when new pages are loaded in a frame
    * or content area, for example via nsIWebNavigation::loadURI()
    *
    * @param aNewURI     The URI of the document to be added to session history.
@@ -82,9 +82,19 @@ interface nsISHistoryListener : nsISuppo
    * from history, to erase evidence of prior page loads, etc.
    *
    * To purge documents from session history call nsISHistory::PurgeHistory()
    *
    * @param aNumEntries   The number of entries to be removed from session history.
    * @return              Whether the operation can proceed.
    */
    boolean OnHistoryPurge(in long aNumEntries);
+
+  /**
+   * Called when an entry is replaced in the session history. Entries are
+   * replaced when navigating away from non-persistent history entries (such as
+   * about pages) and when history.replaceState is called.
+   *
+   * @param aIndex        The index in session history of the entry being
+  *                       replaced
+   */
+   void OnHistoryReplaceEntry(in long aIndex);
 };
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -410,28 +410,30 @@ nsSHistory::AddEntry(nsISHEntry * aSHEnt
 
   if(mListRoot)
     GetTransactionAtIndex(mIndex, getter_AddRefs(currentTxn));
 
   bool currentPersist = true;
   if(currentTxn)
     currentTxn->GetPersist(&currentPersist);
 
+  int32_t currentIndex = mIndex;
+
   if(!currentPersist)
   {
+    NOTIFY_LISTENERS(OnHistoryReplaceEntry, (currentIndex));
     NS_ENSURE_SUCCESS(currentTxn->SetSHEntry(aSHEntry),NS_ERROR_FAILURE);
     currentTxn->SetPersist(aPersist);
     return NS_OK;
   }
 
   nsCOMPtr<nsISHTransaction> txn(do_CreateInstance(NS_SHTRANSACTION_CONTRACTID));
   NS_ENSURE_TRUE(txn, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIURI> uri;
-  int32_t currentIndex = mIndex;
   aSHEntry->GetURI(getter_AddRefs(uri));
   NOTIFY_LISTENERS(OnHistoryNewEntry, (uri));
 
   // If a listener has changed mIndex, we need to get currentTxn again,
   // otherwise we'll be left at an inconsistent state (see bug 320742)
   if (currentIndex != mIndex) {
     GetTransactionAtIndex(mIndex, getter_AddRefs(currentTxn));
   }
@@ -550,16 +552,60 @@ nsSHistory::GetTransactionAtIndex(int32_
     }  //NS_SUCCEEDED
     else 
       return NS_ERROR_FAILURE;
   }  // while 
   
   return NS_OK;
 }
 
+
+/* Get the index of a given entry */
+NS_IMETHODIMP
+nsSHistory::GetIndexOfEntry(nsISHEntry* aSHEntry, int32_t* aResult) {
+  NS_ENSURE_ARG(aSHEntry);
+  NS_ENSURE_ARG_POINTER(aResult);
+  *aResult = -1;
+
+  if (mLength <= 0) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsISHTransaction> currentTxn;
+  int32_t cnt = 0;
+
+  nsresult rv = GetRootTransaction(getter_AddRefs(currentTxn));
+  if (NS_FAILED(rv) || !currentTxn) {
+    return NS_ERROR_FAILURE;
+  }
+
+  while (true) {
+    nsCOMPtr<nsISHEntry> entry;
+    rv = currentTxn->GetSHEntry(getter_AddRefs(entry));
+    if (NS_FAILED(rv) || !entry) {
+      return NS_ERROR_FAILURE;
+    }
+
+    if (aSHEntry == entry) {
+      *aResult = cnt;
+      break;
+    }
+
+    rv = currentTxn->GetNext(getter_AddRefs(currentTxn));
+    if (NS_FAILED(rv) || !currentTxn) {
+      return NS_ERROR_FAILURE;
+    }
+
+    cnt++;
+  }
+
+  return NS_OK;
+}
+
+
 #ifdef DEBUG
 nsresult
 nsSHistory::PrintHistory()
 {
 
   nsCOMPtr<nsISHTransaction>   txn;
   int32_t index = 0;
   nsresult rv;
@@ -729,16 +775,18 @@ nsSHistory::ReplaceEntry(int32_t aIndex,
 
   if (!mListRoot) // Session History is not initialised.
     return NS_ERROR_FAILURE;
 
   rv = GetTransactionAtIndex(aIndex, getter_AddRefs(currentTxn));
 
   if(currentTxn)
   {
+    NOTIFY_LISTENERS(OnHistoryReplaceEntry, (aIndex));
+
     // Set the replacement entry in the transaction
     rv = currentTxn->SetSHEntry(aReplaceEntry);
     rv = currentTxn->SetPersist(true);
   }
   return rv;
 }
 
 NS_IMETHODIMP
--- a/docshell/test/browser/browser_bug422543.js
+++ b/docshell/test/browser/browser_bug422543.js
@@ -34,16 +34,18 @@ SHistoryListener.prototype = {
     return this.retval;
   },
 
   OnHistoryReload: function (aReloadURI, aReloadFlags) {
     this.last = "reload";
     return this.retval;
   },
 
+  OnHistoryReplaceEntry: function (aIndex) {},
+
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
                                          Ci.nsISupportsWeakReference])
 };
 
 let gFirstListener = new SHistoryListener();
 let gSecondListener = new SHistoryListener();
 
 function test() {
--- a/docshell/test/browser/browser_bug670318.js
+++ b/docshell/test/browser/browser_bug670318.js
@@ -34,16 +34,17 @@ function test() {
       return true;
     },
 
     OnHistoryReload: function () true,
     OnHistoryGoBack: function () true,
     OnHistoryGoForward: function () true,
     OnHistoryGotoIndex: function () true,
     OnHistoryPurge: function () true,
+    OnHistoryReplaceEntry: function () true,
 
     QueryInterface: XPCOMUtils.generateQI([Ci.nsISHistoryListener,
                                            Ci.nsISupportsWeakReference])
   };
 
   let tab = gBrowser.loadOneTab(URL, {inBackground: false});
   let browser = tab.linkedBrowser;
   let history = browser.sessionHistory;
--- a/dom/audiochannel/nsIAudioChannelAgent.idl
+++ b/dom/audiochannel/nsIAudioChannelAgent.idl
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMWindow;
 
-[scriptable, uuid(194b55d9-39c0-45c6-b8ef-b8049f978ea5)]
+[uuid(194b55d9-39c0-45c6-b8ef-b8049f978ea5)]
 interface nsIAudioChannelAgentCallback : nsISupports
 {
   /**
    * Notified when the playable status of channel is changed.
    *
    * @param canPlay
    *        Callback from agent to notify component of the playable status
    *        of the channel. If canPlay is muted state, component SHOULD stop
@@ -35,17 +35,17 @@ interface nsIAudioChannelAgentCallback :
  *   3. Notifying the agent when they start/stop using this channel.
  *   4. Notifying the agent of changes to the visibility of the component using
  *      this channel.
  *
  * The agent will invoke a callback to notify Gecko components of
  *   1. Changes to the playable status of this channel.
  */
 
-[scriptable, uuid(2b0222a5-8f7b-49d2-9ab8-cd01b744b23e)]
+[uuid(2b0222a5-8f7b-49d2-9ab8-cd01b744b23e)]
 interface nsIAudioChannelAgent : nsISupports
 {
   const long AUDIO_AGENT_CHANNEL_NORMAL             = 0;
   const long AUDIO_AGENT_CHANNEL_CONTENT            = 1;
   const long AUDIO_AGENT_CHANNEL_NOTIFICATION       = 2;
   const long AUDIO_AGENT_CHANNEL_ALARM              = 3;
   const long AUDIO_AGENT_CHANNEL_TELEPHONY          = 4;
   const long AUDIO_AGENT_CHANNEL_RINGER             = 5;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -70,17 +70,16 @@
 #include "nsPIDOMWindow.h"
 #include "nsIDOMJSWindow.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIDOMConstructor.h"
 
 // DOM core includes
 #include "nsError.h"
 #include "nsIDOMUserDataHandler.h"
-#include "nsIDOMXPathNamespace.h"
 #include "nsIDOMXULButtonElement.h"
 #include "nsIDOMXULCheckboxElement.h"
 #include "nsIDOMXULPopupElement.h"
 
 // Event related includes
 #include "nsIDOMEventTarget.h"
 
 // CSS related includes
@@ -218,17 +217,16 @@ const uint32_t kDOMClassInfo_##_dom_clas
 DOMCI_DATA_NO_CLASS(ContentFrameMessageManager)
 DOMCI_DATA_NO_CLASS(ChromeMessageBroadcaster)
 DOMCI_DATA_NO_CLASS(ChromeMessageSender)
 
 DOMCI_DATA_NO_CLASS(DOMPrototype)
 DOMCI_DATA_NO_CLASS(DOMConstructor)
 
 DOMCI_DATA_NO_CLASS(UserDataHandler)
-DOMCI_DATA_NO_CLASS(XPathNamespace)
 DOMCI_DATA_NO_CLASS(XULControlElement)
 DOMCI_DATA_NO_CLASS(XULLabeledControlElement)
 DOMCI_DATA_NO_CLASS(XULButtonElement)
 DOMCI_DATA_NO_CLASS(XULCheckboxElement)
 DOMCI_DATA_NO_CLASS(XULPopupElement)
 
 #define NS_DEFINE_CLASSINFO_DATA_HELPER(_class, _helper, _flags,              \
                                         _chromeOnly, _allowXBL)               \
@@ -443,18 +441,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSFontFeatureValuesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(UserDataHandler, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(XPathNamespace, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULControlElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULLabeledControlElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULButtonElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CHROME_XBL_CLASSINFO_DATA(XULCheckboxElement, nsDOMGenericSH,
                                       DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1116,20 +1112,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(CSSFontFeatureValuesRule, nsIDOMCSSFontFeatureValuesRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSFontFeatureValuesRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(UserDataHandler, nsIDOMUserDataHandler)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMUserDataHandler)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XPathNamespace, nsIDOMXPathNamespace)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathNamespace)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULControlElement, nsIDOMXULControlElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULControlElement)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN_NO_CLASS_IF(XULLabeledControlElement, nsIDOMXULLabeledControlElement)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMXULLabeledControlElement)
   DOM_CLASSINFO_MAP_END
 
@@ -3161,17 +3153,16 @@ const InterfaceShimEntry kInterfaceShimM
   { "nsIDOMSimpleGestureEvent", "SimpleGestureEvent" },
   { "nsIDOMUIEvent", "UIEvent" },
   { "nsIDOMHTMLMediaElement", "HTMLMediaElement" },
   { "nsIDOMMediaError", "MediaError" },
   { "nsIDOMOfflineResourceList", "OfflineResourceList" },
   { "nsIDOMRange", "Range" },
   { "nsIDOMSVGLength", "SVGLength" },
   { "nsIDOMNodeFilter", "NodeFilter" },
-  { "nsIDOMXPathNamespace", "XPathNamespace" },
   { "nsIDOMXPathResult", "XPathResult" } };
 
 static nsresult
 LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
                      nsPIDOMWindow *win,
                      JS::MutableHandle<JSPropertyDescriptor> desc)
 {
   // Keep track of how often this happens.
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -88,14 +88,13 @@ DOMCI_CLASS(ChromeMessageSender)
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(CSSPageRule)
 
 DOMCI_CLASS(CSSFontFeatureValuesRule)
 
 DOMCI_CLASS(UserDataHandler)
-DOMCI_CLASS(XPathNamespace)
 DOMCI_CLASS(XULControlElement)
 DOMCI_CLASS(XULLabeledControlElement)
 DOMCI_CLASS(XULButtonElement)
 DOMCI_CLASS(XULCheckboxElement)
 DOMCI_CLASS(XULPopupElement)
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -22,17 +22,17 @@
 #include "nsLayoutUtils.h"
 #include "nsIPresShell.h"
 #include "nsFrameTraversal.h"
 #include "nsIWebNavigation.h"
 #include "nsCaret.h"
 #include "nsIBaseWindow.h"
 #include "nsViewManager.h"
 #include "nsFrameSelection.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsXULPopupManager.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIPrincipal.h"
 #include "nsIObserverService.h"
 #include "nsIObjectFrame.h"
 #include "nsBindingManager.h"
 #include "nsStyleCoord.h"
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -167,17 +167,17 @@
 #include "nsXBLService.h"
 
 // used for popup blocking, needs to be converted to something
 // belonging to the back-end like nsIContentPolicy
 #include "nsIPopupWindowManager.h"
 
 #include "nsIDragService.h"
 #include "mozilla/dom/Element.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsFrameLoader.h"
 #include "nsISupportsPrimitives.h"
 #include "nsXPCOMCID.h"
 #include "GeneratedEvents.h"
 #include "GeneratedEventClasses.h"
 #include "mozIThirdPartyUtil.h"
 #ifdef MOZ_LOGGING
 // so we can get logging even in release builds
@@ -1602,16 +1602,18 @@ nsGlobalWindow::FreeInnerObjects()
   CleanupCachedXBLHandlers(this);
 
   for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
     mAudioContexts[i]->Shutdown();
   }
   mAudioContexts.Clear();
 
 #ifdef MOZ_GAMEPAD
+  DisableGamepadUpdates();
+  mHasGamepad = false;
   mGamepads.Clear();
 #endif
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsISupports
 //*****************************************************************************
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -99,26 +99,26 @@ class nsDOMWindowUtils;
 class nsIIdleService;
 struct nsIntSize;
 struct nsRect;
 
 class nsWindowSizes;
 
 namespace mozilla {
 class DOMEventTargetHelper;
-class Selection;
 namespace dom {
 class BarProp;
 class Console;
 class External;
 class Function;
 class Gamepad;
 class MediaQueryList;
 class Navigator;
 class OwningExternalOrWindowProxy;
+class Selection;
 class SpeechSynthesis;
 class WakeLock;
 namespace indexedDB {
 class IDBFactory;
 } // namespace indexedDB
 } // namespace dom
 } // namespace mozilla
 
@@ -877,17 +877,17 @@ public:
                       mozilla::ErrorResult& aError);
   void ClearInterval(int32_t aHandle, mozilla::ErrorResult& aError);
   void Atob(const nsAString& aAsciiBase64String, nsAString& aBinaryData,
             mozilla::ErrorResult& aError);
   void Btoa(const nsAString& aBinaryData, nsAString& aAsciiBase64String,
             mozilla::ErrorResult& aError);
   nsIDOMStorage* GetSessionStorage(mozilla::ErrorResult& aError);
   nsIDOMStorage* GetLocalStorage(mozilla::ErrorResult& aError);
-  mozilla::Selection* GetSelection(mozilla::ErrorResult& aError);
+  mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
   mozilla::dom::indexedDB::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError);
   already_AddRefed<nsICSSDeclaration>
     GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
                      mozilla::ErrorResult& aError);
   already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(const nsAString& aQuery,
                                                             mozilla::ErrorResult& aError);
   nsScreen* GetScreen(mozilla::ErrorResult& aError);
   void MoveTo(int32_t aXPos, int32_t aYPos, mozilla::ErrorResult& aError);
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -969,17 +969,16 @@ DOMInterfaces = {
     'resultNotAddRefed': [ 'alpha', 'blue', 'green', 'red' ]
 },
 
 'Screen': {
     'nativeType': 'nsScreen',
 },
 
 'Selection': {
-    'nativeType': 'mozilla::Selection',
     'resultNotAddRefed': [ 'anchorNode', 'focusNode', 'getRangeAt' ],
 },
 
 'ShadowRoot': {
     'resultNotAddRefed': [
         'styleSheets'
     ]
 },
--- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp
@@ -1373,16 +1373,47 @@ BluetoothHfpManager::GetNumberOfCalls(ui
     if (mCurrentCallArray[i].mState == aState) {
       ++num;
     }
   }
 
   return num;
 }
 
+uint32_t
+BluetoothHfpManager::GetNumberOfConCalls()
+{
+  uint32_t num = 0;
+  uint32_t callLength = mCurrentCallArray.Length();
+
+  for (uint32_t i = 1; i < callLength; ++i) {
+    if (mCurrentCallArray[i].mIsConference) {
+      ++num;
+    }
+  }
+
+  return num;
+}
+
+uint32_t
+BluetoothHfpManager::GetNumberOfConCalls(uint16_t aState)
+{
+  uint32_t num = 0;
+  uint32_t callLength = mCurrentCallArray.Length();
+
+  for (uint32_t i = 1; i < callLength; ++i) {
+    if (mCurrentCallArray[i].mIsConference
+        && mCurrentCallArray[i].mState == aState) {
+      ++num;
+    }
+  }
+
+  return num;
+}
+
 void
 BluetoothHfpManager::HandleCallStateChanged(uint32_t aCallIndex,
                                             uint16_t aCallState,
                                             const nsAString& aError,
                                             const nsAString& aNumber,
                                             const bool aIsOutgoing,
                                             const bool aIsConference,
                                             bool aSend)
@@ -1417,25 +1448,69 @@ BluetoothHfpManager::HandleCallStateChan
   }
   mCurrentCallArray[aCallIndex].mNumber = aNumber;
 
   nsRefPtr<nsRunnable> sendRingTask;
   nsString address;
 
   switch (aCallState) {
     case nsITelephonyProvider::CALL_STATE_HELD:
-      if (prevCallState == nsITelephonyProvider::CALL_STATE_CONNECTED) {
-        if (mCurrentCallArray.Length() == 1) {
-          // A single active call is put on hold (+CIEV, callheld=2)
-          sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_NOACTIVE;
-        } else {
-          // Releases all active calls and accepts the other (+CIEV, callheld=1)
-          sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_ACTIVE;
+      switch (prevCallState) {
+        case nsITelephonyProvider::CALL_STATE_CONNECTED: {
+          uint32_t numActive = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_CONNECTED);
+          uint32_t numHeld = GetNumberOfCalls(nsITelephonyProvider::CALL_STATE_HELD);
+          uint32_t numConCalls = GetNumberOfConCalls();
+
+          /**
+           * An active call becomes a held call.
+           *
+           * If this call is not a conference call,
+           * - callheld state = ONHOLD_NOACTIVE if no active call remains;
+           * - callheld state = ONHOLD_ACTIVE otherwise.
+           * If this call belongs to a conference call and all other members of
+           * the conference call have become held calls,
+           * - callheld state = ONHOLD_NOACTIVE if no active call remains;
+           * - callheld state = ONHOLD_ACTIVE otherwise.
+           *
+           * Note number of active calls may be 0 in-between state transition
+           * (c1 has become held but c2 has not become active yet), so we regard
+           * no active call remains if there is no other active/held call
+           * besides this changed call/group of conference call.
+           */
+          if (!aIsConference) {
+            if (numActive + numHeld == 1) {
+              // A single active call is put on hold.
+              sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_NOACTIVE;
+            } else {
+              // An active call is placed on hold or active/held calls swapped.
+              sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_ACTIVE;
+            }
+            SendCommand(RESPONSE_CIEV, CINDType::CALLHELD);
+          } else if (GetNumberOfConCalls(nsITelephonyProvider::CALL_STATE_HELD)
+                     == numConCalls) {
+            if (numActive + numHeld == numConCalls) {
+              // An active conference call is put on hold.
+              sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_NOACTIVE;
+            } else {
+              // Active calls are placed on hold or active/held calls swapped.
+              sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_ACTIVE;
+            }
+            SendCommand(RESPONSE_CIEV, CINDType::CALLHELD);
+          }
+          break;
         }
-        SendCommand(RESPONSE_CIEV, CINDType::CALLHELD);
+        case nsITelephonyProvider::CALL_STATE_DISCONNECTED:
+          // The call state changed from DISCONNECTED to HELD. It could happen
+          // when user held a call before Bluetooth got connected.
+          if (FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED)) {
+            // callheld = ONHOLD_ACTIVE if an active call already exists.
+            sCINDItems[CINDType::CALLHELD].value = CallHeldState::ONHOLD_ACTIVE;
+            SendCommand(RESPONSE_CIEV, CINDType::CALLHELD);
+          }
+          break;
       }
       break;
     case nsITelephonyProvider::CALL_STATE_INCOMING:
       if (FindFirstCall(nsITelephonyProvider::CALL_STATE_CONNECTED)) {
         SendCCWA(aNumber, mCurrentCallArray[aCallIndex].mType);
         UpdateCIND(CINDType::CALLSETUP, CallSetupState::INCOMING, aSend);
       } else {
         // Start sending RING indicator to HF
@@ -1471,40 +1546,51 @@ BluetoothHfpManager::HandleCallStateChan
     case nsITelephonyProvider::CALL_STATE_ALERTING:
       UpdateCIND(CINDType::CALLSETUP, CallSetupState::OUTGOING_ALERTING, aSend);
 
       // If there's an ongoing call when the headset is just connected, we have
       // to open a sco socket here.
       ConnectSco();
       break;
     case nsITelephonyProvider::CALL_STATE_CONNECTED:
+      /**
+       * A call becomes active because:
+       * - user answers an incoming call,
+       * - user dials a outgoing call and it is answered, or
+       * - SLC is connected when a call is active.
+       */
       switch (prevCallState) {
         case nsITelephonyProvider::CALL_STATE_INCOMING:
         case nsITelephonyProvider::CALL_STATE_DISCONNECTED:
           // Incoming call, no break
           sStopSendingRingFlag = true;
           ConnectSco();
           // NO BREAK HERE. continue to next statement
         case nsITelephonyProvider::CALL_STATE_DIALING:
         case nsITelephonyProvider::CALL_STATE_ALERTING:
           // Outgoing call
           UpdateCIND(CINDType::CALL, CallState::IN_PROGRESS, aSend);
           UpdateCIND(CINDType::CALLSETUP, CallSetupState::NO_CALLSETUP, aSend);
+
+          if (FindFirstCall(nsITelephonyProvider::CALL_STATE_HELD)) {
+            // callheld state = ONHOLD_ACTIVE if a held call already exists.
+            UpdateCIND(CINDType::CALLHELD, CallHeldState::ONHOLD_ACTIVE, aSend);
+          }
           break;
-        // User wants to add a held call to the conversation.
-        // The original connected call become a conference call here.
         case nsITelephonyProvider::CALL_STATE_CONNECTED:
+          // User wants to add a held call to the conversation.
+          // The original connected call becomes a conference call here.
           if (aIsConference) {
             UpdateCIND(CINDType::CALLHELD, CallHeldState::NO_CALLHELD, aSend);
           }
           break;
         case nsITelephonyProvider::CALL_STATE_HELD:
           if (!FindFirstCall(nsITelephonyProvider::CALL_STATE_HELD)) {
             if (aIsConference && !prevCallIsConference) {
-              // The held call was merged and become a conference call.
+              // The held call was merged and becomes a conference call.
               UpdateCIND(CINDType::CALLHELD, CallHeldState::NO_CALLHELD, aSend);
             } else if (sCINDItems[CINDType::CALLHELD].value ==
                        CallHeldState::ONHOLD_NOACTIVE) {
               // The held call(s) become connected call(s).
               UpdateCIND(CINDType::CALLHELD, CallHeldState::NO_CALLHELD, aSend);
             }
           }
           break;
--- a/dom/bluetooth/bluez/BluetoothHfpManager.h
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.h
@@ -152,16 +152,18 @@ private:
   void HandleVolumeChanged(const nsAString& aData);
 
   bool Init();
   void Notify(const hal::BatteryInformation& aBatteryInfo);
 #ifdef MOZ_B2G_RIL
   void ResetCallArray();
   uint32_t FindFirstCall(uint16_t aState);
   uint32_t GetNumberOfCalls(uint16_t aState);
+  uint32_t GetNumberOfConCalls();
+  uint32_t GetNumberOfConCalls(uint16_t aState);
   PhoneType GetPhoneType(const nsAString& aType);
 #endif
 
   void NotifyConnectionStatusChanged(const nsAString& aType);
   void NotifyDialer(const nsAString& aCommand);
 
 #ifdef MOZ_B2G_RIL
   void SendCCWA(const nsAString& aNumber, int aType);
--- a/dom/events/KeyboardEvent.cpp
+++ b/dom/events/KeyboardEvent.cpp
@@ -271,38 +271,16 @@ KeyboardEvent::InitKeyEvent(const nsAStr
   WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
   keyEvent->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey, aMetaKey);
   keyEvent->keyCode = aKeyCode;
   keyEvent->charCode = aCharCode;
 
   return NS_OK;
 }
 
-void
-KeyboardEvent::InitKeyboardEvent(const nsAString& aType,
-                                 bool aCanBubble,
-                                 bool aCancelable,
-                                 nsIDOMWindow* aView,
-                                 uint32_t aDetail,
-                                 const nsAString& aKey,
-                                 uint32_t aLocation,
-                                 const nsAString& aModifiersList,
-                                 bool aRepeat,
-                                 ErrorResult& aRv)
-{
-  aRv = UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
-
-  WidgetKeyboardEvent* keyEvent = mEvent->AsKeyboardEvent();
-  keyEvent->modifiers = UIEvent::ComputeModifierState(aModifiersList);
-  keyEvent->location = aLocation;
-  keyEvent->mIsRepeat = aRepeat;
-  keyEvent->mKeyNameIndex = KEY_NAME_INDEX_USE_STRING;
-  keyEvent->mKeyValue = aKey;
-}
-
 } // namespace dom
 } // namespace mozilla
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsresult
 NS_NewDOMKeyboardEvent(nsIDOMEvent** aInstancePtrResult,
--- a/dom/events/KeyboardEvent.h
+++ b/dom/events/KeyboardEvent.h
@@ -64,23 +64,16 @@ public:
                     uint32_t aKeyCode, uint32_t aCharCode,
                     ErrorResult& aRv)
   {
     aRv = InitKeyEvent(aType, aCanBubble, aCancelable, aView,
                        aCtrlKey, aAltKey, aShiftKey,aMetaKey,
                        aKeyCode, aCharCode);
   }
 
-  void InitKeyboardEvent(const nsAString& aType,
-                         bool aCanBubble, bool aCancelable,
-                         nsIDOMWindow* aView, uint32_t aDetail,
-                         const nsAString& aKey, uint32_t aLocation,
-                         const nsAString& aModifiersList, bool aRepeat,
-                         ErrorResult& aRv);
-
 private:
   // True, if the instance is created with Constructor().
   bool mInitializedByCtor;
   // If the instance is created with Constructor(), which may have independent
   // value.  mInitializedWhichValue stores it.  I.e., this is invalid when
   // mInitializedByCtor is false.
   uint32_t mInitialzedWhichValue;
 };
--- a/dom/events/test/test_dom_keyboard_event.html
+++ b/dom/events/test/test_dom_keyboard_event.html
@@ -15,177 +15,100 @@
 <script type="application/javascript">
 
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(runTests, window);
 
 function testInitializingUntrustedEvent()
 {
   const kTests = [
-    // initKeyEvent
-    { createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
+    { createEventArg: "KeyboardEvent",
       type: "keydown", bubbles: true, cancelable: true, view: null,
       ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 0
+      keyCode: 0x00, charCode: 0x00 },
 
-    { createEventArg: "keyboardevent", useInitKeyboardEvent: false,
+    { createEventArg: "keyboardevent",
       type: "keyup", bubbles: false, cancelable: true, view: window,
       ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
-      keyCode: 0x10, charCode: 0x00,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 1
+      keyCode: 0x10, charCode: 0x00 },
 
-    { createEventArg: "Keyboardevent", useInitKeyboardEvent: false,
+    { createEventArg: "Keyboardevent",
       type: "keypess", bubbles: true, cancelable: false, view: null,
       ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
-      keyCode: 0x11, charCode: 0x30,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 2
+      keyCode: 0x11, charCode: 0x30 },
 
-    { createEventArg: "keyboardEvent", useInitKeyboardEvent: false,
+    { createEventArg: "keyboardEvent",
       type: "boo", bubbles: false, cancelable: false, view: window,
       ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
-      keyCode: 0x30, charCode: 0x40,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 3
+      keyCode: 0x30, charCode: 0x40 },
 
-    { createEventArg: "KeyEvents", useInitKeyboardEvent: false,
+    { createEventArg: "KeyEvents",
       type: "foo", bubbles: true, cancelable: true, view: null,
       ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
-      keyCode: 0x00, charCode: 0x50,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 4
+      keyCode: 0x00, charCode: 0x50 },
 
-    { createEventArg: "keyevents", useInitKeyboardEvent: false,
+    { createEventArg: "keyevents",
       type: "bar", bubbles: false, cancelable: true, view: window,
       ctrlKey: true, altKey: true, shiftKey: false, metaKey: false,
-      keyCode: 0x00, charCode: 0x60,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 5
+      keyCode: 0x00, charCode: 0x60 },
 
-    { createEventArg: "Keyevents", useInitKeyboardEvent: false,
+    { createEventArg: "Keyevents",
       type: "keydown", bubbles: true, cancelable: false, view: null,
       ctrlKey: false, altKey: true, shiftKey: false, metaKey: true,
-      keyCode: 0x30, charCode: 0x00,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 6
+      keyCode: 0x30, charCode: 0x00 },
 
-    { createEventArg: "keyEvents", useInitKeyboardEvent: false,
+    { createEventArg: "keyEvents",
       type: "keyup", bubbles: false, cancelable: false, view: window,
       ctrlKey: true, altKey: false, shiftKey: true, metaKey: false,
-      keyCode: 0x10, charCode: 0x80,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 7
+      keyCode: 0x10, charCode: 0x80 },
 
-    { createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
+    { createEventArg: "KeyboardEvent",
       type: "keypress", bubbles: false, cancelable: false, view: window,
       ctrlKey: true, altKey: false, shiftKey: true, metaKey: true,
-      keyCode: 0x10, charCode: 0x80,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 8
+      keyCode: 0x10, charCode: 0x80 },
 
-    { createEventArg: "KeyboardEvent", useInitKeyboardEvent: false,
+    { createEventArg: "KeyboardEvent",
       type: "foo", bubbles: false, cancelable: false, view: window,
       ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
-      keyCode: 0x10, charCode: 0x80,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 9
-
-    // initKeyboardEvent
-    { createEventArg: "KeyboardEvent", useInitKeyboardEvent: true,
-      type: "keydown", bubbles: true, cancelable: true, view: null,
-      ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 0, key: "", location: 0,  modifiersList: "", repeat: false,
-    }, // 10
-
-    { createEventArg: "keyboardevent", useInitKeyboardEvent: true,
-      type: "keyup", bubbles: false, cancelable: true, view: window,
-      ctrlKey: true, altKey: false, shiftKey: false, metaKey: false,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 2, key: "Unidentified", location: 1,  modifiersList: "Control", repeat: false,
-    }, // 11
-
-    { createEventArg: "Keyboardevent", useInitKeyboardEvent: true,
-      type: "keypess", bubbles: true, cancelable: false, view: null,
-      ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 0, key: "FooBar", location: 2,  modifiersList: "Alt", repeat: true,
-    }, // 12
-
-    { createEventArg: "keyboardevent", useInitKeyboardEvent: true,
-      type: "foo", bubbles: true, cancelable: true, view: null,
-      ctrlKey: false, altKey: false, shiftKey: false, metaKey: true,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 0, key: "a", location: 0,  modifiersList: "Meta", repeat: false,
-    }, // 13
-
-    { createEventArg: "Keyevents", useInitKeyboardEvent: true,
-      type: "", bubbles: false, cancelable: false, view: null,
-      ctrlKey: true, altKey: true, shiftKey: true, metaKey: true,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 0, key: "3", location: 0,  modifiersList: "Control Alt Meta Shift", repeat: true,
-    }, // 14
-
-    { createEventArg: "keyevents", useInitKeyboardEvent: true,
-      type: "", bubbles: false, cancelable: false, view: null,
-      ctrlKey: false, altKey: false, shiftKey: true, metaKey: false,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 0, key: "3", location: 6,  modifiersList: "Shift", repeat: true,
-    }, // 15
-
-    { createEventArg: "keyevents", useInitKeyboardEvent: true,
-      type: "", bubbles: false, cancelable: false, view: null,
-      ctrlKey: false, altKey: true, shiftKey: false, metaKey: false,
-      keyCode: 0x00, charCode: 0x00,
-      detail: 0, key: "", location: 4,  modifiersList: "Shift, Alt", repeat: false,
-    }, // 16
+      keyCode: 0x10, charCode: 0x80 },
   ];
 
   const kOtherModifierName = [
     "CapsLock", "NumLock", "ScrollLock", "SymbolLock", "Fn", "OS", "AltGraph"
   ];
 
   const kInvalidModifierName = [
     "shift", "control", "alt", "meta", "capslock", "numlock", "scrolllock",
     "symbollock", "fn", "os", "altgraph", "Invalid", "Shift Control",
     "Win", "Scroll"
   ];
 
   for (var i = 0; i < kTests.length; i++) {
     var description = "testInitializingUntrustedEvent, Index: " + i + ", ";
     const kTest = kTests[i];
     var e = document.createEvent(kTest.createEventArg);
-    if (kTest.useInitKeyboardEvent) {
-      // IE has extra argument for |.locale|.  Calling with it shouldn't cause error for compatibility with IE.
-      e.initKeyboardEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view, kTest.detail,
-                          kTest.key, kTest.location, kTest.modifiersList, kTest.repeat, "locale");
-    } else {
-      e.initKeyEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view,
-                     kTest.ctrlKey, kTest.altKey, kTest.shiftKey, kTest.metaKey,
-                     kTest.keyCode, kTest.charCode);
-    }
+    e.initKeyEvent(kTest.type, kTest.bubbles, kTest.cancelable, kTest.view,
+                   kTest.ctrlKey, kTest.altKey, kTest.shiftKey, kTest.metaKey,
+                   kTest.keyCode, kTest.charCode);
     is(e.toString(), "[object KeyboardEvent]",
        description + 'class string should be "KeyboardEvent"');
 
     for (var attr in kTest) {
-      if (attr == "createEventArg" || attr == "useInitKeyboardEvent" || attr == "modifiersList") {
+      if (attr == "createEventArg") {
         continue;
       }
-      if (!kTest.useInitKeyboardEvent && attr == "keyCode") {
+      if (attr == "keyCode") {
         // If this is keydown, keyup of keypress event, keycod must be correct.
         if (kTest.type == "keydown" || kTest.type == "keyup" || kTest.type == "keypress") {
           is(e[attr], kTest[attr], description + attr + " returns wrong value");
         // Otherwise, should be always zero (why?)
         } else {
           is(e[attr], 0, description + attr + " returns non-zero for invalid event");
         }
-      } else if (!kTest.useInitKeyboardEvent && attr == "charCode") {
+      } else if (attr == "charCode") {
         // If this is keydown or keyup event, charCode always 0.
         if (kTest.type == "keydown" || kTest.type == "keyup") {
           is(e[attr], 0, description + attr + " returns non-zero for keydown or keyup event");
         // If this is keypress event, charCode must be correct.
         } else if (kTest.type == "keypress") {
           is(e[attr], kTest[attr], description + attr + " returns wrong value");
         // Otherwise, we have a bug.
         } else {
@@ -194,16 +117,19 @@ function testInitializingUntrustedEvent(
           }
         }
       } else {
         is(e[attr], kTest[attr], description + attr + " returns wrong value");
       }
     }
     is(e.isTrusted, false, description + "isTrusted returns wrong value");
 
+    // Currently, there is no way to initialize char and key attribute values.
+    ok(e.key === "", description + "key must return empty string - got " + e.key);
+
     // getModifierState() tests
     is(e.getModifierState("Shift"), kTest.shiftKey,
        description + "getModifierState(\"Shift\") returns wrong value");
     is(e.getModifierState("Control"), kTest.ctrlKey,
        description + "getModifierState(\"Control\") returns wrong value");
     is(e.getModifierState("Alt"), kTest.altKey,
        description + "getModifierState(\"Alt\") returns wrong value");
     is(e.getModifierState("Meta"), kTest.metaKey,
--- a/dom/events/test/test_error_events.html
+++ b/dom/events/test/test_error_events.html
@@ -32,18 +32,18 @@
     [ "Event filename", errorEvent.filename, location.href ],
     [ "Callback filename", file, location.href ],
     [ "Event line number", errorEvent.lineno, 27 ],
     [ "Callback line number", line, 27 ],
     [ "Event message", errorEvent.message, "Error: hello" ],
     [ "Callback message", msg, "Error: hello" ],
     [ "Event error-object", errorEvent.error, thrown],
     [ "Callback error-object", error, thrown ],
-    [ "Event column", errorEvent.colno, 0 ], // Sadly not correct right now
-    [ "Callback column", column, 0 ]
+    [ "Event column", errorEvent.colno, 6 ], // Sadly not correct right now
+    [ "Callback column", column, 6 ]
   ]);
 </script>
 <script>
   var workerLocation = location.protocol + "//" + location.host +
     location.pathname.replace("test_error_events.html", "error_event_worker.js");
   var eventFileTest = async_test("Worker event filename");
   var eventLineTest = async_test("Worker event line number");
   var eventMessageTest = async_test("Worker event message");
--- a/dom/interfaces/base/nsIDOMWindowCollection.idl
+++ b/dom/interfaces/base/nsIDOMWindowCollection.idl
@@ -5,17 +5,17 @@
 
 #include "domstubs.idl"
 
 /**
  * The nsIDOMWindowCollection interface is an interface for a
  * collection of DOM window objects.
  */
 
-[scriptable, uuid(a6cf906f-15b3-11d2-932e-00805f8add32)]
+[uuid(a6cf906f-15b3-11d2-932e-00805f8add32)]
 interface nsIDOMWindowCollection : nsISupports
 {
   /**
    * Accessor for the number of windows in this collection.
    */
   readonly attribute unsigned long    length;
 
   /**
--- a/dom/interfaces/xpath/moz.build
+++ b/dom/interfaces/xpath/moz.build
@@ -3,15 +3,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/.
 
 XPIDL_SOURCES += [
     'nsIDOMNSXPathExpression.idl',
     'nsIDOMXPathEvaluator.idl',
     'nsIDOMXPathExpression.idl',
-    'nsIDOMXPathNamespace.idl',
     'nsIDOMXPathNSResolver.idl',
     'nsIDOMXPathResult.idl',
 ]
 
 XPIDL_MODULE = 'dom_xpath'
 
deleted file mode 100644
--- a/dom/interfaces/xpath/nsIDOMXPathNamespace.idl
+++ /dev/null
@@ -1,19 +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/. */
-
-/**
- * Corresponds to http://www.w3.org/TR/2002/WD-DOM-Level-3-XPath-20020208
- */
-
-#include "nsIDOMNode.idl"
-
-[scriptable, uuid(558c2ab9-513e-43c2-afea-4930024b15b3)]
-interface nsIDOMXPathNamespace : nsIDOMNode
-{
-  // XPathNodeType
-  const unsigned short      XPATH_NAMESPACE_NODE           = 13;
-
-  readonly attribute nsIDOMElement          ownerElement;
-};
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -742,16 +742,17 @@ TabChild::Observe(nsISupports *aSubject,
     }
   } else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
     if (IsAsyncPanZoomEnabled()) {
       nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
       nsCOMPtr<nsIDocument> doc(GetDocument());
 
       if (SameCOMIdentity(subject, doc)) {
         nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
+        utils->SetIsFirstPaint(true);
 
         mContentDocumentIsDisplayed = true;
 
         // Reset CSS viewport and zoom to default on new page, then
         // calculate them properly using the actual metadata from the
         // page.
         SetCSSViewport(kDefaultViewportSize);
 
@@ -805,19 +806,16 @@ TabChild::OnLocationChange(nsIWebProgres
   }
 
   nsCOMPtr<nsIDOMWindow> window;
   aWebProgress->GetDOMWindow(getter_AddRefs(window));
   if (!window) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(window));
-  utils->SetIsFirstPaint(true);
-
   nsCOMPtr<nsIDOMDocument> progressDoc;
   window->GetDocument(getter_AddRefs(progressDoc));
   if (!progressDoc) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIDOMDocument> domDoc;
   WebNavigation()->GetDocument(getter_AddRefs(domDoc));
--- a/dom/system/gonk/tests/marionette/ril_jshint/jshint.js
+++ b/dom/system/gonk/tests/marionette/ril_jshint/jshint.js
@@ -579,17 +579,16 @@ exports.browser = {
 	WebSocket            : false,
 	window               : false,
 	Worker               : false,
 	XMLHttpRequest       : false,
 	XMLSerializer        : false,
 	XPathEvaluator       : false,
 	XPathException       : false,
 	XPathExpression      : false,
-	XPathNamespace       : false,
 	XPathNSResolver      : false,
 	XPathResult          : false
 };
 
 exports.devel = {
 	alert  : false,
 	confirm: false,
 	console: false,
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -1185,18 +1185,16 @@ var interfaceNamesInGlobalScope =
     "XMLSerializer",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "XMLStylesheetProcessingInstruction",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "XPathEvaluator",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "XPathExpression",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "XPathNamespace",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "XPathNSResolver",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "XPathResult",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "XSLTProcessor",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "XULButtonElement", xbl: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/KeyboardEvent.webidl
+++ b/dom/webidl/KeyboardEvent.webidl
@@ -26,27 +26,16 @@ interface KeyboardEvent : UIEvent
   const unsigned long DOM_KEY_LOCATION_MOBILE   = 0x04;
   const unsigned long DOM_KEY_LOCATION_JOYSTICK = 0x05;
 
   readonly attribute unsigned long location;
   readonly attribute boolean       repeat;
   readonly attribute boolean       isComposing;
 
   readonly attribute DOMString key;
-
-  [Throws]
-  void initKeyboardEvent(DOMString typeArg,
-                         boolean bubblesArg,
-                         boolean cancelableArg,
-                         WindowProxy? viewArg,
-                         long detailArg,
-                         DOMString keyArg,
-                         unsigned long locationArg,
-                         DOMString modifiersListArg,
-                         boolean repeatArg);
 };
 
 dictionary KeyboardEventInit : UIEventInit
 {
   DOMString      key           = "";
   unsigned long  location      = 0;
   boolean        ctrlKey       = false;
   boolean        shiftKey      = false;
--- a/dom/xbl/nsXBLPrototypeResources.cpp
+++ b/dom/xbl/nsXBLPrototypeResources.cpp
@@ -61,26 +61,33 @@ nsXBLPrototypeResources::AddResourceList
 nsresult
 nsXBLPrototypeResources::FlushSkinSheets()
 {
   if (mStyleSheetList.Length() == 0)
     return NS_OK;
 
   nsCOMPtr<nsIDocument> doc =
     mLoader->mBinding->XBLDocumentInfo()->GetDocument();
-  mozilla::css::Loader* cssLoader = doc->CSSLoader();
+
+  // If doc is null, we're in the process of tearing things down, so just
+  // return without rebuilding anything.
+  if (!doc) {
+    return NS_OK;
+  }
 
   // We have scoped stylesheets.  Reload any chrome stylesheets we
   // encounter.  (If they aren't skin sheets, it doesn't matter, since
   // they'll still be in the chrome cache.
   mRuleProcessor = nullptr;
 
   sheet_array_type oldSheets(mStyleSheetList);
   mStyleSheetList.Clear();
 
+  mozilla::css::Loader* cssLoader = doc->CSSLoader();
+
   for (sheet_array_type::size_type i = 0, count = oldSheets.Length();
        i < count; ++i) {
     nsCSSStyleSheet* oldSheet = oldSheets[i];
 
     nsIURI* uri = oldSheet->GetSheetURI();
 
     nsRefPtr<nsCSSStyleSheet> newSheet;
     if (IsChromeURI(uri)) {
--- a/dom/xslt/xpath/nsXPathExpression.cpp
+++ b/dom/xslt/xpath/nsXPathExpression.cpp
@@ -5,17 +5,16 @@
 
 #include "nsXPathExpression.h"
 #include "txExpr.h"
 #include "txExprResult.h"
 #include "nsError.h"
 #include "nsIDOMCharacterData.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIDOMDocument.h"
-#include "nsIDOMXPathNamespace.h"
 #include "nsXPathResult.h"
 #include "txURIUtils.h"
 #include "txXPathTreeWalker.h"
 
 NS_IMPL_CYCLE_COLLECTION_1(nsXPathExpression, mDocument)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPathExpression)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPathExpression)
@@ -89,18 +88,17 @@ nsXPathExpression::EvaluateWithContext(n
 
         // XXX Need to get logical XPath text node for CDATASection
         //     and Text nodes.
     }
     else if (nodeType != nsIDOMNode::DOCUMENT_NODE &&
              nodeType != nsIDOMNode::ELEMENT_NODE &&
              nodeType != nsIDOMNode::ATTRIBUTE_NODE &&
              nodeType != nsIDOMNode::COMMENT_NODE &&
-             nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE &&
-             nodeType != nsIDOMXPathNamespace::XPATH_NAMESPACE_NODE) {
+             nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) {
         return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
 
     NS_ENSURE_ARG(aResult);
     *aResult = nullptr;
 
     nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode));
     if (!contextNode) {
--- a/editor/libeditor/base/DeleteRangeTxn.cpp
+++ b/editor/libeditor/base/DeleteRangeTxn.cpp
@@ -2,31 +2,32 @@
 /* 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 "DeleteNodeTxn.h"
 #include "DeleteRangeTxn.h"
 #include "DeleteTextTxn.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/mozalloc.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsEditor.h"
 #include "nsError.h"
 #include "nsIContent.h"
 #include "nsIContentIterator.h"
 #include "nsIDOMCharacterData.h"
 #include "nsINode.h"
 #include "nsAString.h"
 
 class nsIDOMRange;
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 // note that aEditor is not refcounted
 DeleteRangeTxn::DeleteRangeTxn()
   : EditAggregateTxn(),
     mRange(),
     mEditor(nullptr),
     mRangeUpdater(nullptr)
 {
--- a/editor/libeditor/base/DeleteTextTxn.cpp
+++ b/editor/libeditor/base/DeleteTextTxn.cpp
@@ -1,27 +1,28 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DeleteTextTxn.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsAutoPtr.h"
 #include "nsDebug.h"
 #include "nsEditor.h"
 #include "nsError.h"
 #include "nsIEditor.h"
 #include "nsISelection.h"
 #include "nsISupportsImpl.h"
 #include "nsSelectionState.h"
 #include "nsAString.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 DeleteTextTxn::DeleteTextTxn() :
   EditTxn(),
   mEditor(nullptr),
   mCharData(),
   mOffset(0),
   mNumCharsToDelete(0),
   mRangeUpdater(nullptr)
--- a/editor/libeditor/base/PlaceholderTxn.cpp
+++ b/editor/libeditor/base/PlaceholderTxn.cpp
@@ -2,19 +2,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PlaceholderTxn.h"
 #include "nsEditor.h"
 #include "IMETextTxn.h"
 #include "nsGkAtoms.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 PlaceholderTxn::PlaceholderTxn() :  EditAggregateTxn(), 
                                     mAbsorb(true), 
                                     mForwarding(nullptr),
                                     mIMETextTxn(nullptr),
                                     mCommitted(false),
                                     mStartSel(nullptr),
                                     mEndSel(),
--- a/editor/libeditor/base/nsEditRules.h
+++ b/editor/libeditor/base/nsEditRules.h
@@ -43,17 +43,17 @@ public:
 
   NS_IMETHOD Init(nsPlaintextEditor *aEditor)=0;
   NS_IMETHOD SetInitialValue(const nsAString& aValue) = 0;
   NS_IMETHOD DetachEditor()=0;
   NS_IMETHOD BeforeEdit(EditAction action,
                         nsIEditor::EDirection aDirection) = 0;
   NS_IMETHOD AfterEdit(EditAction action,
                        nsIEditor::EDirection aDirection) = 0;
-  NS_IMETHOD WillDoAction(mozilla::Selection* aSelection, nsRulesInfo* aInfo,
+  NS_IMETHOD WillDoAction(mozilla::dom::Selection* aSelection, nsRulesInfo* aInfo,
                           bool* aCancel, bool* aHandled) = 0;
   NS_IMETHOD DidDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult)=0;
   NS_IMETHOD DocumentIsEmpty(bool *aDocumentIsEmpty)=0;
   NS_IMETHOD DocumentModified()=0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIEditRules, NS_IEDITRULES_IID)
 
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -21,17 +21,17 @@
 #include "JoinElementTxn.h"             // for JoinElementTxn
 #include "PlaceholderTxn.h"             // for PlaceholderTxn
 #include "SplitElementTxn.h"            // for SplitElementTxn
 #include "mozFlushType.h"               // for mozFlushType::Flush_Frames
 #include "mozISpellCheckingEngine.h"
 #include "mozInlineSpellChecker.h"      // for mozInlineSpellChecker
 #include "mozilla/IMEStateManager.h"    // for IMEStateManager
 #include "mozilla/Preferences.h"        // for Preferences
-#include "mozilla/Selection.h"          // for Selection, etc
+#include "mozilla/dom/Selection.h"      // for Selection, etc
 #include "mozilla/Services.h"           // for GetObserverService
 #include "mozilla/TextComposition.h"    // for TextComposition
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"        // for Element, nsINode::AsElement
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsAString.h"                  // for nsAString_internal::Length, etc
 #include "nsCCUncollectableMarker.h"    // for nsCCUncollectableMarker
 #include "nsCaret.h"                    // for nsCaret
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -62,23 +62,23 @@ class nsISelection;
 class nsISupports;
 class nsITransaction;
 class nsIWidget;
 class nsRange;
 class nsString;
 class nsTransactionManager;
 
 namespace mozilla {
-class Selection;
 class TextComposition;
 
 namespace dom {
 class DataTransfer;
 class Element;
 class EventTarget;
+class Selection;
 }  // namespace dom
 }  // namespace mozilla
 
 namespace mozilla {
 namespace widget {
 struct IMEState;
 } // namespace widget
 } // namespace mozilla
@@ -430,17 +430,17 @@ public:
 
   /** All editor operations which alter the doc should be followed
    *  with a call to EndOperation */
   NS_IMETHOD EndOperation();
 
   /** routines for managing the preservation of selection across 
    *  various editor actions */
   bool     ArePreservingSelection();
-  void     PreserveSelectionAcrossActions(mozilla::Selection* aSel);
+  void     PreserveSelectionAcrossActions(mozilla::dom::Selection* aSel);
   nsresult RestorePreservedSelection(nsISelection *aSel);
   void     StopPreservingSelection();
 
   /** 
    * SplitNode() creates a new node identical to an existing node, and split the contents between the two nodes
    * @param aExistingRightNode   the node to split.  It will become the new node's next sibling.
    * @param aOffset              the offset of aExistingRightNode's content|children to do the split at
    * @param aNewLeftNode         [OUT] the new node resulting from the split, becomes aExistingRightNode's previous sibling.
@@ -618,27 +618,27 @@ public:
 
   static bool IsTextNode(nsIDOMNode *aNode);
   static bool IsTextNode(nsINode *aNode);
   
   static nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, int32_t aOffset);
   static nsCOMPtr<nsIDOMNode> GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, int32_t aOffset);
 
   static nsresult GetStartNodeAndOffset(nsISelection *aSelection, nsIDOMNode **outStartNode, int32_t *outStartOffset);
-  static nsresult GetStartNodeAndOffset(mozilla::Selection* aSelection,
+  static nsresult GetStartNodeAndOffset(mozilla::dom::Selection* aSelection,
                                         nsINode** aStartNode,
                                         int32_t* aStartOffset);
   static nsresult GetEndNodeAndOffset(nsISelection *aSelection, nsIDOMNode **outEndNode, int32_t *outEndOffset);
-  static nsresult GetEndNodeAndOffset(mozilla::Selection* aSelection,
+  static nsresult GetEndNodeAndOffset(mozilla::dom::Selection* aSelection,
                                       nsINode** aEndNode,
                                       int32_t* aEndOffset);
 #if DEBUG_JOE
   static void DumpNode(nsIDOMNode *aNode, int32_t indent=0);
 #endif
-  mozilla::Selection* GetSelection();
+  mozilla::dom::Selection* GetSelection();
 
   // Helpers to add a node to the selection. 
   // Used by table cell selection methods
   nsresult CreateRange(nsIDOMNode *aStartParent, int32_t aStartOffset,
                        nsIDOMNode *aEndParent, int32_t aEndOffset,
                        nsIDOMRange **aRange);
 
   // Creates a range with just the supplied node and appends that to the selection
--- a/editor/libeditor/base/nsEditorUtils.cpp
+++ b/editor/libeditor/base/nsEditorUtils.cpp
@@ -1,14 +1,14 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsCOMArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsEditorUtils.h"
 #include "nsError.h"
 #include "nsIClipboardDragDropHookList.h"
 // hooks
 #include "nsIClipboardDragDropHooks.h"
 #include "nsIContent.h"
@@ -19,16 +19,17 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsINode.h"
 #include "nsISimpleEnumerator.h"
 
 class nsIDOMRange;
 class nsISupports;
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 /******************************************************************************
  * nsAutoSelectionReset
  *****************************************************************************/
 
 nsAutoSelectionReset::nsAutoSelectionReset(Selection* aSel, nsEditor* aEd)
   : mSel(nullptr), mEd(nullptr)
 { 
--- a/editor/libeditor/base/nsEditorUtils.h
+++ b/editor/libeditor/base/nsEditorUtils.h
@@ -51,22 +51,22 @@ class MOZ_STACK_CLASS nsAutoEditBatch : 
 /***************************************************************************
  * stack based helper class for saving/restoring selection.  Note that this
  * assumes that the nodes involved are still around afterwards!
  */
 class MOZ_STACK_CLASS nsAutoSelectionReset
 {
   private:
     /** ref-counted reference to the selection that we are supposed to restore */
-    nsRefPtr<mozilla::Selection> mSel;
+    nsRefPtr<mozilla::dom::Selection> mSel;
     nsEditor *mEd;  // non-owning ref to nsEditor
 
   public:
     /** constructor responsible for remembering all state needed to restore aSel */
-    nsAutoSelectionReset(mozilla::Selection* aSel, nsEditor* aEd);
+    nsAutoSelectionReset(mozilla::dom::Selection* aSel, nsEditor* aEd);
     
     /** destructor restores mSel to its former state */
     ~nsAutoSelectionReset();
 
     /** Abort: cancel selection saver */
     void Abort();
 };
 
--- a/editor/libeditor/base/nsSelectionState.cpp
+++ b/editor/libeditor/base/nsSelectionState.cpp
@@ -1,31 +1,32 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
-#include "mozilla/Selection.h"          // for Selection
+#include "mozilla/dom/Selection.h"      // for Selection
 #include "nsAString.h"                  // for nsAString_internal::Length
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCycleCollectionParticipant.h"
 #include "nsDebug.h"                    // for NS_ENSURE_TRUE, etc
 #include "nsEditor.h"                   // for nsEditor
 #include "nsEditorUtils.h"              // for nsEditorUtils
 #include "nsError.h"                    // for NS_OK, etc
 #include "nsIDOMCharacterData.h"        // for nsIDOMCharacterData
 #include "nsIDOMNode.h"                 // for nsIDOMNode
 #include "nsIDOMRange.h"                // for nsIDOMRange, etc
 #include "nsISelection.h"               // for nsISelection
 #include "nsISupportsImpl.h"            // for nsRange::Release
 #include "nsRange.h"                    // for nsRange
 #include "nsSelectionState.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 /***************************************************************************
  * class for recording selection info.  stores selection as collection of
  * { {startnode, startoffset} , {endnode, endoffset} } tuples.  Can't store
  * ranges since dom gravity will possibly change the ranges.
  */
 nsSelectionState::nsSelectionState() : mArray(){}
 
--- a/editor/libeditor/base/nsSelectionState.h
+++ b/editor/libeditor/base/nsSelectionState.h
@@ -13,18 +13,20 @@
 #include "nscore.h"
 
 class nsCycleCollectionTraversalCallback;
 class nsIDOMCharacterData;
 class nsIDOMRange;
 class nsISelection;
 class nsRange;
 namespace mozilla {
+namespace dom {
 class Selection;
 }
+}
 
 /***************************************************************************
  * class for recording selection info.  stores selection as collection of
  * { {startnode, startoffset} , {endnode, endoffset} } tuples.  Can't store
  * ranges since dom gravity will possibly change the ranges.
  */
 
 // first a helper struct for saving/setting ranges
@@ -54,17 +56,17 @@ class nsSelectionState
   public:
       
     nsSelectionState();
     ~nsSelectionState();
 
     void DoTraverse(nsCycleCollectionTraversalCallback &cb);
     void DoUnlink() { MakeEmpty(); }
   
-    void     SaveSelection(mozilla::Selection *aSel);
+    void     SaveSelection(mozilla::dom::Selection *aSel);
     nsresult RestoreSelection(nsISelection *aSel);
     bool     IsCollapsed();
     bool     IsEqual(nsSelectionState *aSelState);
     void     MakeEmpty();
     bool     IsEmpty();
   protected:    
     nsTArray<nsRefPtr<nsRangeStore> > mArray;
     
--- a/editor/libeditor/html/nsHTMLAbsPosition.cpp
+++ b/editor/libeditor/html/nsHTMLAbsPosition.cpp
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <math.h>
 
 #include "mozilla/Preferences.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsComputedDOMStyle.h"
 #include "nsDebug.h"
@@ -47,16 +47,17 @@
 #include "nsString.h"
 #include "nsStringFwd.h"
 #include "nsTextEditRules.h"
 #include "nsTextEditUtils.h"
 #include "nscore.h"
 #include <algorithm>
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 #define  BLACK_BG_RGB_TRIGGER 0xd0
 
 NS_IMETHODIMP
 nsHTMLEditor::AbsolutePositionSelection(bool aEnabled)
 {
   nsAutoEditBatch beginBatching(this);
   nsAutoRules beginRulesSniffing(this,
--- a/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -6,17 +6,17 @@
 
 #include <string.h>
 
 #include "mozilla/dom/DocumentFragment.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Base64.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsAString.h"
 #include "nsAutoPtr.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsComponentManagerUtils.h"
 #include "nsContentUtils.h"
--- a/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -4,17 +4,17 @@
  * 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 <stdlib.h>
 
 #include "mozilla/Assertions.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
 #include "nsCOMArray.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsComponentManagerUtils.h"
@@ -56,16 +56,17 @@
 #include "nsUnicharUtils.h"
 #include "nsWSRunObject.h"
 #include <algorithm>
 
 class nsISupports;
 class nsRulesInfo;
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 //const static char* kMOZEditorBogusNodeAttr="MOZ_EDITOR_BOGUS_NODE";
 //const static char* kMOZEditorBogusNodeValue="TRUE";
 
 enum
 {
   kLonely = 0,
   kPrevSib = 1,
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -28,19 +28,19 @@ class nsIDOMNode;
 class nsIDOMRange;
 class nsIEditor;
 class nsINode;
 class nsISelection;
 class nsPlaintextEditor;
 class nsRange;
 class nsRulesInfo;
 namespace mozilla {
-class Selection;
 namespace dom {
 class Element;
+class Selection;
 }  // namespace dom
 }  // namespace mozilla
 struct DOMPoint;
 template <class E> class nsCOMArray;
 
 struct StyleCache : public PropItem
 {
   bool mPresent;
@@ -74,17 +74,17 @@ public:
 
   // nsIEditRules methods
   NS_IMETHOD Init(nsPlaintextEditor *aEditor);
   NS_IMETHOD DetachEditor();
   NS_IMETHOD BeforeEdit(EditAction action,
                         nsIEditor::EDirection aDirection);
   NS_IMETHOD AfterEdit(EditAction action,
                        nsIEditor::EDirection aDirection);
-  NS_IMETHOD WillDoAction(mozilla::Selection* aSelection, nsRulesInfo* aInfo,
+  NS_IMETHOD WillDoAction(mozilla::dom::Selection* aSelection, nsRulesInfo* aInfo,
                           bool* aCancel, bool* aHandled);
   NS_IMETHOD DidDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
   NS_IMETHOD DocumentModified();
 
   nsresult GetListState(bool *aMixed, bool *aOL, bool *aUL, bool *aDL);
   nsresult GetListItemState(bool *aMixed, bool *aLI, bool *aDT, bool *aDD);
   nsresult GetIndentState(bool *aCanIndent, bool *aCanOutdent);
   nsresult GetAlignment(bool *aMixed, nsIHTMLEditor::EAlignment *aAlign);
@@ -122,73 +122,73 @@ protected:
   {
     kBeforeBlock,
     kBlockEnd
   };
 
   // nsHTMLEditRules implementation methods
   nsresult WillInsert(nsISelection *aSelection, bool *aCancel);
   nsresult WillInsertText(  EditAction aAction,
-                            mozilla::Selection* aSelection,
+                            mozilla::dom::Selection* aSelection,
                             bool            *aCancel,
                             bool            *aHandled,
                             const nsAString *inString,
                             nsAString       *outString,
                             int32_t          aMaxLength);
   nsresult WillLoadHTML(nsISelection *aSelection, bool *aCancel);
-  nsresult WillInsertBreak(mozilla::Selection* aSelection,
+  nsresult WillInsertBreak(mozilla::dom::Selection* aSelection,
                            bool* aCancel, bool* aHandled);
   nsresult StandardBreakImpl(nsIDOMNode *aNode, int32_t aOffset, nsISelection *aSelection);
   nsresult DidInsertBreak(nsISelection *aSelection, nsresult aResult);
   nsresult SplitMailCites(nsISelection *aSelection, bool aPlaintext, bool *aHandled);
-  nsresult WillDeleteSelection(mozilla::Selection* aSelection,
+  nsresult WillDeleteSelection(mozilla::dom::Selection* aSelection,
                                nsIEditor::EDirection aAction,
                                nsIEditor::EStripWrappers aStripWrappers,
                                bool* aCancel, bool* aHandled);
   nsresult DidDeleteSelection(nsISelection *aSelection, 
                               nsIEditor::EDirection aDir, 
                               nsresult aResult);
   nsresult InsertBRIfNeeded(nsISelection *aSelection);
   nsresult GetGoodSelPointForNode(nsIDOMNode *aNode, nsIEditor::EDirection aAction, 
                                   nsCOMPtr<nsIDOMNode> *outSelNode, int32_t *outSelOffset);
   nsresult JoinBlocks(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, bool *aCanceled);
   nsresult MoveBlock(nsIDOMNode *aLeft, nsIDOMNode *aRight, int32_t aLeftOffset, int32_t aRightOffset);
   nsresult MoveNodeSmart(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset);
   nsresult MoveContents(nsIDOMNode *aSource, nsIDOMNode *aDest, int32_t *aOffset);
   nsresult DeleteNonTableElements(nsINode* aNode);
-  nsresult WillMakeList(mozilla::Selection* aSelection,
+  nsresult WillMakeList(mozilla::dom::Selection* aSelection,
                         const nsAString* aListType,
                         bool aEntireList,
                         const nsAString* aBulletType,
                         bool* aCancel, bool* aHandled,
                         const nsAString* aItemType = nullptr);
-  nsresult WillRemoveList(mozilla::Selection* aSelection,
+  nsresult WillRemoveList(mozilla::dom::Selection* aSelection,
                           bool aOrdered, bool* aCancel, bool* aHandled);
-  nsresult WillIndent(mozilla::Selection* aSelection,
+  nsresult WillIndent(mozilla::dom::Selection* aSelection,
                       bool* aCancel, bool* aHandled);
-  nsresult WillCSSIndent(mozilla::Selection* aSelection,
+  nsresult WillCSSIndent(mozilla::dom::Selection* aSelection,
                          bool* aCancel, bool* aHandled);
-  nsresult WillHTMLIndent(mozilla::Selection* aSelection,
+  nsresult WillHTMLIndent(mozilla::dom::Selection* aSelection,
                           bool* aCancel, bool* aHandled);
-  nsresult WillOutdent(mozilla::Selection* aSelection,
+  nsresult WillOutdent(mozilla::dom::Selection* aSelection,
                        bool* aCancel, bool* aHandled);
-  nsresult WillAlign(mozilla::Selection* aSelection,
+  nsresult WillAlign(mozilla::dom::Selection* aSelection,
                      const nsAString* alignType,
                      bool* aCancel, bool* aHandled);
-  nsresult WillAbsolutePosition(mozilla::Selection* aSelection,
+  nsresult WillAbsolutePosition(mozilla::dom::Selection* aSelection,
                                 bool* aCancel, bool* aHandled);
-  nsresult WillRemoveAbsolutePosition(mozilla::Selection* aSelection,
+  nsresult WillRemoveAbsolutePosition(mozilla::dom::Selection* aSelection,
                                       bool* aCancel, bool* aHandled);
-  nsresult WillRelativeChangeZIndex(mozilla::Selection* aSelection,
+  nsresult WillRelativeChangeZIndex(mozilla::dom::Selection* aSelection,
                                     int32_t aChange,
                                     bool* aCancel, bool* aHandled);
-  nsresult WillMakeDefListItem(mozilla::Selection* aSelection,
+  nsresult WillMakeDefListItem(mozilla::dom::Selection* aSelection,
                                const nsAString* aBlockType, bool aEntireList,
                                bool* aCancel, bool* aHandled);
-  nsresult WillMakeBasicBlock(mozilla::Selection* aSelection,
+  nsresult WillMakeBasicBlock(mozilla::dom::Selection* aSelection,
                               const nsAString* aBlockType,
                               bool* aCancel, bool* aHandled);
   nsresult DidMakeBasicBlock(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
   nsresult DidAbsolutePosition();
   nsresult AlignInnerBlocks(nsIDOMNode *aNode, const nsAString *alignType);
   nsresult AlignBlockContents(nsIDOMNode *aNode, const nsAString *alignType);
   nsresult AppendInnerFormatNodes(nsCOMArray<nsIDOMNode>& aArray,
                                   nsINode* aNode);
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -64,23 +64,24 @@
 #include "TextEditorTest.h"
 #include "nsEditorUtils.h"
 #include "nsWSRunObject.h"
 #include "nsGkAtoms.h"
 #include "nsIWidget.h"
 
 #include "nsIFrame.h"
 #include "nsIParserService.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/HTMLBodyElement.h"
 #include "nsTextFragment.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::widget;
 
 // Some utilities to handle annoying overloading of "A" tag for link and named anchor
 static char hrefText[] = "href";
 static char anchorTxt[] = "anchor";
 static char namedanchorText[] = "namedanchor";
 
 #define IsLinkTag(s) (s.EqualsIgnoreCase(hrefText))
--- a/editor/libeditor/html/nsHTMLEditorStyle.cpp
+++ b/editor/libeditor/html/nsHTMLEditorStyle.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "TypeInState.h"
 #include "mozilla/Assertions.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAttrName.h"
 #include "nsAutoPtr.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
 #include "nsCaseTreatment.h"
@@ -47,16 +47,17 @@
 #include "nsTextEditRules.h"
 #include "nsTextEditUtils.h"
 #include "nsUnicharUtils.h"
 #include "nscore.h"
 
 class nsISupports;
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 static bool
 IsEmptyTextNode(nsHTMLEditor* aThis, nsINode* aNode)
 {
   bool isEmptyTextNode = false;
   return nsEditor::IsTextNode(aNode) &&
          NS_SUCCEEDED(aThis->IsEmptyNode(aNode, &isEmptyTextNode)) &&
          isEmptyTextNode;
--- a/editor/libeditor/html/nsTableEditor.cpp
+++ b/editor/libeditor/html/nsTableEditor.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdio.h>
 
 #include "mozilla/Assertions.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsEditProperty.h"
 #include "nsEditor.h"
 #include "nsEditorUtils.h"
@@ -37,16 +37,17 @@
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsTableCellFrame.h"
 #include "nsTableOuterFrame.h"
 #include "nscore.h"
 #include <algorithm>
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 /***************************************************************************
  * stack based helper class for restoring selection after table edit
  */
 class MOZ_STACK_CLASS nsSetSelectionAfterTableEdit
 {
   private:
     nsCOMPtr<nsITableEditor> mEd;
--- a/editor/libeditor/html/nsWSRunObject.h
+++ b/editor/libeditor/html/nsWSRunObject.h
@@ -331,27 +331,27 @@ class MOZ_STACK_CLASS nsWSRunObject
     nsresult AppendNodeToList(nsIDOMNode *aNode);
     nsresult GetPreviousWSNode(nsIDOMNode *aStartNode, 
                                nsIDOMNode *aBlockParent, 
                                nsCOMPtr<nsIDOMNode> *aPriorNode);
     nsresult GetPreviousWSNode(nsIDOMNode *aStartNode,
                                int32_t      aOffset,
                                nsIDOMNode  *aBlockParent, 
                                nsCOMPtr<nsIDOMNode> *aPriorNode);
-    nsresult GetPreviousWSNode(DOMPoint aPoint,
+    nsresult GetPreviousWSNode(::DOMPoint aPoint,
                                nsIDOMNode  *aBlockParent, 
                                nsCOMPtr<nsIDOMNode> *aPriorNode);
     nsresult GetNextWSNode(nsIDOMNode *aStartNode, 
                            nsIDOMNode *aBlockParent, 
                            nsCOMPtr<nsIDOMNode> *aNextNode);
     nsresult GetNextWSNode(nsIDOMNode *aStartNode,
                            int32_t     aOffset,
                            nsIDOMNode *aBlockParent, 
                            nsCOMPtr<nsIDOMNode> *aNextNode);
-    nsresult GetNextWSNode(DOMPoint aPoint,
+    nsresult GetNextWSNode(::DOMPoint aPoint,
                            nsIDOMNode  *aBlockParent, 
                            nsCOMPtr<nsIDOMNode> *aNextNode);
     nsresult PrepareToDeleteRangePriv(nsWSRunObject* aEndObject);
     nsresult PrepareToSplitAcrossBlocksPriv();
     nsresult DeleteChars(nsIDOMNode *aStartNode, int32_t aStartOffset, 
                          nsIDOMNode *aEndNode, int32_t aEndOffset,
                          AreaRestriction aAR = eAnywhere);
     WSPoint  GetCharAfter(nsIDOMNode *aNode, int32_t aOffset);
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
 #include "nsCaret.h"
@@ -59,16 +59,17 @@
 #include "nsUnicharUtils.h"
 #include "nsXPCOM.h"
 
 class nsIOutputStream;
 class nsISupports;
 class nsISupportsArray;
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 nsPlaintextEditor::nsPlaintextEditor()
 : nsEditor()
 , mRules(nullptr)
 , mWrapToWindow(false)
 , mWrapColumn(0)
 , mMaxTextLength(-1)
 , mInitTriggerCounter(0)
--- a/editor/libeditor/text/nsTextEditRules.cpp
+++ b/editor/libeditor/text/nsTextEditRules.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/TextComposition.h"
 #include "mozilla/dom/Element.h"
 #include "nsAString.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsComponentManagerUtils.h"
@@ -38,16 +38,17 @@
 #include "nsISupportsBase.h"
 #include "nsLiteralString.h"
 #include "mozilla/dom/NodeIterator.h"
 #include "nsTextEditRules.h"
 #include "nsTextEditUtils.h"
 #include "nsUnicharUtils.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 #define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
   if (IsReadonly() || IsDisabled()) \
   {                     \
     *aCancel = true; \
     return NS_OK;       \
   };
 
--- a/editor/libeditor/text/nsTextEditRules.h
+++ b/editor/libeditor/text/nsTextEditRules.h
@@ -16,17 +16,19 @@
 #include "nsPlaintextEditor.h"
 #include "nsString.h"
 #include "nscore.h"
 
 class nsIDOMElement;
 class nsIDOMNode;
 class nsISelection;
 namespace mozilla {
+namespace dom {
 class Selection;
+}  // namespace dom
 }  // namespace mozilla
 
 /** Object that encapsulates HTML text-specific editing rules.
   *  
   * To be a good citizen, edit rules must live by these restrictions:
   * 1. All data manipulation is through the editor.  
   *    Content nodes in the document tree must <B>not</B> be manipulated directly.
   *    Content nodes in document fragments that are not part of the document itself
@@ -48,18 +50,18 @@ public:
   // nsIEditRules methods
   NS_IMETHOD Init(nsPlaintextEditor *aEditor);
   NS_IMETHOD SetInitialValue(const nsAString& aValue);
   NS_IMETHOD DetachEditor();
   NS_IMETHOD BeforeEdit(EditAction action,
                         nsIEditor::EDirection aDirection);
   NS_IMETHOD AfterEdit(EditAction action,
                        nsIEditor::EDirection aDirection);
-  NS_IMETHOD WillDoAction(mozilla::Selection* aSelection, nsRulesInfo* aInfo,
-                          bool* aCancel, bool* aHandled);
+  NS_IMETHOD WillDoAction(mozilla::dom::Selection* aSelection,
+                          nsRulesInfo* aInfo, bool* aCancel, bool* aHandled);
   NS_IMETHOD DidDoAction(nsISelection *aSelection, nsRulesInfo *aInfo, nsresult aResult);
   NS_IMETHOD DocumentIsEmpty(bool *aDocumentIsEmpty);
   NS_IMETHOD DocumentModified();
 
 public:
   void ResetIMETextPWBuf();
 
   /**
@@ -97,33 +99,33 @@ public:
    *        contain.
    */
   static void FillBufWithPWChars(nsAString *aOutString, int32_t aLength);
 
 protected:
 
   // nsTextEditRules implementation methods
   nsresult WillInsertText(  EditAction aAction,
-                            mozilla::Selection* aSelection,
+                            mozilla::dom::Selection* aSelection,
                             bool            *aCancel,
                             bool            *aHandled,
                             const nsAString *inString,
                             nsAString       *outString,
                             int32_t          aMaxLength);
   nsresult DidInsertText(nsISelection *aSelection, nsresult aResult);
   nsresult GetTopEnclosingPre(nsIDOMNode *aNode, nsIDOMNode** aOutPreNode);
 
-  nsresult WillInsertBreak(mozilla::Selection* aSelection, bool* aCancel,
+  nsresult WillInsertBreak(mozilla::dom::Selection* aSelection, bool* aCancel,
                            bool *aHandled, int32_t aMaxLength);
   nsresult DidInsertBreak(nsISelection *aSelection, nsresult aResult);
 
   nsresult WillInsert(nsISelection *aSelection, bool *aCancel);
   nsresult DidInsert(nsISelection *aSelection, nsresult aResult);
 
-  nsresult WillDeleteSelection(mozilla::Selection* aSelection,
+  nsresult WillDeleteSelection(mozilla::dom::Selection* aSelection,
                                nsIEditor::EDirection aCollapsedAction, 
                                bool *aCancel,
                                bool *aHandled);
   nsresult DidDeleteSelection(nsISelection *aSelection, 
                               nsIEditor::EDirection aCollapsedAction, 
                               nsresult aResult);
 
   nsresult WillSetTextProperty(nsISelection *aSelection, bool *aCancel, bool *aHandled);
@@ -162,17 +164,17 @@ protected:
   /** creates a trailing break in the text doc if there is not one already */
   nsresult CreateTrailingBRIfNeeded();
   
  /** creates a bogus text node if the document has no editable content */
   nsresult CreateBogusNodeIfNeeded(nsISelection *aSelection);
 
   /** returns a truncated insertion string if insertion would place us
       over aMaxLength */
-  nsresult TruncateInsertionIfNeeded(mozilla::Selection*       aSelection,
+  nsresult TruncateInsertionIfNeeded(mozilla::dom::Selection*  aSelection,
                                      const nsAString          *aInString,
                                      nsAString                *aOutString,
                                      int32_t                   aMaxLength,
                                      bool                     *aTruncated);
 
   /** Remove IME composition text from password buffer */
   void RemoveIMETextFromPWBuf(int32_t &aStart, nsAString *aIMEString);
 
--- a/editor/libeditor/text/nsTextEditRulesBidi.cpp
+++ b/editor/libeditor/text/nsTextEditRulesBidi.cpp
@@ -7,25 +7,26 @@
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsFrameSelection.h"
 #include "nsIContent.h"
 #include "nsIDOMNode.h"
 #include "nsIEditor.h"
 #include "nsIPresShell.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsISelectionPrivate.h"
 #include "nsISupportsImpl.h"
 #include "nsPlaintextEditor.h"
 #include "nsPresContext.h"
 #include "nsTextEditRules.h"
 #include "nscore.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 // Test for distance between caret and text that will be deleted
 nsresult
 nsTextEditRules::CheckBidiLevelForDeletion(nsISelection         *aSelection,
                                            nsIDOMNode           *aSelNode, 
                                            int32_t               aSelOffset, 
                                            nsIEditor::EDirection aAction,
                                            bool                 *aCancel)
--- a/embedding/tests/winEmbed/WebBrowserChrome.cpp
+++ b/embedding/tests/winEmbed/WebBrowserChrome.cpp
@@ -361,16 +361,22 @@ WebBrowserChrome::OnHistoryReload(nsIURI
 NS_IMETHODIMP
 WebBrowserChrome::OnHistoryPurge(int32_t aNumEntries, bool *aContinue)
 {
     // For now let the operation continue
     *aContinue = false;
     return SendHistoryStatusMessage(nullptr, "purge", aNumEntries);
 }
 
+NS_IMETHODIMP
+WebBrowserChrome::OnHistoryReplaceEntry(int32_t aIndex)
+{
+    return SendHistoryStatusMessage(nullptr, "replace", aIndex);
+}
+
 static void
 AppendIntToCString(int32_t info1, nsCString& aResult)
 {
   char intstr[10];
   _snprintf(intstr, sizeof(intstr) - 1, "%i", info1);
   intstr[sizeof(intstr) - 1] = '\0';
   aResult.Append(intstr);
 }
@@ -433,16 +439,21 @@ WebBrowserChrome::SendHistoryStatusMessa
         status.Append(" Url: ");
         status.Append(uriSpec);
     }
     else if (!(strcmp(operation, "purge")))
     {
         AppendIntToCString(info1, status);
         status.Append(" purged from Session History");
     }
+    else if (!(strcmp(operation, "replace")))
+    {
+        status.Assign("Replacing HistoryIndex: ");
+        AppentIntToCString(info1, status);
+    }
 
     nsString wstatus;
     NS_CStringToUTF16(status, NS_CSTRING_ENCODING_UTF8, wstatus);
     WebBrowserChromeUI::UpdateStatusBarText(this, wstatus.get());
 
     return NS_OK;
 }
 
--- a/gfx/layers/apz/util/ActiveElementManager.cpp
+++ b/gfx/layers/apz/util/ActiveElementManager.cpp
@@ -36,17 +36,19 @@ ActiveElementManager::ActiveElementManag
 
 ActiveElementManager::~ActiveElementManager() {}
 
 void
 ActiveElementManager::SetTargetElement(nsIDOMEventTarget* aTarget)
 {
   if (mTarget) {
     // Multiple fingers on screen (since HandleTouchEnd clears mTarget).
+    CancelTask();
     ResetActive();
+    mTarget = nullptr;
     return;
   }
 
   mTarget = do_QueryInterface(aTarget);
   TriggerElementActivation();
 }
 
 void
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -7,18 +7,18 @@
 #include "CompositorChild.h"            // for CompositorChild
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "gfxPrefs.h"                   // for gfxPrefs::LayersTileWidth/Height
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Hal.h"
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/dom/TabChild.h"       // for TabChild
 #include "mozilla/hal_sandbox/PHal.h"   // for ScreenConfiguration
-#include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
-#include "mozilla/layers/ContentClient.h"  // for ContentClientRemote
+#include "mozilla/layers/CompositableClient.h"
+#include "mozilla/layers/ContentClient.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersMessages.h"  // for EditReply, etc
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/PLayerChild.h"  // for PLayerChild
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/TextureClientPool.h" // for TextureClientPool
 #include "mozilla/layers/SimpleTextureClientPool.h" // for SimpleTextureClientPool
 #include "nsAString.h"
@@ -374,37 +374,35 @@ ClientLayerManager::ForwardTransaction(b
       const EditReply& reply = replies[i];
 
       switch (reply.type()) {
       case EditReply::TOpContentBufferSwap: {
         MOZ_LAYERS_LOG(("[LayersForwarder] DoubleBufferSwap"));
 
         const OpContentBufferSwap& obs = reply.get_OpContentBufferSwap();
 
-        CompositableChild* compositableChild =
-          static_cast<CompositableChild*>(obs.compositableChild());
+        CompositableClient* compositable =
+          CompositableClient::FromIPDLActor(obs.compositableChild());
         ContentClientRemote* contentClient =
-          static_cast<ContentClientRemote*>(compositableChild->GetCompositableClient());
+          static_cast<ContentClientRemote*>(compositable);
         MOZ_ASSERT(contentClient);
 
         contentClient->SwapBuffers(obs.frontUpdatedRegion());
 
         break;
       }
       case EditReply::TOpTextureSwap: {
         MOZ_LAYERS_LOG(("[LayersForwarder] TextureSwap"));
 
         const OpTextureSwap& ots = reply.get_OpTextureSwap();
 
-        CompositableChild* compositableChild =
-          static_cast<CompositableChild*>(ots.compositableChild());
-        MOZ_ASSERT(compositableChild);
-
-        compositableChild->GetCompositableClient()
-          ->SetDescriptorFromReply(ots.textureId(), ots.image());
+        CompositableClient* compositable =
+          CompositableClient::FromIPDLActor(ots.compositableChild());
+        MOZ_ASSERT(compositable);
+        compositable->SetDescriptorFromReply(ots.textureId(), ots.image());
         break;
       }
       case EditReply::TReturnReleaseFence: {
         const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
         FenceHandle fence = rep.fence();
         PTextureChild* child = rep.textureChild();
 
         if (!fence.IsValid() || !child) {
--- a/gfx/layers/client/CompositableClient.cpp
+++ b/gfx/layers/client/CompositableClient.cpp
@@ -16,16 +16,77 @@
 #include "mozilla/layers/TextureD3D9.h"
 #endif
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
+/**
+ * IPDL actor used by CompositableClient to match with its corresponding
+ * CompositableHost on the compositor side.
+ *
+ * CompositableChild is owned by a CompositableClient.
+ */
+class CompositableChild : public PCompositableChild
+{
+public:
+  CompositableChild()
+  : mCompositableClient(nullptr), mAsyncID(0)
+  {
+    MOZ_COUNT_CTOR(CompositableChild);
+  }
+
+  ~CompositableChild()
+  {
+    MOZ_COUNT_DTOR(CompositableChild);
+  }
+
+  virtual void ActorDestroy(ActorDestroyReason) MOZ_OVERRIDE {
+    if (mCompositableClient) {
+      mCompositableClient->mCompositableChild = nullptr;
+    }
+  }
+
+  CompositableClient* mCompositableClient;
+
+  uint64_t mAsyncID;
+};
+
+PCompositableChild*
+CompositableClient::CreateIPDLActor()
+{
+  return new CompositableChild();
+}
+
+bool
+CompositableClient::DestroyIPDLActor(PCompositableChild* actor)
+{
+  delete actor;
+  return true;
+}
+
+void
+CompositableClient::InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID)
+{
+  MOZ_ASSERT(aActor);
+  CompositableChild* child = static_cast<CompositableChild*>(aActor);
+  mCompositableChild = child;
+  child->mCompositableClient = this;
+  child->mAsyncID = aAsyncID;
+}
+
+CompositableClient*
+CompositableClient::FromIPDLActor(PCompositableChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+  return static_cast<CompositableChild*>(aActor)->mCompositableClient;
+}
+
 CompositableClient::CompositableClient(CompositableForwarder* aForwarder,
                                        TextureFlags aTextureFlags)
 : mCompositableChild(nullptr)
 , mForwarder(aForwarder)
 , mTextureFlags(aTextureFlags)
 {
   MOZ_COUNT_CTOR(CompositableClient);
 }
@@ -43,17 +104,17 @@ CompositableClient::GetCompositorBackend
 }
 
 void
 CompositableClient::SetIPDLActor(CompositableChild* aChild)
 {
   mCompositableChild = aChild;
 }
 
-CompositableChild*
+PCompositableChild*
 CompositableClient::GetIPDLActor() const
 {
   return mCompositableChild;
 }
 
 bool
 CompositableClient::Connect()
 {
@@ -65,37 +126,30 @@ CompositableClient::Connect()
 }
 
 void
 CompositableClient::Destroy()
 {
   if (!mCompositableChild) {
     return;
   }
-  mCompositableChild->SetClient(nullptr);
-  mCompositableChild->Destroy();
+  mCompositableChild->mCompositableClient = nullptr;
+  PCompositableChild::Send__delete__(mCompositableChild);
   mCompositableChild = nullptr;
 }
 
 uint64_t
 CompositableClient::GetAsyncID() const
 {
   if (mCompositableChild) {
-    return mCompositableChild->GetAsyncID();
+    return mCompositableChild->mAsyncID;
   }
   return 0; // zero is always an invalid async ID
 }
 
-
-void
-CompositableChild::Destroy()
-{
-  Send__delete__(this);
-}
-
 TemporaryRef<BufferTextureClient>
 CompositableClient::CreateBufferTextureClient(SurfaceFormat aFormat,
                                               TextureFlags aTextureFlags,
                                               gfx::BackendType aMoz2DBackend)
 {
   return TextureClient::CreateBufferTextureClient(GetForwarder(), aFormat,
                                                   aTextureFlags | mTextureFlags,
                                                   aMoz2DBackend);
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -100,17 +100,17 @@ public:
 
   /**
    * Establishes the connection with compositor side through IPDL
    */
   virtual bool Connect();
 
   void Destroy();
 
-  CompositableChild* GetIPDLActor() const;
+  PCompositableChild* GetIPDLActor() const;
 
   // should only be called by a CompositableForwarder
   virtual void SetIPDLActor(CompositableChild* aChild);
 
   CompositableForwarder* GetForwarder() const
   {
     return mForwarder;
   }
@@ -141,69 +141,38 @@ public:
   virtual void OnDetach() {}
 
   /**
    * Clear any resources that are not immediately necessary. This may be called
    * in low-memory conditions.
    */
   virtual void ClearCachedResources() {}
 
+  static CompositableClient* FromIPDLActor(PCompositableChild* aActor);
+
+  /**
+   * Allocate and deallocate a CompositableChild actor.
+   *
+   * CompositableChild is an implementation detail of CompositableClient that is not
+   * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
+   * are for use with the managing IPDL protocols only (so that they can
+   * implement AllocCompositableChild and DeallocPCompositableChild).
+   */
+  static PCompositableChild* CreateIPDLActor();
+
+  static bool DestroyIPDLActor(PCompositableChild* actor);
+
+  void InitIPDLActor(PCompositableChild* aActor, uint64_t aAsyncID = 0);
+
 protected:
   CompositableChild* mCompositableChild;
   CompositableForwarder* mForwarder;
   // Some layers may want to enforce some flags to all their textures
   // (like disallowing tiling)
   TextureFlags mTextureFlags;
 
   friend class CompositableChild;
 };
 
-/**
- * IPDL actor used by CompositableClient to match with its corresponding
- * CompositableHost on the compositor side.
- *
- * CompositableChild is owned by a CompositableClient.
- */
-class CompositableChild : public PCompositableChild
-{
-public:
-  CompositableChild()
-  : mCompositableClient(nullptr), mID(0)
-  {
-    MOZ_COUNT_CTOR(CompositableChild);
-  }
-  ~CompositableChild()
-  {
-    MOZ_COUNT_DTOR(CompositableChild);
-  }
-
-  void Destroy();
-
-  void SetClient(CompositableClient* aClient)
-  {
-    mCompositableClient = aClient;
-  }
-
-  CompositableClient* GetCompositableClient() const
-  {
-    return mCompositableClient;
-  }
-
-  virtual void ActorDestroy(ActorDestroyReason) MOZ_OVERRIDE {
-    if (mCompositableClient) {
-      mCompositableClient->mCompositableChild = nullptr;
-    }
-  }
-
-  void SetAsyncID(uint64_t aID) { mID = aID; }
-  uint64_t GetAsyncID() const
-  {
-    return mID;
-  }
-private:
-  CompositableClient* mCompositableClient;
-  uint64_t mID;
-};
-
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -231,19 +231,19 @@ public:
    * in-memory buffer. The consequence of this is that locking the
    * TextureClient does not contend with locking the texture on the host side.
    */
   virtual bool HasInternalBuffer() const = 0;
 
   /**
    * Allocate and deallocate a TextureChild actor.
    *
-   * TextureChild is an implementation detail of TextureHost that is not
+   * TextureChild is an implementation detail of TextureClient that is not
    * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
-   * are for use with the maging IPDL protocols only (so that they can
+   * are for use with the managing IPDL protocols only (so that they can
    * implement AllocPextureChild and DeallocPTextureChild).
    */
   static PTextureChild* CreateIPDLActor();
   static bool DestroyIPDLActor(PTextureChild* actor);
 
   /**
    * Get the TextureClient corresponding to the actor passed in parameter.
    */
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -259,36 +259,32 @@ ImageBridgeChild::~ImageBridgeChild()
   delete mTxn;
 }
 
 void
 ImageBridgeChild::Connect(CompositableClient* aCompositable)
 {
   MOZ_ASSERT(aCompositable);
   uint64_t id = 0;
-  CompositableChild* child = static_cast<CompositableChild*>(
-    SendPCompositableConstructor(aCompositable->GetTextureInfo(), &id));
+  PCompositableChild* child =
+    SendPCompositableConstructor(aCompositable->GetTextureInfo(), &id);
   MOZ_ASSERT(child);
-  child->SetAsyncID(id);
-  aCompositable->SetIPDLActor(child);
-  MOZ_ASSERT(child->GetAsyncID() == id);
-  child->SetClient(aCompositable);
+  aCompositable->InitIPDLActor(child, id);
 }
 
 PCompositableChild*
 ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID)
 {
-  return new CompositableChild();
+  return CompositableClient::CreateIPDLActor();
 }
 
 bool
 ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
 {
-  delete aActor;
-  return true;
+  return CompositableClient::DestroyIPDLActor(aActor);
 }
 
 
 Thread* ImageBridgeChild::GetThread() const
 {
   return sImageBridgeChildThread;
 }
 
@@ -486,23 +482,22 @@ ImageBridgeChild::EndTransaction()
     }
   }
   for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
     const EditReply& reply = replies[i];
     switch (reply.type()) {
     case EditReply::TOpTextureSwap: {
       const OpTextureSwap& ots = reply.get_OpTextureSwap();
 
-      CompositableChild* compositableChild =
-          static_cast<CompositableChild*>(ots.compositableChild());
+      CompositableClient* compositable =
+        CompositableClient::FromIPDLActor(ots.compositableChild());
 
-      MOZ_ASSERT(compositableChild);
+      MOZ_ASSERT(compositable);
 
-      compositableChild->GetCompositableClient()
-        ->SetDescriptorFromReply(ots.textureId(), ots.image());
+      compositable->SetDescriptorFromReply(ots.textureId(), ots.image());
       break;
     }
     case EditReply::TReturnReleaseFence: {
       const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
       FenceHandle fence = rep.fence();
       PTextureChild* child = rep.textureChild();
 
       if (!fence.IsValid() || !child) {
--- a/gfx/layers/ipc/LayerTransactionChild.cpp
+++ b/gfx/layers/ipc/LayerTransactionChild.cpp
@@ -68,24 +68,23 @@ LayerTransactionChild::DeallocPLayerChil
 {
   delete actor;
   return true;
 }
 
 PCompositableChild*
 LayerTransactionChild::AllocPCompositableChild(const TextureInfo& aInfo)
 {
-  return new CompositableChild();
+  return CompositableClient::CreateIPDLActor();
 }
 
 bool
 LayerTransactionChild::DeallocPCompositableChild(PCompositableChild* actor)
 {
-  delete actor;
-  return true;
+  return CompositableClient::DestroyIPDLActor(actor);
 }
 
 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
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -643,21 +643,20 @@ ShadowLayerForwarder::Connect(Compositab
 #ifdef GFX_COMPOSITOR_LOGGING
   printf("ShadowLayerForwarder::Connect(Compositable)\n");
 #endif
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(mShadowManager);
   if (!mShadowManager->IPCOpen()) {
     return;
   }
-  CompositableChild* child = static_cast<CompositableChild*>(
-    mShadowManager->SendPCompositableConstructor(aCompositable->GetTextureInfo()));
-  MOZ_ASSERT(child);
-  aCompositable->SetIPDLActor(child);
-  child->SetClient(aCompositable);
+  PCompositableChild* actor =
+    mShadowManager->SendPCompositableConstructor(aCompositable->GetTextureInfo());
+  MOZ_ASSERT(actor);
+  aCompositable->InitIPDLActor(actor);
 }
 
 void
 ShadowLayerForwarder::CreatedIncrementalBuffer(CompositableClient* aCompositable,
                                                const TextureInfo& aTextureInfo,
                                                const nsIntRect& aBufferRect)
 {
   MOZ_ASSERT(aCompositable);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -3431,16 +3431,18 @@ static bool
 EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption,
               bool isLet = false)
 {
     JS_ASSERT(pn->isArity(PN_LIST));
     JS_ASSERT(isLet == (emitOption == PushInitialValues));
 
     ParseNode *next;
     for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) {
+        if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
+            return false;
         next = pn2->pn_next;
 
         ParseNode *pn3;
         if (!pn2->isKind(PNK_NAME)) {
             if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) {
                 /*
                  * Emit variable binding ops, but not destructuring ops.  The
                  * parser (see Parser::variables) has ensured that our caller
@@ -5899,16 +5901,19 @@ EmitObject(ExclusiveContext *cx, Bytecod
     if (bce->script->compileAndGo()) {
         gc::AllocKind kind = GuessObjectGCKind(pn->pn_count);
         obj = NewBuiltinClassInstance(cx, &JSObject::class_, kind, TenuredObject);
         if (!obj)
             return false;
     }
 
     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
+        if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
+            return false;
+
         /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
         ParseNode *pn3 = pn2->pn_left;
         bool isIndex = false;
         if (pn3->isKind(PNK_NUMBER)) {
             if (!EmitNumberOp(cx, pn3->pn_dval, bce))
                 return false;
             isIndex = true;
         } else {
@@ -6060,16 +6065,18 @@ EmitArray(ExclusiveContext *cx, Bytecode
     // minimum possible final size.
     SET_UINT24(pc, count - nspread);
 
     ParseNode *pn2 = pn;
     jsatomid atomIndex;
     if (nspread && !EmitNumberOp(cx, 0, bce))
         return false;
     for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
+        if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
+            return false;
         if (pn2->isKind(PNK_ELISION)) {
             if (Emit1(cx, bce, JSOP_HOLE) < 0)
                 return false;
         } else {
             ParseNode *expr = pn2->isKind(PNK_SPREAD) ? pn2->pn_kid : pn2;
             if (!EmitTree(cx, bce, expr))
                 return false;
         }
@@ -6367,16 +6374,18 @@ frontend::EmitTree(ExclusiveContext *cx,
 
       case PNK_LABEL:
         ok = EmitLabeledStatement(cx, bce, &pn->as<LabeledStatement>());
         break;
 
       case PNK_COMMA:
       {
         for (ParseNode *pn2 = pn->pn_head; ; pn2 = pn2->pn_next) {
+            if (!UpdateSourceCoordNotes(cx, bce, pn2->pn_pos.begin))
+                return false;
             if (!EmitTree(cx, bce, pn2))
                 return false;
             if (!pn2->pn_next)
                 break;
             if (Emit1(cx, bce, JSOP_POP) < 0)
                 return false;
         }
         break;
--- a/js/src/jit-test/tests/asm.js/testStackWalking.js
+++ b/js/src/jit-test/tests/asm.js/testStackWalking.js
@@ -1,38 +1,93 @@
 load(libdir + "asm.js");
 load(libdir + "asserts.js");
 
-var callFFI1 = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function asmfun1() { return ffi(1)|0 } return asmfun1");
-var callFFI2 = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function asmfun2() { return ffi(2)|0 } return asmfun2");
+function matchStack(stackString, stackArray)
+{
+    var match = 0;
+    for (name of stackArray) {
+        match = stackString.indexOf(name, match);
+        if (match === -1)
+            throw name + " not found in the stack " + stack;
+    }
+}
 
 var stack;
-function dumpStack(i) { stack = new Error().stack; return i+11 }
+function dumpStack()
+{
+    stack = new Error().stack
+}
+
+var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
 
-var asmfun1 = asmLink(callFFI1, null, {ffi:dumpStack});
-assertEq(asmfun1(), 12);
-assertEq(stack.indexOf("asmfun1") === -1, false);
+var f = asmLink(callFFI, null, {ffi:dumpStack});
+for (var i = 0; i < 5000; i++) {
+    stack = null;
+    f();
+    matchStack(stack, ['dumpStack', 'f']);
+}
 
-var asmfun2 = asmLink(callFFI2, null, {ffi:function ffi(i){return asmfun1()+20}});
-assertEq(asmfun2(), 32);
-assertEq(stack.indexOf("asmfun1") == -1, false);
-assertEq(stack.indexOf("asmfun2") == -1, false);
-assertEq(stack.indexOf("asmfun2") > stack.indexOf("asmfun1"), true);
+if (isAsmJSCompilationAvailable() && isCachingEnabled()) {
+    var callFFI = asmCompile('global', 'ffis', USE_ASM + "var ffi=ffis.ffi; function f() { return ffi()|0 } return f");
+    assertEq(isAsmJSModuleLoadedFromCache(callFFI), true);
+    stack = null;
+    f();
+    matchStack(stack, ['dumpStack', 'f']);
+}
+
+var f1 = asmLink(callFFI, null, {ffi:dumpStack});
+var f2 = asmLink(callFFI, null, {ffi:function middle() { f1() }});
+stack = null;
+(function outer() { f2() })();
+matchStack(stack, ["dumpStack", "f", "middle", "f"]);
+
+function returnStackDumper() { return { valueOf:function() { stack = new Error().stack } } }
+var f = asmLink(callFFI, null, {ffi:returnStackDumper});
+for (var i = 0; i < 5000; i++) {
+    stack = null;
+    f();
+    matchStack(stack, ['valueOf', 'f']);
+}
 
 var caught = false;
 try {
+    stack = null;
     asmLink(asmCompile(USE_ASM + "function asmRec() { asmRec() } return asmRec"))();
 } catch (e) {
     caught = true;
+    matchStack(e.stack, ['asmRec', 'asmRec', 'asmRec', 'asmRec']);
+}
+assertEq(caught, true);
+
+var caught = false;
+try {
+    callFFI(null, {ffi:Object.preventExtensions})();
+} catch (e) {
+    caught = true;
 }
 assertEq(caught, true);
 
-var caught = false;
-try {
-    callFFI1(null, {ffi:Object.preventExtensions})();
-} catch (e) {
-    caught = true;
-}
-assertEq(caught, true);
+asmLink(callFFI, null, {ffi:eval})();
+asmLink(callFFI, null, {ffi:Function})();
+asmLink(callFFI, null, {ffi:Error})();
 
-assertEq(asmLink(callFFI1, null, {ffi:eval})(), 1);
-assertEq(asmLink(callFFI1, null, {ffi:Function})(), 0);
-assertEq(asmLink(callFFI1, null, {ffi:Error})(), 0);
+var manyCalls = asmCompile('global', 'ffis',
+    USE_ASM +
+    "var ffi=ffis.ffi;\
+     function f1(a,b,c,d,e,f,g,h,i,j,k) { \
+       a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;j=j|0;k=k|0; \
+       ffi(); \
+       return (a+b+c+d+e+f+g+h+i+j+k)|0; \
+     } \
+     function f2() { \
+       return f1(1,2,3,4,5,6,7,8,f1(1,2,3,4,5,6,7,8,9,10,11)|0,10,11)|0; \
+     } \
+     function f3() { return 13 } \
+     function f4(i) { \
+       i=i|0; \
+       return TBL[i&3]()|0; \
+     } \
+     var TBL=[f3, f3, f2, f3]; \
+     return f4;");
+stack = null;
+assertEq(asmLink(manyCalls, null, {ffi:dumpStack})(2), 123);
+matchStack(stack, ['dumpStack', 'f1', 'f2', 'f4']);
--- a/js/src/jit-test/tests/debug/Object-deleteProperty-error-02.js
+++ b/js/src/jit-test/tests/debug/Object-deleteProperty-error-02.js
@@ -3,21 +3,17 @@ var dbg = Debugger(g);
 dbg.onDebuggerStatement = function (frame) {
     try {
         frame.arguments[0].deleteProperty("x");
     } catch (exc) {
         assertEq(exc instanceof ReferenceError, true);
         assertEq(exc.message, "diaf");
         assertEq(exc.fileName, "fail");
         assertEq(exc.lineNumber, 4);
-
-        // Arrant nonsense?  Sure -- but different from lineNumber is all this
-        // test exists to verify.  If you're the person to make column numbers
-        // actually work, change this accordingly.
-        assertEq(exc.columnNumber, 0);
+        assertEq(exc.columnNumber, 20);
         return;
     }
     throw new Error("deleteProperty should throw");
 };
 
 g.evaluate("function h(obj) { debugger; } \n" +
            "h(new Proxy({}, \n" +
            "            { deleteProperty: function () { \n" +
--- a/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-01.js
+++ b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-01.js
@@ -11,9 +11,9 @@ Debugger(global).onDebuggerStatement = f
             }
         });
     });
 };
 
 global.log = '';
 global.eval("function f(n) { for (var i = 0; i < n; ++i) log += '. '; log += '! '; } debugger;");
 global.f(3);
-assertEq(global.log, "21 32 44 . 39 32 44 . 39 32 44 . 39 32 57 ! 69 ");
+assertEq(global.log, "25 32 44 . 39 32 44 . 39 32 44 . 39 32 57 ! 69 ");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-02.js
@@ -0,0 +1,21 @@
+// getColumnOffsets correctly places multiple variable declarations.
+
+var global = newGlobal();
+Debugger(global).onDebuggerStatement = function (frame) {
+    var script = frame.eval("f").return.script;
+    script.getAllColumnOffsets().forEach(function (offset) {
+        script.setBreakpoint(offset.offset, {
+            hit: function (frame) {
+                assertEq(offset.lineNumber, 1);
+                global.log += offset.columnNumber + " ";
+            }
+        });
+    });
+};
+
+global.log = '';
+global.eval("function f(n){var w0,x1=3,y2=4,z3=9} debugger;");
+global.f(3);
+
+// Should have hit each variable declared.
+assertEq(global.log, "18 21 26 31 33 ");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-03.js
@@ -0,0 +1,20 @@
+// getColumnOffsets correctly places comma separated expressions.
+
+var global = newGlobal();
+Debugger(global).onDebuggerStatement = function (frame) {
+    var script = frame.eval("f").return.script;
+    script.getAllColumnOffsets().forEach(function (offset) {
+        script.setBreakpoint(offset.offset, {
+            hit: function (frame) {
+                assertEq(offset.lineNumber, 1);
+                global.log += offset.columnNumber + " ";
+            }
+        });
+    });
+};
+
+global.log = '';
+global.eval("function f(n){print(n),print(n),print(n)} debugger;");
+global.f(3);
+// Should hit each call that was separated by commas.
+assertEq(global.log, "14 23 32 40 ");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-04.js
@@ -0,0 +1,20 @@
+// getColumnOffsets correctly places object properties.
+
+var global = newGlobal();
+Debugger(global).onDebuggerStatement = function (frame) {
+    var script = frame.eval("f").return.script;
+    script.getAllColumnOffsets().forEach(function (offset) {
+        script.setBreakpoint(offset.offset, {
+            hit: function (frame) {
+                assertEq(offset.lineNumber, 1);
+                global.log += offset.columnNumber + " ";
+            }
+        });
+    });
+};
+
+global.log = '';
+global.eval("function f(n){var o={a:1,b:2,c:3}} debugger;");
+global.f(3);
+// Should hit each property in the object.
+assertEq(global.log, "18 21 25 29 19 ");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Script-getAllColumnOffsets-05.js
@@ -0,0 +1,20 @@
+// getColumnOffsets correctly places array properties.
+
+var global = newGlobal();
+Debugger(global).onDebuggerStatement = function (frame) {
+    var script = frame.eval("f").return.script;
+    script.getAllColumnOffsets().forEach(function (offset) {
+        script.setBreakpoint(offset.offset, {
+            hit: function (frame) {
+                assertEq(offset.lineNumber, 1);
+                global.log += offset.columnNumber + " ";
+            }
+        });
+    });
+};
+
+global.log = '';
+global.eval("function f(n){var a=[1,2,3]} debugger;");
+global.f(3);
+// Should hit each item in the array.
+assertEq(global.log, "18 21 23 25 19 ");
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1031,17 +1031,16 @@ class MOZ_STACK_CLASS ModuleCompiler
     ParseNode *                    moduleFunctionNode_;
     PropertyName *                 moduleFunctionName_;
 
     GlobalMap                      globals_;
     FuncVector                     functions_;
     FuncPtrTableVector             funcPtrTables_;
     ExitMap                        exits_;
     MathNameMap                    standardLibraryMathNames_;
-    GlobalAccessVector             globalAccesses_;
     Label                          stackOverflowLabel_;
     Label                          interruptLabel_;
 
     char *                         errorString_;
     uint32_t                       errorOffset_;
     bool                           errorOverRecursed_;
 
     int64_t                        usecBefore_;
@@ -1072,33 +1071,32 @@ class MOZ_STACK_CLASS ModuleCompiler
         moduleLifo_(LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
         moduleFunctionNode_(parser.pc->maybeFunction),
         moduleFunctionName_(nullptr),
         globals_(cx),
         functions_(cx),
         funcPtrTables_(cx),
         exits_(cx),
         standardLibraryMathNames_(cx),
-        globalAccesses_(cx),
         errorString_(nullptr),
         errorOffset_(UINT32_MAX),
         errorOverRecursed_(false),
         usecBefore_(PRMJ_Now()),
         slowFunctions_(cx),
         finishedFunctionBodies_(false)
     {
         JS_ASSERT(moduleFunctionNode_->pn_funbox == parser.pc->sc->asFunctionBox());
     }
 
     ~ModuleCompiler() {
         if (errorString_) {
             JS_ASSERT(errorOffset_ != UINT32_MAX);
-            parser_.tokenStream.reportAsmJSError(errorOffset_,
-                                                 JSMSG_USE_ASM_TYPE_FAIL,
-                                                 errorString_);
+            tokenStream().reportAsmJSError(errorOffset_,
+                                           JSMSG_USE_ASM_TYPE_FAIL,
+                                           errorString_);
             js_free(errorString_);
         }
         if (errorOverRecursed_)
             js_ReportOverRecursed(cx_);
 
         // Avoid spurious Label assertions on compilation failure.
         if (!stackOverflowLabel_.bound())
             stackOverflowLabel_.bind(0);
@@ -1137,17 +1135,17 @@ class MOZ_STACK_CLASS ModuleCompiler
             !addStandardLibraryMathName("PI", M_PI) ||
             !addStandardLibraryMathName("SQRT1_2", M_SQRT1_2) ||
             !addStandardLibraryMathName("SQRT2", M_SQRT2))
         {
             return false;
         }
 
         uint32_t funcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin;
-        uint32_t offsetToEndOfUseAsm = parser_.tokenStream.currentToken().pos.end;
+        uint32_t offsetToEndOfUseAsm = tokenStream().currentToken().pos.end;
 
         // "use strict" should be added to the source if we are in an implicit
         // strict context, see also comment above addUseStrict in
         // js::FunctionToString.
         bool strict = parser_.pc->sc->strict && !parser_.pc->sc->hasExplicitUseStrict();
 
         module_ = cx_->new_<AsmJSModule>(parser_.ss, funcStart, offsetToEndOfUseAsm, strict);
         if (!module_)
@@ -1169,24 +1167,24 @@ class MOZ_STACK_CLASS ModuleCompiler
         if (pn)
             return failOffset(pn->pn_pos.begin, str);
 
         // The exact rooting static analysis does not perform dataflow analysis, so it believes
         // that unrooted things on the stack during compilation may still be accessed after this.
         // Since pn is typically only null under OOM, this suppression simply forces any GC to be
         // delayed until the compilation is off the stack and more memory can be freed.
         gc::AutoSuppressGC nogc(cx_);
-        return failOffset(parser_.tokenStream.peekTokenPos().begin, str);
+        return failOffset(tokenStream().peekTokenPos().begin, str);
     }
 
     bool failfVA(ParseNode *pn, const char *fmt, va_list ap) {
         JS_ASSERT(!errorString_);
         JS_ASSERT(errorOffset_ == UINT32_MAX);
         JS_ASSERT(fmt);
-        errorOffset_ = pn ? pn->pn_pos.begin : parser_.tokenStream.currentToken().pos.end;
+        errorOffset_ = pn ? pn->pn_pos.begin : tokenStream().currentToken().pos.end;
         errorString_ = JS_vsmprintf(fmt, ap);
         return false;
     }
 
     bool failf(ParseNode *pn, const char *fmt, ...) {
         va_list ap;
         va_start(ap, fmt);
         failfVA(pn, fmt, ap);
@@ -1211,24 +1209,25 @@ class MOZ_STACK_CLASS ModuleCompiler
     static const unsigned SLOW_FUNCTION_THRESHOLD_MS = 250;
 
     bool maybeReportCompileTime(const Func &func) {
         if (func.compileTime() < SLOW_FUNCTION_THRESHOLD_MS)
             return true;
         SlowFunction sf;
         sf.name = func.name();
         sf.ms = func.compileTime();
-        parser_.tokenStream.srcCoords.lineNumAndColumnIndex(func.srcOffset(), &sf.line, &sf.column);
+        tokenStream().srcCoords.lineNumAndColumnIndex(func.srcOffset(), &sf.line, &sf.column);
         return slowFunctions_.append(sf);
     }
 
     /*************************************************** Read-only interface */
 
     ExclusiveContext *cx() const { return cx_; }
     AsmJSParser &parser() const { return parser_; }
+    TokenStream &tokenStream() const { return parser_.tokenStream; }
     MacroAssembler &masm() { return masm_; }
     Label &stackOverflowLabel() { return stackOverflowLabel_; }
     Label &interruptLabel() { return interruptLabel_; }
     bool hasError() const { return errorString_ != nullptr; }
     const AsmJSModule &module() const { return *module_.get(); }
     uint32_t moduleStart() const { return module_->funcStart(); }
 
     ParseNode *moduleFunctionNode() const { return moduleFunctionNode_; }
@@ -1392,81 +1391,66 @@ class MOZ_STACK_CLASS ModuleCompiler
     bool addExportedFunction(const Func *func, PropertyName *maybeFieldName) {
         AsmJSModule::ArgCoercionVector argCoercions;
         const VarTypeVector &args = func->sig().args();
         if (!argCoercions.resize(args.length()))
             return false;
         for (unsigned i = 0; i < args.length(); i++)
             argCoercions[i] = args[i].toCoercion();
         AsmJSModule::ReturnType retType = func->sig().retType().toModuleReturnType();
-        uint32_t line, column;
-        parser_.tokenStream.srcCoords.lineNumAndColumnIndex(func->srcOffset(), &line, &column);
-        return module_->addExportedFunction(func->name(), line, column,
-                                            func->srcOffset(), func->endOffset(), maybeFieldName,
-                                            Move(argCoercions), retType);
+        return module_->addExportedFunction(func->name(), func->srcOffset(), func->endOffset(),
+                                            maybeFieldName, Move(argCoercions), retType);
     }
     bool addExit(unsigned ffiIndex, PropertyName *name, Signature &&sig, unsigned *exitIndex) {
         ExitDescriptor exitDescriptor(name, Move(sig));
         ExitMap::AddPtr p = exits_.lookupForAdd(exitDescriptor);
         if (p) {
             *exitIndex = p->value();
             return true;
         }
         if (!module_->addExit(ffiIndex, exitIndex))
             return false;
         return exits_.add(p, Move(exitDescriptor), *exitIndex);
     }
-    bool addGlobalAccess(AsmJSGlobalAccess access) {
-        return globalAccesses_.append(access);
+    bool addFunctionName(PropertyName *name, uint32_t *index) {
+        return module_->addFunctionName(name, index);
     }
 
     // Note a constraint on the minimum size of the heap.  The heap size is
     // constrained when linking to be at least the maximum of all such constraints.
     void requireHeapLengthToBeAtLeast(uint32_t len) {
         module_->requireHeapLengthToBeAtLeast(len);
     }
     uint32_t minHeapLength() const {
         return module_->minHeapLength();
     }
     LifoAlloc &lifo() {
         return moduleLifo_;
     }
 
-    bool collectAccesses(MIRGenerator &gen) {
-        if (!module_->addHeapAccesses(gen.heapAccesses()))
-            return false;
-        if (!globalAccesses_.appendAll(gen.globalAccesses()))
-            return false;
-        return true;
-    }
-
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     bool trackProfiledFunction(const Func &func, unsigned endCodeOffset) {
         unsigned lineno = 0U, columnIndex = 0U;
-        parser().tokenStream.srcCoords.lineNumAndColumnIndex(func.srcOffset(), &lineno, &columnIndex);
+        tokenStream().srcCoords.lineNumAndColumnIndex(func.srcOffset(), &lineno, &columnIndex);
         unsigned startCodeOffset = func.code()->offset();
         return module_->trackProfiledFunction(func.name(), startCodeOffset, endCodeOffset,
                                               lineno, columnIndex);
     }
 #endif
 
 #ifdef JS_ION_PERF
     bool trackPerfProfiledBlocks(AsmJSPerfSpewer &perfSpewer, const Func &func, unsigned endCodeOffset) {
         unsigned startCodeOffset = func.code()->offset();
         perfSpewer.noteBlocksOffsets();
         unsigned endInlineCodeOffset = perfSpewer.endInlineCode.offset();
         return module_->trackPerfProfiledBlocks(func.name(), startCodeOffset, endInlineCodeOffset,
                                                 endCodeOffset, perfSpewer.basicBlocks());
     }
 #endif
 
-    bool addFunctionCounts(IonScriptCounts *counts) {
-        return module_->addFunctionCounts(counts);
-    }
-
     void finishFunctionBodies() {
         JS_ASSERT(!finishedFunctionBodies_);
         masm_.align(AsmJSPageSize);
         finishedFunctionBodies_ = true;
         module_->initFunctionBytes(masm_.size());
     }
 
     void setInterpExitOffset(unsigned exitIndex) {
@@ -1513,29 +1497,36 @@ class MOZ_STACK_CLASS ModuleCompiler
                                msTotal,
                                storedInCache ? "stored in cache" : "not stored in cache",
                                slowFuns ? slowFuns.get() : ""));
 #endif
     }
 
     bool finish(ScopedJSDeletePtr<AsmJSModule> *module)
     {
-        module_->initFuncEnd(parser_.tokenStream.currentToken().pos.end,
-                             parser_.tokenStream.peekTokenPos().end);
+        module_->initFuncEnd(tokenStream().currentToken().pos.end,
+                             tokenStream().peekTokenPos().end);
         masm_.finish();
         if (masm_.oom())
             return false;
 
+        module_->assignCallSites(masm_.extractCallSites());
+        module_->assignHeapAccesses(masm_.extractAsmJSHeapAccesses());
+
 #if defined(JS_CODEGEN_ARM)
         // Now that compilation has finished, we need to update offsets to
         // reflect actual offsets (an ARM distinction).
         for (unsigned i = 0; i < module_->numHeapAccesses(); i++) {
             AsmJSHeapAccess &a = module_->heapAccess(i);
             a.setOffset(masm_.actualOffset(a.offset()));
         }
+        for (unsigned i = 0; i < module_->numCallSites(); i++) {
+            CallSite &c = module_->callSite(i);
+            c.setReturnAddressOffset(masm_.actualOffset(c.returnAddressOffset()));
+        }
 #endif
 
         // The returned memory is owned by module_.
         if (!module_->allocateAndCopyCode(cx_, masm_))
             return false;
 
         // c.f. JitCode::copyFrom
         JS_ASSERT(masm_.jumpRelocationTableBytes() == 0);
@@ -1600,32 +1591,32 @@ class MOZ_STACK_CLASS ModuleCompiler
                     return false;
             }
         }
 
 #if defined(JS_CODEGEN_X86)
         // Global data accesses in x86 need to be patched with the absolute
         // address of the global. Globals are allocated sequentially after the
         // code section so we can just use an RelativeLink.
-        for (unsigned i = 0; i < globalAccesses_.length(); i++) {
-            AsmJSGlobalAccess a = globalAccesses_[i];
+        for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
+            AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
             AsmJSModule::RelativeLink link;
             link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
             link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
             if (!module_->addRelativeLink(link))
                 return false;
         }
 #endif
 
 #if defined(JS_CODEGEN_X64)
         // Global data accesses on x64 use rip-relative addressing and thus do
         // not need patching after deserialization.
         uint8_t *code = module_->codeBase();
-        for (unsigned i = 0; i < globalAccesses_.length(); i++) {
-            AsmJSGlobalAccess a = globalAccesses_[i];
+        for (unsigned i = 0; i < masm_.numAsmJSGlobalAccesses(); i++) {
+            AsmJSGlobalAccess a = masm_.asmJSGlobalAccess(i);
             masm_.patchAsmJSGlobalAccess(a.patchAt, code, module_->globalData(), a.globalDataOffset);
         }
 #endif
 
         // Absolute links
         for (size_t i = 0; i < masm_.numAsmJSAbsoluteLinks(); i++) {
             AsmJSAbsoluteLink src = masm_.asmJSAbsoluteLink(i);
             AsmJSModule::AbsoluteLink link;
@@ -1897,16 +1888,17 @@ class FunctionCompiler
     typedef js::Vector<TypedValue> VarInitializerVector;
     typedef HashMap<PropertyName*, BlockVector> LabeledBlockMap;
     typedef HashMap<ParseNode*, BlockVector> UnlabeledBlockMap;
     typedef js::Vector<ParseNode*, 4> NodeStack;
 
     ModuleCompiler &       m_;
     LifoAlloc &            lifo_;
     ParseNode *            fn_;
+    uint32_t               functionNameIndex_;
 
     LocalMap               locals_;
     VarInitializerVector   varInitializers_;
     Maybe<RetType>         alreadyReturned_;
 
     TempAllocator *        alloc_;
     MIRGraph *             graph_;
     CompileInfo *          info_;
@@ -1917,21 +1909,25 @@ class FunctionCompiler
 
     NodeStack              loopStack_;
     NodeStack              breakableStack_;
     UnlabeledBlockMap      unlabeledBreaks_;
     UnlabeledBlockMap      unlabeledContinues_;
     LabeledBlockMap        labeledBreaks_;
     LabeledBlockMap        labeledContinues_;
 
+    static const uint32_t NO_FUNCTION_NAME_INDEX = UINT32_MAX;
+    JS_STATIC_ASSERT(NO_FUNCTION_NAME_INDEX > CallSiteDesc::FUNCTION_NAME_INDEX_MAX);
+
   public:
     FunctionCompiler(ModuleCompiler &m, ParseNode *fn, LifoAlloc &lifo)
       : m_(m),
         lifo_(lifo),
         fn_(fn),
+        functionNameIndex_(NO_FUNCTION_NAME_INDEX),
         locals_(m.cx()),
         varInitializers_(m.cx()),
         alloc_(nullptr),
         graph_(nullptr),
         info_(nullptr),
         mirGen_(nullptr),
         curBlock_(nullptr),
         loopStack_(m.cx()),
@@ -2024,18 +2020,16 @@ class FunctionCompiler
         const JitCompileOptions options;
         mirGen_ = lifo_.new_<MIRGenerator>(CompileCompartment::get(cx()->compartment()),
                                            options, alloc_,
                                            graph_, info_, optimizationInfo);
 
         if (!newBlock(/* pred = */ nullptr, &curBlock_, fn_))
             return false;
 
-        curBlock_->add(MAsmJSCheckOverRecursed::New(alloc(), &m_.stackOverflowLabel()));
-
         for (ABIArgTypeIter i = argTypes; !i.done(); i++) {
             MAsmJSParameter *ins = MAsmJSParameter::New(alloc(), *i, i.mirType());
             curBlock_->add(ins);
             curBlock_->initSlot(info().localSlot(i.index()), ins);
             if (!mirGen_->ensureBallast())
                 return false;
         }
         unsigned firstLocalSlot = argTypes.length();
@@ -2273,37 +2267,39 @@ class FunctionCompiler
     // between evaluating an argument and making the call, another argument
     // evaluation could perform a call that also needs to store to the stack.
     // When this occurs childClobbers_ = true and the parent expression's
     // arguments are stored above the maximum depth clobbered by a child
     // expression.
 
     class Call
     {
+        ParseNode *node_;
         ABIArgGenerator abi_;
         uint32_t prevMaxStackBytes_;
         uint32_t maxChildStackBytes_;
         uint32_t spIncrement_;
         Signature sig_;
         MAsmJSCall::Args regArgs_;
         js::Vector<MAsmJSPassStackArg*> stackArgs_;
         bool childClobbers_;
 
         friend class FunctionCompiler;
 
       public:
-        Call(FunctionCompiler &f, RetType retType)
-          : prevMaxStackBytes_(0),
+        Call(FunctionCompiler &f, ParseNode *callNode, RetType retType)
+          : node_(callNode),
+            prevMaxStackBytes_(0),
             maxChildStackBytes_(0),
             spIncrement_(0),
             sig_(f.m().lifo(), retType),
             regArgs_(f.cx()),
             stackArgs_(f.cx()),
             childClobbers_(false)
-        {}
+        { }
         Signature &sig() { return sig_; }
         const Signature &sig() const { return sig_; }
     };
 
     void startCallArgs(Call *call)
     {
         if (inDeadCode())
             return;
@@ -2359,20 +2355,31 @@ class FunctionCompiler
 
   private:
     bool callPrivate(MAsmJSCall::Callee callee, const Call &call, MIRType returnType, MDefinition **def)
     {
         if (inDeadCode()) {
             *def = nullptr;
             return true;
         }
-        MAsmJSCall *ins = MAsmJSCall::New(alloc(), callee, call.regArgs_, returnType,
+
+        uint32_t line, column;
+        m_.tokenStream().srcCoords.lineNumAndColumnIndex(call.node_->pn_pos.begin, &line, &column);
+
+        if (functionNameIndex_ == NO_FUNCTION_NAME_INDEX) {
+            if (!m_.addFunctionName(FunctionName(fn_), &functionNameIndex_))
+                return false;
+        }
+
+        CallSiteDesc desc(line, column, functionNameIndex_);
+        MAsmJSCall *ins = MAsmJSCall::New(alloc(), desc, callee, call.regArgs_, returnType,
                                           call.spIncrement_);
         if (!ins)
             return false;
+
         curBlock_->add(ins);
         *def = ins;
         return true;
     }
 
   public:
     bool internalCall(const ModuleCompiler::Func &func, const Call &call, MDefinition **def)
     {
@@ -2763,17 +2770,17 @@ class FunctionCompiler
 
     /*************************************************************************/
   private:
     void noteBasicBlockPosition(MBasicBlock *blk, ParseNode *pn)
     {
 #if defined(JS_ION_PERF)
         if (pn) {
             unsigned line = 0U, column = 0U;
-            m().parser().tokenStream.srcCoords.lineNumAndColumnIndex(pn->pn_pos.begin, &line, &column);
+            m().tokenStream().srcCoords.lineNumAndColumnIndex(pn->pn_pos.begin, &line, &column);
             blk->setLineno(line);
             blk->setColumnIndex(column);
         }
 #endif
     }
 
     bool newBlockWithDepth(MBasicBlock *pred, unsigned loopDepth, MBasicBlock **block, ParseNode *pn)
     {
@@ -3878,17 +3885,17 @@ CheckIsVarType(FunctionCompiler &f, Pars
         return f.failf(argNode, "%s is not a subtype of int, float or double", type.toChars());
     return true;
 }
 
 static bool
 CheckInternalCall(FunctionCompiler &f, ParseNode *callNode, PropertyName *calleeName,
                   RetType retType, MDefinition **def, Type *type)
 {
-    FunctionCompiler::Call call(f, retType);
+    FunctionCompiler::Call call(f, callNode, retType);
 
     if (!CheckCallArgs(f, callNode, CheckIsVarType, &call))
         return false;
 
     ModuleCompiler::Func *callee;
     if (!CheckFunctionSignature(f.m(), callNode, Move(call.sig()), calleeName, &callee))
         return false;
 
@@ -3954,17 +3961,17 @@ CheckFuncPtrCall(FunctionCompiler &f, Pa
     MDefinition *indexDef;
     Type indexType;
     if (!CheckExpr(f, indexNode, &indexDef, &indexType))
         return false;
 
     if (!indexType.isIntish())
         return f.failf(indexNode, "%s is not a subtype of intish", indexType.toChars());
 
-    FunctionCompiler::Call call(f, retType);
+    FunctionCompiler::Call call(f, callNode, retType);
 
     if (!CheckCallArgs(f, callNode, CheckIsVarType, &call))
         return false;
 
     ModuleCompiler::FuncPtrTable *table;
     if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(call.sig()), mask, &table))
         return false;
 
@@ -3987,17 +3994,17 @@ static bool
 CheckFFICall(FunctionCompiler &f, ParseNode *callNode, unsigned ffiIndex, RetType retType,
              MDefinition **def, Type *type)
 {
     PropertyName *calleeName = CallCallee(callNode)->name();
 
     if (retType == RetType::Float)
         return f.fail(callNode, "FFI calls can't return float");
 
-    FunctionCompiler::Call call(f, retType);
+    FunctionCompiler::Call call(f, callNode, retType);
     if (!CheckCallArgs(f, callNode, CheckIsExternType, &call))
         return false;
 
     unsigned exitIndex;
     if (!f.m().addExit(ffiIndex, calleeName, Move(call.sig()), &exitIndex))
         return false;
 
     if (!f.ffiCall(exitIndex, call, retType.toMIRType(), def))
@@ -4112,17 +4119,17 @@ CheckMathBuiltinCall(FunctionCompiler &f
       default: MOZ_ASSUME_UNREACHABLE("unexpected mathBuiltin function");
     }
 
     if (retType == RetType::Float && floatCallee == AsmJSImm_Invalid)
         return f.fail(callNode, "math builtin cannot be used as float");
     if (retType != RetType::Double && retType != RetType::Float)
         return f.failf(callNode, "return type of math function is double or float, used as %s", retType.toType().toChars());
 
-    FunctionCompiler::Call call(f, retType);
+    FunctionCompiler::Call call(f, callNode, retType);
     if (retType == RetType::Float && !CheckCallArgs(f, callNode, CheckIsMaybeFloat, &call))
         return false;
     if (retType == RetType::Double && !CheckCallArgs(f, callNode, CheckIsMaybeDouble, &call))
         return false;
 
     if (call.sig().args().length() != arity)
         return f.failf(callNode, "call passed %u arguments, expected %u", call.sig().args().length(), arity);
 
@@ -5314,17 +5321,17 @@ CheckStatement(FunctionCompiler &f, Pars
     }
 
     return f.fail(stmt, "unexpected statement kind");
 }
 
 static bool
 ParseFunction(ModuleCompiler &m, ParseNode **fnOut)
 {
-    TokenStream &tokenStream = m.parser().tokenStream;
+    TokenStream &tokenStream = m.tokenStream();
 
     DebugOnly<TokenKind> tk = tokenStream.getToken();
     JS_ASSERT(tk == TOK_FUNCTION);
 
     RootedPropertyName name(m.cx());
 
     TokenKind tt = tokenStream.getToken();
     if (tt == TOK_NAME) {
@@ -5354,17 +5361,17 @@ ParseFunction(ModuleCompiler &m, ParseNo
     FunctionBox *funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator);
     if (!funbox)
         return false;
 
     Directives newDirectives = directives;
     AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives,
                             outerpc->staticLevel + 1, outerpc->blockidGen,
                             /* blockScopeDepth = */ 0);
-    if (!funpc.init(m.parser().tokenStream))
+    if (!funpc.init(tokenStream))
         return false;
 
     if (!m.parser().functionArgsAndBodyGeneric(fn, fun, Normal, Statement, &newDirectives))
         return false;
 
     if (tokenStream.hadError() || directives != newDirectives)
         return false;
 
@@ -5465,29 +5472,20 @@ GenerateCode(ModuleCompiler &m, ModuleCo
     // that there is a single linear code segment for each module. To avoid
     // spiking memory, a LifoAllocScope in the caller frees all MIR/LIR
     // after each function is compiled. This method is responsible for cleaning
     // out any dangling pointers that the MacroAssembler may have kept.
     m.masm().resetForNewCodeGenerator(mir.alloc());
 
     m.masm().bind(func.code());
 
-    ScopedJSDeletePtr<CodeGenerator> codegen(jit::GenerateCode(&mir, &lir, &m.masm()));
-    if (!codegen)
+    ScopedJSDeletePtr<CodeGenerator> codegen(js_new<CodeGenerator>(&mir, &lir, &m.masm()));
+    if (!codegen || !codegen->generateAsmJS(&m.stackOverflowLabel()))
         return m.fail(nullptr, "internal codegen failure (probably out of memory)");
 
-    if (!m.collectAccesses(mir))
-        return false;
-
-    jit::IonScriptCounts *counts = codegen->extractUnassociatedScriptCounts();
-    if (counts && !m.addFunctionCounts(counts)) {
-        js_delete(counts);
-        return false;
-    }
-
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     // Profiling might not be active now, but it may be activated later (perhaps
     // after the module has been cached and reloaded from the cache). Function
     // profiling info isn't huge, so store it always (in --enable-profiling
     // builds, which is only Nightly builds, but default).
     if (!m.trackProfiledFunction(func, m.masm().size()))
         return false;
 #endif
@@ -6043,16 +6041,26 @@ static unsigned
 StackDecrementForCall(MacroAssembler &masm, const VectorT &argTypes, unsigned extraBytes = 0)
 {
     return StackDecrementForCall(masm, StackArgBytes(argTypes) + extraBytes);
 }
 
 static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
                                              NonVolatileRegs.fpus().size() * sizeof(double);
 
+// On arm, we need to include an extra word of space at the top of the stack so
+// we can explicitly store the return address before making the call to C++ or
+// Ion. On x86/x64, this isn't necessary since the call instruction pushes the
+// return address.
+#ifdef JS_CODEGEN_ARM
+static const unsigned MaybeRetAddr = sizeof(void*);
+#else
+static const unsigned MaybeRetAddr = 0;
+#endif
+
 static bool
 GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFunc)
 {
     MacroAssembler &masm = m.masm();
 
     // In constrast to the system ABI, the Ion convention is that all registers
     // are clobbered by calls. Thus, we must save the caller's non-volatile
     // registers.
@@ -6122,17 +6130,17 @@ GenerateEntry(ModuleCompiler &m, const A
                 masm.storeDouble(ScratchFloatReg, Address(StackPointer, iter->offsetFromArgBase()));
             }
             break;
         }
     }
 
     // Call into the real function.
     AssertStackAlignment(masm);
-    masm.call(func.code());
+    masm.call(CallSiteDesc::Entry(), func.code());
 
     // Pop the stack and recover the original 'argv' argument passed to the
     // trampoline (which was pushed on the stack).
     masm.freeStack(stackDec);
     masm.Pop(argv);
 
     // Store the return value in argv[0]
     switch (func.sig().retType().which()) {
@@ -6316,33 +6324,36 @@ GenerateFFIInterpreterExit(ModuleCompile
 
     MIRType typeArray[] = { MIRType_Pointer,   // cx
                             MIRType_Pointer,   // exitDatum
                             MIRType_Int32,     // argc
                             MIRType_Pointer }; // argv
     MIRTypeVector invokeArgTypes(m.cx());
     invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
-    // Reserve space for a call to InvokeFromAsmJS_* and an array of values
-    // passed to this FFI call.
+    // The stack layout looks like:
+    // | return address | stack arguments | array of values |
     unsigned arraySize = Max<size_t>(1, exit.sig().args().length()) * sizeof(Value);
-    unsigned stackDec = StackDecrementForCall(masm, invokeArgTypes, arraySize);
+    unsigned stackDec = StackDecrementForCall(masm, invokeArgTypes, arraySize + MaybeRetAddr);
     masm.reserveStack(stackDec);
 
     // Fill the argument array.
     unsigned offsetToCallerStackArgs = AlignmentAtPrologue + masm.framePushed();
-    unsigned offsetToArgv = StackArgBytes(invokeArgTypes);
+    unsigned offsetToArgv = StackArgBytes(invokeArgTypes) + MaybeRetAddr;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
     FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
 
     // Prepare the arguments for the call to InvokeFromAsmJS_*.
     ABIArgMIRTypeIter i(invokeArgTypes);
     Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
     LoadAsmJSActivationIntoRegister(masm, activation);
 
+    // Record sp in the AsmJSActivation for stack-walking.
+    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
+
     // argument 0: cx
     if (i->kind() == ABIArg::GPR) {
         LoadJSContextFromActivation(masm, activation, i->gpr());
     } else {
         LoadJSContextFromActivation(masm, activation, scratch);
         masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
     }
     i++;
@@ -6372,26 +6383,26 @@ GenerateFFIInterpreterExit(ModuleCompile
     }
     i++;
     JS_ASSERT(i.done());
 
     // Make the call, test whether it succeeded, and extract the return value.
     AssertStackAlignment(masm);
     switch (exit.sig().retType().which()) {
       case RetType::Void:
-        masm.call(AsmJSImm_InvokeFromAsmJS_Ignore);
+        masm.callExit(AsmJSImm_InvokeFromAsmJS_Ignore, i.stackBytesConsumedSoFar());
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         break;
       case RetType::Signed:
-        masm.call(AsmJSImm_InvokeFromAsmJS_ToInt32);
+        masm.callExit(AsmJSImm_InvokeFromAsmJS_ToInt32, i.stackBytesConsumedSoFar());
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         masm.unboxInt32(argv, ReturnReg);
         break;
       case RetType::Double:
-        masm.call(AsmJSImm_InvokeFromAsmJS_ToNumber);
+        masm.callExit(AsmJSImm_InvokeFromAsmJS_ToNumber, i.stackBytesConsumedSoFar());
         masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
         masm.loadDouble(argv, ReturnFloatReg);
         break;
       case RetType::Float:
         MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be returned from a FFI");
         break;
     }
 
@@ -6410,26 +6421,30 @@ GenerateOOLConvert(ModuleCompiler &m, Re
                             MIRType_Pointer }; // argv
     MIRTypeVector callArgTypes(m.cx());
     callArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
 
     // The stack is assumed to be aligned.  The frame is allocated by GenerateFFIIonExit and
     // the stack usage here needs to kept in sync with GenerateFFIIonExit.
 
     // Store value
-    unsigned offsetToArgv = StackArgBytes(callArgTypes);
+    unsigned offsetToArgv = StackArgBytes(callArgTypes) + MaybeRetAddr;
     masm.storeValue(JSReturnOperand, Address(StackPointer, offsetToArgv));
 
+    Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
+    Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
+    LoadAsmJSActivationIntoRegister(masm, activation);
+
+    // Record sp in the AsmJSActivation for stack-walking.
+    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
+
     // Store real arguments
     ABIArgMIRTypeIter i(callArgTypes);
-    Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
 
     // argument 0: cx
-    Register activation = ABIArgGenerator::NonArgReturnVolatileReg1;
-    LoadAsmJSActivationIntoRegister(masm, activation);
     if (i->kind() == ABIArg::GPR) {
         LoadJSContextFromActivation(masm, activation, i->gpr());
     } else {
         LoadJSContextFromActivation(masm, activation, scratch);
         masm.storePtr(scratch, Address(StackPointer, i->offsetFromArgBase()));
     }
     i++;
 
@@ -6443,27 +6458,27 @@ GenerateOOLConvert(ModuleCompiler &m, Re
     }
     i++;
     JS_ASSERT(i.done());
 
     // Call
     AssertStackAlignment(masm);
     switch (retType.which()) {
       case RetType::Signed:
-          masm.call(AsmJSImm_CoerceInPlace_ToInt32);
-          masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
-          masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
-          break;
+        masm.callExit(AsmJSImm_CoerceInPlace_ToInt32, i.stackBytesConsumedSoFar());
+        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
+        masm.unboxInt32(Address(StackPointer, offsetToArgv), ReturnReg);
+        break;
       case RetType::Double:
-          masm.call(AsmJSImm_CoerceInPlace_ToNumber);
-          masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
-          masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnFloatReg);
-          break;
+        masm.callExit(AsmJSImm_CoerceInPlace_ToNumber, i.stackBytesConsumedSoFar());
+        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
+        masm.loadDouble(Address(StackPointer, offsetToArgv), ReturnFloatReg);
+        break;
       default:
-          MOZ_ASSUME_UNREACHABLE("Unsupported convert type");
+        MOZ_ASSUME_UNREACHABLE("Unsupported convert type");
     }
 }
 
 static void
 GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit,
                          unsigned exitIndex, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
@@ -6483,38 +6498,29 @@ GenerateFFIIonExit(ModuleCompiler &m, co
                                                        (1<<lr.code())),
                                     FloatRegisterSet(uint32_t(0))));
 #endif
 
     // The stack frame is used for the call into Ion and also for calls into C for OOL
     // conversion of the result.  A frame large enough for both is allocated.
     //
     // Arguments to the Ion function are in the following order on the stack:
-    // descriptor | callee | argc | this | arg1 | arg2 | ...
+    // | return address | descriptor | callee | argc | this | arg1 | arg2 | ...
     unsigned argBytes = 3 * sizeof(size_t) + (1 + exit.sig().args().length()) * sizeof(Value);
-
-    // On ARM, we call with ma_callIonNoPush which, following the Ion calling convention,
-    // stores the return address into *sp. This means we need to include an extra word of
-    // space before the arguments in the stack allocation. (On x86/x64, the call
-    // instruction does the push itself and the ABI just requires us to be aligned before
-    // the call instruction.)
-    unsigned offsetToArgs = 0;
-#if defined(JS_CODEGEN_ARM)
-    offsetToArgs += sizeof(size_t);
-#endif
-
+    unsigned offsetToArgs = MaybeRetAddr;
     unsigned stackDecForIonCall = StackDecrementForCall(masm, argBytes + offsetToArgs);
 
     // Reserve space for a call to AsmJSImm_CoerceInPlace_* and an array of values used by
     // OOLConvert which reuses the same frame. This code needs to be kept in sync with the
     // stack usage in GenerateOOLConvert.
     MIRType typeArray[] = { MIRType_Pointer, MIRType_Pointer }; // cx, argv
     MIRTypeVector callArgTypes(m.cx());
     callArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray));
-    unsigned stackDecForOOLCall = StackDecrementForCall(masm, callArgTypes, sizeof(Value));
+    unsigned oolExtraBytes = sizeof(Value) + MaybeRetAddr;
+    unsigned stackDecForOOLCall = StackDecrementForCall(masm, callArgTypes, oolExtraBytes);
 
     // Allocate a frame large enough for both of the above calls.
     unsigned stackDec = Max(stackDecForIonCall, stackDecForOOLCall);
 
     masm.reserveStack(stackDec);
     AssertStackAlignment(masm);
 
     // 1. Descriptor
@@ -6526,20 +6532,20 @@ GenerateFFIIonExit(ModuleCompiler &m, co
     // 2. Callee
     Register callee = ABIArgGenerator::NonArgReturnVolatileReg0;
     Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
 
     // 2.1. Get ExitDatum
     unsigned globalDataOffset = m.module().exitIndexToGlobalDataOffset(exitIndex);
 #if defined(JS_CODEGEN_X64)
     CodeOffsetLabel label2 = masm.leaRipRelative(callee);
-    m.addGlobalAccess(AsmJSGlobalAccess(label2.offset(), globalDataOffset));
+    m.masm().append(AsmJSGlobalAccess(label2.offset(), globalDataOffset));
 #elif defined(JS_CODEGEN_X86)
     CodeOffsetLabel label2 = masm.movlWithPatch(Imm32(0), callee);
-    m.addGlobalAccess(AsmJSGlobalAccess(label2.offset(), globalDataOffset));
+    m.masm().append(AsmJSGlobalAccess(label2.offset(), globalDataOffset));
 #else
     masm.lea(Operand(GlobalReg, globalDataOffset), callee);
 #endif
 
     // 2.2. Get callee
     masm.loadPtr(Address(callee, offsetof(AsmJSModule::ExitDatum, fun)), callee);
 
     // 2.3. Save callee
@@ -6587,16 +6593,19 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         JS_ASSERT(callee == AsmJSIonExitRegCallee);
         Register reg0 = AsmJSIonExitRegE0;
         Register reg1 = AsmJSIonExitRegE1;
         Register reg2 = AsmJSIonExitRegE2;
         Register reg3 = AsmJSIonExitRegE3;
 
         LoadAsmJSActivationIntoRegister(masm, reg0);
 
+        // Record sp in the AsmJSActivation for stack-walking.
+        masm.storePtr(StackPointer, Address(reg0, AsmJSActivation::offsetOfExitSP()));
+
         // The following is inlined:
         //   JSContext *cx = activation->cx();
         //   Activation *act = cx->mainThread().activation();
         //   act.active_ = true;
         //   act.prevIonTop_ = cx->mainThread().ionTop;
         //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
         //   cx->mainThread().jitJSContext = cx;
         // On the ARM store8() uses the secondScratchReg (lr) as a temp.
@@ -6613,24 +6622,17 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevIonTop()));
         masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext()));
         masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext));
     }
 
     // 2. Call
     AssertStackAlignment(masm);
-#if defined(JS_CODEGEN_ARM)
-    masm.ma_callIonNoPush(callee);
-    // The return address has been popped from the stack, so adjust the stack
-    // without changing the frame-pushed counter to keep the stack aligned.
-    masm.subPtr(Imm32(4), sp);
-#else
-    masm.callIon(callee);
-#endif
+    masm.callIonFromAsmJS(callee);
     AssertStackAlignment(masm);
 
     {
         // Disable Activation.
         //
         // This sequence needs three registers, and must preserve the JSReturnReg_Data and
         // JSReturnReg_Type, so there are five live registers.
         JS_ASSERT(JSReturnReg_Data == AsmJSIonExitRegReturnData);
@@ -6734,40 +6736,50 @@ GenerateFFIExit(ModuleCompiler &m, const
 // all the frames.
 static bool
 GenerateStackOverflowExit(ModuleCompiler &m, Label *throwLabel)
 {
     MacroAssembler &masm = m.masm();
     masm.align(CodeAlignment);
     masm.bind(&m.stackOverflowLabel());
 
-#if defined(JS_CODEGEN_X86)
-    // Ensure that at least one slot is pushed for passing 'cx' below.
-    masm.push(Imm32(0));
-#endif
-
-    // We know that StackPointer is word-aligned, but nothing past that. Thus,
-    // we must align StackPointer dynamically. Don't worry about restoring
-    // StackPointer since throwLabel will clobber StackPointer immediately.
-    masm.andPtr(Imm32(~(StackAlignment - 1)), StackPointer);
-    if (ShadowStackSpace)
-        masm.subPtr(Imm32(ShadowStackSpace), StackPointer);
-
-    // Prepare the arguments for the call to js_ReportOverRecursed.
-#if defined(JS_CODEGEN_X86)
-    LoadAsmJSActivationIntoRegister(masm, eax);
-    LoadJSContextFromActivation(masm, eax, eax);
-    masm.storePtr(eax, Address(StackPointer, 0));
-#else
-    LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
-    LoadJSContextFromActivation(masm, IntArgReg0, IntArgReg0);
-#endif
-    masm.call(AsmJSImm_ReportOverRecursed);
+    // The overflow check always occurs before the initial function-specific
+    // stack-size adjustment. See CodeGenerator::generateAsmJSPrologue.
+    masm.setFramePushed(AlignmentMidPrologue - AlignmentAtPrologue);
+
+    MIRTypeVector argTypes(m.cx());
+    argTypes.infallibleAppend(MIRType_Pointer); // cx
+
+    unsigned stackDec = StackDecrementForCall(masm, argTypes, MaybeRetAddr);
+    masm.reserveStack(stackDec);
+
+    Register activation = ABIArgGenerator::NonArgReturnVolatileReg0;
+    LoadAsmJSActivationIntoRegister(masm, activation);
+
+    // Record sp in the AsmJSActivation for stack-walking.
+    masm.storePtr(StackPointer, Address(activation, AsmJSActivation::offsetOfExitSP()));
+
+    ABIArgMIRTypeIter i(argTypes);
+
+    // argument 0: cx
+    if (i->kind() == ABIArg::GPR) {
+        LoadJSContextFromActivation(masm, activation, i->gpr());
+    } else {
+        LoadJSContextFromActivation(masm, activation, activation);
+        masm.storePtr(activation, Address(StackPointer, i->offsetFromArgBase()));
+    }
+    i++;
+
+    JS_ASSERT(i.done());
+
+    AssertStackAlignment(masm);
+    masm.callExit(AsmJSImm_ReportOverRecursed, i.stackBytesConsumedSoFar());
+
+    // Don't worry about restoring the stack; throwLabel will pop everything.
     masm.jump(throwLabel);
-
     return !masm.oom();
 }
 
 // The operation-callback exit is called from arbitrarily-interrupted asm.js
 // code. That means we must first save *all* registers and restore *all*
 // registers (except the stack pointer) when we resume. The address to resume to
 // (assuming that js::HandleExecutionInterrupt doesn't indicate that the
 // execution should be aborted) is stored in AsmJSActivation::resumePC_.
@@ -6909,16 +6921,18 @@ GenerateThrowExit(ModuleCompiler &m, Lab
 
 static bool
 GenerateStubs(ModuleCompiler &m)
 {
     for (unsigned i = 0; i < m.module().numExportedFunctions(); i++) {
         m.setEntryOffset(i);
         if (!GenerateEntry(m, m.module().exportedFunction(i)))
             return false;
+        if (m.masm().oom())
+            return false;
     }
 
     Label throwLabel;
 
     // The order of the iterations here is non-deterministic, since
     // m.allExits() is a hash keyed by pointer values!
     for (ModuleCompiler::ExitMap::Range r = m.allExits(); !r.empty(); r.popFront()) {
         GenerateFFIExit(m, r.front().key(), r.front().value(), &throwLabel);
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -1,16 +1,19 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/AsmJSLink.h"
 
+#include "mozilla/BinarySearch.h"
+#include "mozilla/PodOperations.h"
+
 #ifdef MOZ_VTUNE
 # include "vtune/VTuneWrapper.h"
 #endif
 
 #include "jscntxt.h"
 #include "jsmath.h"
 #include "jsprf.h"
 #include "jswrapper.h"
@@ -24,17 +27,112 @@
 #endif
 #include "vm/StringBuffer.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::BinarySearch;
 using mozilla::IsNaN;
+using mozilla::PodZero;
+
+AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation *activation)
+{
+    if (!activation || activation->isInterruptedSP()) {
+        PodZero(this);
+        JS_ASSERT(done());
+        return;
+    }
+
+    module_ = &activation->module();
+    sp_ = activation->exitSP();
+
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+    // For calls to Ion/C++ on x86/x64, the exitSP is the SP right before the call
+    // to C++. Since the call instruction pushes the return address, we know
+    // that the return address is 1 word below exitSP.
+    returnAddress_ = *(uint8_t**)(sp_ - sizeof(void*));
+#else
+    // For calls to Ion/C++ on ARM, the *caller* pushes the return address on
+    // the stack. For Ion, this is just part of the ABI. For C++, the return
+    // address is explicitly pushed before the call since we cannot expect the
+    // callee to immediately push lr. This means that exitSP points to the
+    // return address.
+    returnAddress_ = *(uint8_t**)sp_;
+#endif
+
+    settle();
+}
+
+struct GetCallSite
+{
+    const AsmJSModule &module;
+    GetCallSite(const AsmJSModule &module) : module(module) {}
+    uint32_t operator[](size_t index) const {
+        return module.callSite(index).returnAddressOffset();
+    }
+};
+
+void
+AsmJSFrameIterator::popFrame()
+{
+    // After adding stackDepth, sp points to the word before the return address,
+    // on both ARM and x86/x64.
+    sp_ += callsite_->stackDepth();
+    returnAddress_ = *(uint8_t**)(sp_ - sizeof(void*));
+}
+
+void
+AsmJSFrameIterator::settle()
+{
+    while (true) {
+        uint32_t target = returnAddress_ - module_->codeBase();
+        size_t lowerBound = 0;
+        size_t upperBound = module_->numCallSites();
+
+        size_t match;
+        if (!BinarySearch(GetCallSite(*module_), lowerBound, upperBound, target, &match)) {
+            callsite_ = nullptr;
+            return;
+        }
+
+        callsite_ = &module_->callSite(match);
+
+        if (callsite_->isExit()) {
+            popFrame();
+            continue;
+        }
+
+        if (callsite_->isEntry()) {
+            callsite_ = nullptr;
+            return;
+        }
+
+        JS_ASSERT(callsite_->isNormal());
+        return;
+    }
+}
+
+JSAtom *
+AsmJSFrameIterator::functionDisplayAtom() const
+{
+    JS_ASSERT(!done());
+    return module_->functionName(callsite_->functionNameIndex());
+}
+
+unsigned
+AsmJSFrameIterator::computeLine(uint32_t *column) const
+{
+    JS_ASSERT(!done());
+    if (column)
+        *column = callsite_->column();
+    return callsite_->line();
+}
 
 static bool
 CloneModule(JSContext *cx, MutableHandle<AsmJSModuleObject*> moduleObj)
 {
     ScopedJSDeletePtr<AsmJSModule> module;
     if (!moduleObj->module().clone(cx, &module))
         return false;
 
@@ -403,18 +501,17 @@ CallAsmJS(JSContext *cx, unsigned argc, 
     }
 
     {
         // Push an AsmJSActivation to describe the asm.js frames we're about to
         // push when running this module. Additionally, push a JitActivation so
         // that the optimized asm.js-to-Ion FFI call path (which we want to be
         // very fast) can avoid doing so. The JitActivation is marked as
         // inactive so stack iteration will skip over it.
-        unsigned exportIndex = FunctionToExportedFunctionIndex(callee);
-        AsmJSActivation activation(cx, module, exportIndex);
+        AsmJSActivation activation(cx, module);
         JitActivation jitActivation(cx, /* firstFrameIsConstructing = */ false, /* active */ false);
 
         // Call the per-exported-function trampoline created by GenerateEntry.
         AsmJSModule::CodePtr enter = module.entryTrampoline(func);
         if (!CALL_GENERATED_ASMJS(enter, coercedArgs.begin(), module.globalData()))
             return false;
     }
 
--- a/js/src/jit/AsmJSLink.h
+++ b/js/src/jit/AsmJSLink.h
@@ -4,18 +4,43 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_AsmJSLink_h
 #define jit_AsmJSLink_h
 
 #include "NamespaceImports.h"
 
+class JSAtom;
+
 namespace js {
 
+class AsmJSActivation;
+class AsmJSModule;
+namespace jit { class CallSite; }
+
+// Iterates over the frames of a single AsmJSActivation.
+class AsmJSFrameIterator
+{
+    const AsmJSModule *module_;
+    const jit::CallSite *callsite_;
+    uint8_t *sp_;
+    uint8_t *returnAddress_;
+
+    void popFrame();
+    void settle();
+
+  public:
+    AsmJSFrameIterator(const AsmJSActivation *activation);
+    void operator++() { popFrame(); settle(); }
+    bool done() const { return !callsite_; }
+    JSAtom *functionDisplayAtom() const;
+    unsigned computeLine(uint32_t *column) const;
+};
+
 #ifdef JS_ION
 
 // Create a new JSFunction to replace originalFun as the representation of the
 // function defining the succesfully-validated module 'moduleObj'.
 extern JSFunction *
 NewAsmJSModuleFunction(ExclusiveContext *cx, JSFunction *originalFun, HandleObject moduleObj);
 
 // Return whether this is the js::Native returned by NewAsmJSModuleFunction.
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -366,38 +366,36 @@ AsmJSModule::~AsmJSModule()
                 continue;
 
             jit::DependentAsmJSModuleExit exit(this, i);
             script->ionScript()->removeDependentAsmJSModule(exit);
         }
 
         DeallocateExecutableMemory(code_, pod.totalBytes_);
     }
-
-    for (size_t i = 0; i < numFunctionCounts(); i++)
-        js_delete(functionCounts(i));
 }
 
 void
 AsmJSModule::addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModuleCode,
                            size_t *asmJSModuleData)
 {
     *asmJSModuleCode += pod.totalBytes_;
     *asmJSModuleData += mallocSizeOf(this) +
                         globals_.sizeOfExcludingThis(mallocSizeOf) +
                         exits_.sizeOfExcludingThis(mallocSizeOf) +
                         exports_.sizeOfExcludingThis(mallocSizeOf) +
+                        callSites_.sizeOfExcludingThis(mallocSizeOf) +
+                        functionNames_.sizeOfExcludingThis(mallocSizeOf) +
                         heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
                         profiledFunctions_.sizeOfExcludingThis(mallocSizeOf) +
 #endif
 #if defined(JS_ION_PERF)
                         perfProfiledBlocksFunctions_.sizeOfExcludingThis(mallocSizeOf) +
 #endif
-                        functionCounts_.sizeOfExcludingThis(mallocSizeOf) +
                         staticLinkData_.sizeOfExcludingThis(mallocSizeOf);
 }
 
 static void
 AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj)
 {
     fop->delete_(&obj->as<AsmJSModuleObject>().module());
 }
@@ -476,29 +474,41 @@ ReadScalar(const uint8_t *src, T *dst)
 
 static size_t
 SerializedNameSize(PropertyName *name)
 {
     return sizeof(uint32_t) +
            (name ? name->length() * sizeof(jschar) : 0);
 }
 
+size_t
+AsmJSModule::Name::serializedSize() const
+{
+    return SerializedNameSize(name_);
+}
+
 static uint8_t *
 SerializeName(uint8_t *cursor, PropertyName *name)
 {
     JS_ASSERT_IF(name, !name->empty());
     if (name) {
         cursor = WriteScalar<uint32_t>(cursor, name->length());
         cursor = WriteBytes(cursor, name->chars(), name->length() * sizeof(jschar));
     } else {
         cursor = WriteScalar<uint32_t>(cursor, 0);
     }
     return cursor;
 }
 
+uint8_t *
+AsmJSModule::Name::serialize(uint8_t *cursor) const
+{
+    return SerializeName(cursor, name_);
+}
+
 static const uint8_t *
 DeserializeName(ExclusiveContext *cx, const uint8_t *cursor, PropertyName **name)
 {
     uint32_t length;
     cursor = ReadScalar<uint32_t>(cursor, &length);
 
     if (length == 0) {
         *name = nullptr;
@@ -520,16 +530,29 @@ DeserializeName(ExclusiveContext *cx, co
     JSAtom *atom = AtomizeChars(cx, src, length);
     if (!atom)
         return nullptr;
 
     *name = atom->asPropertyName();
     return cursor + length * sizeof(jschar);
 }
 
+const uint8_t *
+AsmJSModule::Name::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
+{
+    return DeserializeName(cx, cursor, &name_);
+}
+
+bool
+AsmJSModule::Name::clone(ExclusiveContext *cx, Name *out) const
+{
+    out->name_ = name_;
+    return true;
+}
+
 template <class T>
 size_t
 SerializedVectorSize(const js::Vector<T, 0, SystemAllocPolicy> &vec)
 {
     size_t size = sizeof(uint32_t);
     for (size_t i = 0; i < vec.length(); i++)
         size += vec[i].serializedSize();
     return size;
@@ -787,16 +810,18 @@ AsmJSModule::serializedSize() const
     return sizeof(pod) +
            pod.codeBytes_ +
            SerializedNameSize(globalArgumentName_) +
            SerializedNameSize(importArgumentName_) +
            SerializedNameSize(bufferArgumentName_) +
            SerializedVectorSize(globals_) +
            SerializedVectorSize(exits_) +
            SerializedVectorSize(exports_) +
+           SerializedPodVectorSize(callSites_) +
+           SerializedVectorSize(functionNames_) +
            SerializedPodVectorSize(heapAccesses_) +
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
            SerializedVectorSize(profiledFunctions_) +
 #endif
            staticLinkData_.serializedSize();
 }
 
 uint8_t *
@@ -805,16 +830,18 @@ AsmJSModule::serialize(uint8_t *cursor) 
     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     cursor = WriteBytes(cursor, code_, pod.codeBytes_);
     cursor = SerializeName(cursor, globalArgumentName_);
     cursor = SerializeName(cursor, importArgumentName_);
     cursor = SerializeName(cursor, bufferArgumentName_);
     cursor = SerializeVector(cursor, globals_);
     cursor = SerializeVector(cursor, exits_);
     cursor = SerializeVector(cursor, exports_);
+    cursor = SerializePodVector(cursor, callSites_);
+    cursor = SerializeVector(cursor, functionNames_);
     cursor = SerializePodVector(cursor, heapAccesses_);
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     cursor = SerializeVector(cursor, profiledFunctions_);
 #endif
     cursor = staticLinkData_.serialize(cursor);
     return cursor;
 }
 
@@ -829,16 +856,18 @@ AsmJSModule::deserialize(ExclusiveContex
     (code_ = AllocateExecutableMemory(cx, pod.totalBytes_)) &&
     (cursor = ReadBytes(cursor, code_, pod.codeBytes_)) &&
     (cursor = DeserializeName(cx, cursor, &globalArgumentName_)) &&
     (cursor = DeserializeName(cx, cursor, &importArgumentName_)) &&
     (cursor = DeserializeName(cx, cursor, &bufferArgumentName_)) &&
     (cursor = DeserializeVector(cx, cursor, &globals_)) &&
     (cursor = DeserializeVector(cx, cursor, &exits_)) &&
     (cursor = DeserializeVector(cx, cursor, &exports_)) &&
+    (cursor = DeserializePodVector(cx, cursor, &callSites_)) &&
+    (cursor = DeserializeVector(cx, cursor, &functionNames_)) &&
     (cursor = DeserializePodVector(cx, cursor, &heapAccesses_)) &&
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     (cursor = DeserializeVector(cx, cursor, &profiledFunctions_)) &&
 #endif
     (cursor = staticLinkData_.deserialize(cx, cursor));
 
     loadedFromCache_ = true;
     return cursor;
@@ -896,16 +925,18 @@ AsmJSModule::clone(JSContext *cx, Scoped
 
     out.globalArgumentName_ = globalArgumentName_;
     out.importArgumentName_ = importArgumentName_;
     out.bufferArgumentName_ = bufferArgumentName_;
 
     if (!CloneVector(cx, globals_, &out.globals_) ||
         !CloneVector(cx, exits_, &out.exits_) ||
         !CloneVector(cx, exports_, &out.exports_) ||
+        !ClonePodVector(cx, callSites_, &out.callSites_) ||
+        !CloneVector(cx, functionNames_, &out.functionNames_) ||
         !ClonePodVector(cx, heapAccesses_, &out.heapAccesses_) ||
         !staticLinkData_.clone(cx, &out.staticLinkData_))
     {
         return false;
     }
 
     out.loadedFromCache_ = loadedFromCache_;
 
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -216,41 +216,36 @@ class AsmJSModule
     class ExportedFunction
     {
         PropertyName *name_;
         PropertyName *maybeFieldName_;
         ArgCoercionVector argCoercions_;
         struct Pod {
             ReturnType returnType_;
             uint32_t codeOffset_;
-            uint32_t line_;
-            uint32_t column_;
             // These two fields are offsets to the beginning of the ScriptSource
             // of the module, and thus invariant under serialization (unlike
             // absolute offsets into ScriptSource).
             uint32_t startOffsetInModule_;
             uint32_t endOffsetInModule_;
         } pod;
 
         friend class AsmJSModule;
 
         ExportedFunction(PropertyName *name,
-                         uint32_t line, uint32_t column,
                          uint32_t startOffsetInModule, uint32_t endOffsetInModule,
                          PropertyName *maybeFieldName,
                          ArgCoercionVector &&argCoercions,
                          ReturnType returnType)
         {
             name_ = name;
             maybeFieldName_ = maybeFieldName;
             argCoercions_ = mozilla::Move(argCoercions);
             pod.returnType_ = returnType;
             pod.codeOffset_ = UINT32_MAX;
-            pod.line_ = line;
-            pod.column_ = column;
             pod.startOffsetInModule_ = startOffsetInModule;
             pod.endOffsetInModule_ = endOffsetInModule;
             JS_ASSERT_IF(maybeFieldName_, name_->isTenured());
         }
 
         void trace(JSTracer *trc) {
             MarkStringUnbarriered(trc, &name_, "asm.js export name");
             if (maybeFieldName_)
@@ -269,22 +264,16 @@ class AsmJSModule
         void initCodeOffset(unsigned off) {
             JS_ASSERT(pod.codeOffset_ == UINT32_MAX);
             pod.codeOffset_ = off;
         }
 
         PropertyName *name() const {
             return name_;
         }
-        uint32_t line() const {
-            return pod.line_;
-        }
-        uint32_t column() const {
-            return pod.column_;
-        }
         uint32_t startOffsetInModule() const {
             return pod.startOffsetInModule_;
         }
         uint32_t endOffsetInModule() const {
             return pod.endOffsetInModule_;
         }
         PropertyName *maybeFieldName() const {
             return maybeFieldName_;
@@ -300,16 +289,30 @@ class AsmJSModule
         }
 
         size_t serializedSize() const;
         uint8_t *serialize(uint8_t *cursor) const;
         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
         bool clone(ExclusiveContext *cx, ExportedFunction *out) const;
     };
 
+    class Name
+    {
+        PropertyName *name_;
+      public:
+        Name() : name_(nullptr) {}
+        Name(PropertyName *name) : name_(name) {}
+        PropertyName *name() const { return name_; }
+        PropertyName *&name() { return name_; }
+        size_t serializedSize() const;
+        uint8_t *serialize(uint8_t *cursor) const;
+        const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
+        bool clone(ExclusiveContext *cx, Name *out) const;
+    };
+
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     // Function information to add to the VTune JIT profiler following linking.
     struct ProfiledFunction
     {
         PropertyName *name;
         struct Pod {
             unsigned startCodeOffset;
             unsigned endCodeOffset;
@@ -395,19 +398,21 @@ class AsmJSModule
         uint8_t *serialize(uint8_t *cursor) const;
         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
         bool clone(ExclusiveContext *cx, StaticLinkData *out) const;
 
         size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
     };
 
   private:
-    typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector;
     typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector;
     typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector;
+    typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector;
+    typedef Vector<jit::CallSite, 0, SystemAllocPolicy> CallSiteVector;
+    typedef Vector<Name, 0, SystemAllocPolicy> FunctionNameVector;
     typedef Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector;
     typedef Vector<jit::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector;
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector;
 #endif
 #if defined(JS_ION_PERF)
     typedef Vector<ProfiledBlocksFunction, 0, SystemAllocPolicy> ProfiledBlocksFunctionVector;
 #endif
@@ -415,16 +420,18 @@ class AsmJSModule
   private:
     PropertyName *                        globalArgumentName_;
     PropertyName *                        importArgumentName_;
     PropertyName *                        bufferArgumentName_;
 
     GlobalVector                          globals_;
     ExitVector                            exits_;
     ExportedFunctionVector                exports_;
+    CallSiteVector                        callSites_;
+    FunctionNameVector                    functionNames_;
     HeapAccessVector                      heapAccesses_;
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     ProfiledFunctionVector                profiledFunctions_;
 #endif
 #if defined(JS_ION_PERF)
     ProfiledBlocksFunctionVector          perfProfiledBlocksFunctions_;
 #endif
 
@@ -453,18 +460,16 @@ class AsmJSModule
     // The next two fields need to be kept out of the Pod as they depend on the
     // position of the module within the ScriptSource and thus aren't invariant
     // with caching.
     uint32_t                              funcStart_;
     uint32_t                              offsetToEndOfUseAsm_;
 
     ScriptSource *                        scriptSource_;
 
-    FunctionCountsVector                  functionCounts_;
-
     // This field is accessed concurrently when requesting an interrupt.
     // Access must be synchronized via the runtime's interrupt lock.
     mutable bool                          codeIsProtected_;
 
   public:
     explicit AsmJSModule(ScriptSource *scriptSource, uint32_t functStart,
                          uint32_t offsetToEndOfUseAsm, bool strict);
     ~AsmJSModule();
@@ -473,16 +478,18 @@ class AsmJSModule
         for (unsigned i = 0; i < globals_.length(); i++)
             globals_[i].trace(trc);
         for (unsigned i = 0; i < exports_.length(); i++)
             exports_[i].trace(trc);
         for (unsigned i = 0; i < exits_.length(); i++) {
             if (exitIndexToGlobalDatum(i).fun)
                 MarkObject(trc, &exitIndexToGlobalDatum(i).fun, "asm.js imported function");
         }
+        for (unsigned i = 0; i < functionNames_.length(); i++)
+            MarkStringUnbarriered(trc, &functionNames_[i].name(), "asm.js module function name");
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
         for (unsigned i = 0; i < profiledFunctions_.length(); i++)
             profiledFunctions_[i].trace(trc);
 #endif
 #if defined(JS_ION_PERF)
         for (unsigned i = 0; i < perfProfiledBlocksFunctions_.length(); i++)
             perfProfiledBlocksFunctions_[i].trace(trc);
 #endif
@@ -591,27 +598,23 @@ class AsmJSModule
         if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < sizeof(ExitDatum))
             return false;
         uint32_t globalDataOffset = globalDataBytes();
         JS_STATIC_ASSERT(sizeof(ExitDatum) % sizeof(void*) == 0);
         pod.funcPtrTableAndExitBytes_ += sizeof(ExitDatum);
         *exitIndex = unsigned(exits_.length());
         return exits_.append(Exit(ffiIndex, globalDataOffset));
     }
-    bool addFunctionCounts(jit::IonScriptCounts *counts) {
-        return functionCounts_.append(counts);
-    }
 
-    bool addExportedFunction(PropertyName *name, uint32_t line, uint32_t column,
-                             uint32_t srcStart, uint32_t srcEnd,
+    bool addExportedFunction(PropertyName *name, uint32_t srcStart, uint32_t srcEnd,
                              PropertyName *maybeFieldName,
                              ArgCoercionVector &&argCoercions,
                              ReturnType returnType)
     {
-        ExportedFunction func(name, line, column, srcStart, srcEnd, maybeFieldName,
+        ExportedFunction func(name, srcStart, srcEnd, maybeFieldName,
                               mozilla::Move(argCoercions), returnType);
         if (exports_.length() >= UINT32_MAX)
             return false;
         return exports_.append(mozilla::Move(func));
     }
     unsigned numExportedFunctions() const {
         return exports_.length();
     }
@@ -621,16 +624,27 @@ class AsmJSModule
     ExportedFunction &exportedFunction(unsigned i) {
         return exports_[i];
     }
     CodePtr entryTrampoline(const ExportedFunction &func) const {
         JS_ASSERT(func.pod.codeOffset_ != UINT32_MAX);
         return JS_DATA_TO_FUNC_PTR(CodePtr, code_ + func.pod.codeOffset_);
     }
 
+    bool addFunctionName(PropertyName *name, uint32_t *nameIndex) {
+        JS_ASSERT(name->isTenured());
+        if (functionNames_.length() > jit::CallSiteDesc::FUNCTION_NAME_INDEX_MAX)
+            return false;
+        *nameIndex = functionNames_.length();
+        return functionNames_.append(name);
+    }
+    PropertyName *functionName(uint32_t i) const {
+        return functionNames_[i].name();
+    }
+
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     bool trackProfiledFunction(PropertyName *name, unsigned startCodeOffset, unsigned endCodeOffset,
                                unsigned line, unsigned column)
     {
         ProfiledFunction func(name, startCodeOffset, endCodeOffset, line, column);
         return profiledFunctions_.append(func);
     }
     unsigned numProfiledFunctions() const {
@@ -682,22 +696,16 @@ class AsmJSModule
     uint8_t *interpExitTrampoline(const Exit &exit) const {
         JS_ASSERT(exit.interpCodeOffset_);
         return code_ + exit.interpCodeOffset_;
     }
     uint8_t *ionExitTrampoline(const Exit &exit) const {
         JS_ASSERT(exit.ionCodeOffset_);
         return code_ + exit.ionCodeOffset_;
     }
-    unsigned numFunctionCounts() const {
-        return functionCounts_.length();
-    }
-    jit::IonScriptCounts *functionCounts(unsigned i) {
-        return functionCounts_[i];
-    }
 
     // An Exit holds bookkeeping information about an exit; the ExitDatum
     // struct overlays the actual runtime data stored in the global data
     // section.
     struct ExitDatum
     {
         uint8_t *exit;
         HeapPtrFunction fun;
@@ -759,28 +767,42 @@ class AsmJSModule
         JS_ASSERT(pod.functionBytes_);
         JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
         return pod.functionBytes_;
     }
     bool containsPC(void *pc) const {
         return pc >= code_ && pc < (code_ + functionBytes());
     }
 
-    bool addHeapAccesses(const jit::AsmJSHeapAccessVector &accesses) {
-        return heapAccesses_.appendAll(accesses);
+    void assignHeapAccesses(jit::AsmJSHeapAccessVector &&accesses) {
+        heapAccesses_ = Move(accesses);
     }
     unsigned numHeapAccesses() const {
         return heapAccesses_.length();
     }
+    const jit::AsmJSHeapAccess &heapAccess(unsigned i) const {
+        return heapAccesses_[i];
+    }
     jit::AsmJSHeapAccess &heapAccess(unsigned i) {
         return heapAccesses_[i];
     }
-    const jit::AsmJSHeapAccess &heapAccess(unsigned i) const {
-        return heapAccesses_[i];
+
+    void assignCallSites(jit::CallSiteVector &&callsites) {
+        callSites_ = Move(callsites);
+    }
+    unsigned numCallSites() const {
+        return callSites_.length();
     }
+    const jit::CallSite &callSite(unsigned i) const {
+        return callSites_[i];
+    }
+    jit::CallSite &callSite(unsigned i) {
+        return callSites_[i];
+    }
+
     void initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx);
 
     void requireHeapLengthToBeAtLeast(uint32_t len) {
         if (len > pod.minHeapLength_)
             pod.minHeapLength_ = len;
     }
     uint32_t minHeapLength() const {
         return pod.minHeapLength_;
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -337,17 +337,17 @@ HandleSimulatorInterrupt(JSRuntime *rt, 
     // simulator could be in the middle of an instruction. On ARM, the signal
     // handlers are currently only used for Odin code, see bug 964258.
 
 #ifdef JS_ARM_SIMULATOR
     const AsmJSModule &module = activation->module();
     if (module.containsPC((void *)rt->mainThread.simulator()->get_pc()) &&
         module.containsPC(faultingAddress))
     {
-        activation->setResumePC(nullptr);
+        activation->setInterrupted(nullptr);
         int32_t nextpc = int32_t(module.interruptExit());
         rt->mainThread.simulator()->set_resume_pc(nextpc);
         return true;
     }
 #endif
     return false;
 }
 
@@ -447,17 +447,17 @@ HandleException(PEXCEPTION_POINTERS exce
         return false;
 
     // If we faulted trying to execute code in 'module', this must be an
     // interrupt callback (see RequestInterruptForAsmJSCode). Redirect
     // execution to a trampoline which will call js::HandleExecutionInterrupt.
     // The trampoline will jump to activation->resumePC if execution isn't
     // interrupted.
     if (module.containsPC(faultingAddress)) {
-        activation->setResumePC(pc);
+        activation->setInterrupted(pc);
         *ppc = module.interruptExit();
 
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
         return true;
     }
 
 # if defined(JS_CODEGEN_X64)
@@ -650,17 +650,17 @@ HandleMachException(JSRuntime *rt, const
         return false;
 
     // If we faulted trying to execute code in 'module', this must be an
     // interrupt callback (see RequestInterruptForAsmJSCode). Redirect
     // execution to a trampoline which will call js::HandleExecutionInterrupt.
     // The trampoline will jump to activation->resumePC if execution isn't
     // interrupted.
     if (module.containsPC(faultingAddress)) {
-        activation->setResumePC(pc);
+        activation->setInterrupted(pc);
         *ppc = module.interruptExit();
 
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
 
         // Update the thread state with the new pc.
         kret = thread_set_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, x86_THREAD_STATE_COUNT);
         return kret == KERN_SUCCESS;
@@ -900,17 +900,17 @@ HandleSignal(int signum, siginfo_t *info
         return false;
 
     // If we faulted trying to execute code in 'module', this must be an
     // interrupt callback (see RequestInterruptForAsmJSCode). Redirect
     // execution to a trampoline which will call js::HandleExecutionInterrupt.
     // The trampoline will jump to activation->resumePC if execution isn't
     // interrupted.
     if (module.containsPC(faultingAddress)) {
-        activation->setResumePC(pc);
+        activation->setInterrupted(pc);
         *ppc = module.interruptExit();
 
         JSRuntime::AutoLockForInterrupt lock(rt);
         module.unprotectCode(rt);
         return true;
     }
 
 # if defined(JS_CODEGEN_X64)
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -72,17 +72,17 @@ jit::Bailout(BailoutStack *sp, BaselineB
 {
     JSContext *cx = GetJSContextFromJitCode();
     JS_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
     cx->mainThread().ionTop = nullptr;
     JitActivationIterator jitActivations(cx->runtime());
     IonBailoutIterator iter(jitActivations, sp);
-    JitActivation *activation = jitActivations.activation()->asJit();
+    JitActivation *activation = jitActivations->asJit();
 
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
     TraceLogTimestamp(logger, TraceLogger::Bailout);
 
     IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
 
     JS_ASSERT(IsBaselineEnabled(cx));
 
@@ -106,17 +106,17 @@ jit::InvalidationBailout(InvalidationBai
     sp->checkInvariants();
 
     JSContext *cx = GetJSContextFromJitCode();
 
     // We don't have an exit frame.
     cx->mainThread().ionTop = nullptr;
     JitActivationIterator jitActivations(cx->runtime());
     IonBailoutIterator iter(jitActivations, sp);
-    JitActivation *activation = jitActivations.activation()->asJit();
+    JitActivation *activation = jitActivations->asJit();
 
     TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
     TraceLogTimestamp(logger, TraceLogger::Invalidation);
 
     IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
 
     // Note: the frame size must be computed before we return from this function.
     *frameSizeOut = iter.topFrameSize();
@@ -174,17 +174,17 @@ jit::ExceptionHandlerBailout(JSContext *
     // We can be propagating debug mode exceptions without there being an
     // actual exception pending. For instance, when we return false from an
     // operation callback like a timeout handler.
     MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
 
     cx->mainThread().ionTop = nullptr;
     JitActivationIterator jitActivations(cx->runtime());
     IonBailoutIterator iter(jitActivations, frame.frame());
-    JitActivation *activation = jitActivations.activation()->asJit();
+    JitActivation *activation = jitActivations->asJit();
 
     BaselineBailoutInfo *bailoutInfo = nullptr;
     uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo);
 
     if (retval == BAILOUT_RETURN_OK) {
         MOZ_ASSERT(bailoutInfo);
 
         // Overwrite the kind so HandleException after the bailout returns
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -953,12 +953,12 @@ MarkActiveBaselineScripts(JSRuntime *rt,
     }
 }
 
 void
 jit::MarkActiveBaselineScripts(Zone *zone)
 {
     JSRuntime *rt = zone->runtimeFromMainThread();
     for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
-        if (iter.activation()->compartment()->zone() == zone)
+        if (iter->compartment()->zone() == zone)
             MarkActiveBaselineScripts(rt, iter);
     }
 }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -145,24 +145,22 @@ CodeGenerator::visitOutOfLineCache(OutOf
 StringObject *
 MNewStringObject::templateObj() const {
     return &templateObj_->as<StringObject>();
 }
 
 CodeGenerator::CodeGenerator(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
   : CodeGeneratorSpecific(gen, graph, masm)
   , ionScriptLabels_(gen->alloc())
-  , unassociatedScriptCounts_(nullptr)
 {
 }
 
 CodeGenerator::~CodeGenerator()
 {
     JS_ASSERT_IF(!gen->compilingAsmJS(), masm.numAsmJSAbsoluteLinks() == 0);
-    js_delete(unassociatedScriptCounts_);
 }
 
 typedef bool (*StringToNumberFn)(ThreadSafeContext *, JSString *, double *);
 typedef bool (*StringToNumberParFn)(ForkJoinContext *, JSString *, double *);
 static const VMFunctionsModal StringToNumberInfo = VMFunctionsModal(
     FunctionInfo<StringToNumberFn>(StringToNumber),
     FunctionInfo<StringToNumberParFn>(StringToNumberPar));
 
@@ -2744,27 +2742,16 @@ class CheckOverRecursedFailure : public 
     }
 
     LCheckOverRecursed *lir() const {
         return lir_;
     }
 };
 
 bool
-CodeGenerator::omitOverRecursedCheck() const
-{
-    // If the current function makes no calls (which means it isn't recursive)
-    // and it uses only a small amount of stack space, it doesn't need a
-    // stack overflow check. Note that the actual number here is somewhat
-    // arbitrary, and codegen actually uses small bounded amounts of
-    // additional stack space in some cases too.
-    return frameSize() < 64 && !gen->performsCall();
-}
-
-bool
 CodeGenerator::visitCheckOverRecursed(LCheckOverRecursed *lir)
 {
     // If we don't push anything on the stack, skip the check.
     if (omitOverRecursedCheck())
         return true;
 
     // Ensure that this frame will not cross the stack limit.
     // This is a weak check, justified by Ion using the C stack: we must always
@@ -2982,60 +2969,51 @@ IonScriptCounts *
 CodeGenerator::maybeCreateScriptCounts()
 {
     // If scripts are being profiled, create a new IonScriptCounts and attach
     // it to the script. This must be done on the main thread.
     JSContext *cx = GetIonContext()->cx;
     if (!cx || !cx->runtime()->profilingScripts)
         return nullptr;
 
-    IonScriptCounts *counts = nullptr;
-
     CompileInfo *outerInfo = &gen->info();
     JSScript *script = outerInfo->script();
-
-    if (script && !script->hasScriptCounts() && !script->initScriptCounts(cx))
+    if (!script)
         return nullptr;
 
-    counts = js_new<IonScriptCounts>();
+    if (!script->hasScriptCounts() && !script->initScriptCounts(cx))
+        return nullptr;
+
+    IonScriptCounts *counts = js_new<IonScriptCounts>();
     if (!counts || !counts->init(graph.numBlocks())) {
         js_delete(counts);
         return nullptr;
     }
 
     for (size_t i = 0; i < graph.numBlocks(); i++) {
         MBasicBlock *block = graph.getBlock(i)->mir();
 
-        uint32_t offset = 0;
-        if (script) {
-            // Find a PC offset in the outermost script to use. If this block
-            // is from an inlined script, find a location in the outer script
-            // to associate information about the inlining with.
-            MResumePoint *resume = block->entryResumePoint();
-            while (resume->caller())
-                resume = resume->caller();
-            offset = script->pcToOffset(resume->pc());
-        }
-
+        // Find a PC offset in the outermost script to use. If this block
+        // is from an inlined script, find a location in the outer script
+        // to associate information about the inlining with.
+        MResumePoint *resume = block->entryResumePoint();
+        while (resume->caller())
+            resume = resume->caller();
+
+        uint32_t offset = script->pcToOffset(resume->pc());
         if (!counts->block(i).init(block->id(), offset, block->numSuccessors())) {
             js_delete(counts);
             return nullptr;
         }
+
         for (size_t j = 0; j < block->numSuccessors(); j++)
             counts->block(i).setSuccessor(j, block->getSuccessor(j)->id());
     }
 
-    if (script) {
-        script->addIonCounts(counts);
-    } else {
-        // Compiling code for Asm.js. Leave the counts on the CodeGenerator to
-        // be picked up by the AsmJSModule after generation finishes.
-        unassociatedScriptCounts_ = counts;
-    }
-
+    script->addIonCounts(counts);
     return counts;
 }
 
 // Structure for managing the state tracked for a block by script counters.
 struct ScriptCountBlockState
 {
     IonBlockCounts &block;
     MacroAssembler &masm;
@@ -6197,30 +6175,30 @@ CodeGenerator::visitRestPar(LRestPar *li
 
     if (!emitAllocateGCThingPar(lir, temp2, cx, temp0, temp1, templateObject))
         return false;
 
     return emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject);
 }
 
 bool
-CodeGenerator::generateAsmJS()
+CodeGenerator::generateAsmJS(Label *stackOverflowLabel)
 {
     IonSpew(IonSpew_Codegen, "# Emitting asm.js code");
 
     // AsmJS doesn't do profiler instrumentation.
     sps_.disable();
 
     // The caller (either another asm.js function or the external-entry
     // trampoline) has placed all arguments in registers and on the stack
     // according to the system ABI. The MAsmJSParameters which represent these
     // parameters have been useFixed()ed to these ABI-specified positions.
     // Thus, there is nothing special to do in the prologue except (possibly)
     // bump the stack.
-    if (!generatePrologue())
+    if (!generateAsmJSPrologue(stackOverflowLabel))
         return false;
     if (!generateBody())
         return false;
     if (!generateEpilogue())
         return false;
 #if defined(JS_ION_PERF)
     // Note the end of the inline code and start of the OOL code.
     gen->perfSpewer().noteEndInlineCode(masm);
@@ -8235,39 +8213,40 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall
             if (a->isFloatReg()) {
                 FloatRegister fr = ToFloatRegister(a);
                 int srcId = fr.code() * 2;
                 masm.ma_vxfer(fr, Register::FromCode(srcId), Register::FromCode(srcId+1));
             }
         }
     }
 #endif
+
    if (mir->spIncrement())
         masm.freeStack(mir->spIncrement());
 
    JS_ASSERT((AlignmentAtPrologue +  masm.framePushed()) % StackAlignment == 0);
 
 #ifdef DEBUG
     Label ok;
     JS_ASSERT(IsPowerOfTwo(StackAlignment));
     masm.branchTestPtr(Assembler::Zero, StackPointer, Imm32(StackAlignment - 1), &ok);
     masm.assumeUnreachable("Stack should be aligned.");
     masm.bind(&ok);
 #endif
 
     MAsmJSCall::Callee callee = mir->callee();
     switch (callee.which()) {
       case MAsmJSCall::Callee::Internal:
-        masm.call(callee.internal());
+        masm.call(mir->desc(), callee.internal());
         break;
       case MAsmJSCall::Callee::Dynamic:
-        masm.call(ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex())));
+        masm.call(mir->desc(), ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex())));
         break;
       case MAsmJSCall::Callee::Builtin:
-        masm.call(callee.builtin());
+        masm.call(mir->desc(), callee.builtin());
         break;
     }
 
     if (mir->spIncrement())
         masm.reserveStack(mir->spIncrement());
 
     postAsmJSCall(ins);
     return true;
@@ -8293,30 +8272,16 @@ CodeGenerator::visitAsmJSVoidReturn(LAsm
 {
     // Don't emit a jump to the return label if this is the last block.
     if (current->mir() != *gen->graph().poBegin())
         masm.jump(&returnLabel_);
     return true;
 }
 
 bool
-CodeGenerator::visitAsmJSCheckOverRecursed(LAsmJSCheckOverRecursed *lir)
-{
-    // If we don't push anything on the stack, skip the check.
-    if (omitOverRecursedCheck())
-        return true;
-
-    masm.branchPtr(Assembler::AboveOrEqual,
-                   AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
-                   StackPointer,
-                   lir->mir()->onError());
-    return true;
-}
-
-bool
 CodeGenerator::emitAssertRangeI(const Range *r, Register input)
 {
     // Check the lower bound.
     if (r->hasInt32LowerBound() && r->lower() > INT32_MIN) {
         Label success;
         masm.branch32(Assembler::GreaterThanOrEqual, input, Imm32(r->lower()), &success);
         masm.assumeUnreachable("Integer input should be equal or higher than Lowerbound.");
         masm.bind(&success);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -48,17 +48,17 @@ class CodeGenerator : public CodeGenerat
     bool generateBody();
 
   public:
     CodeGenerator(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm = nullptr);
     ~CodeGenerator();
 
   public:
     bool generate();
-    bool generateAsmJS();
+    bool generateAsmJS(Label *stackOverflowLabel);
     bool link(JSContext *cx, types::CompilerConstraintList *constraints);
 
     bool visitLabel(LLabel *lir);
     bool visitNop(LNop *lir);
     bool visitOsiPoint(LOsiPoint *lir);
     bool visitGoto(LGoto *lir);
     bool visitTableSwitch(LTableSwitch *ins);
     bool visitTableSwitchV(LTableSwitchV *ins);
@@ -289,17 +289,16 @@ class CodeGenerator : public CodeGenerat
     bool visitHasClass(LHasClass *lir);
     bool visitAsmJSCall(LAsmJSCall *lir);
     bool visitAsmJSParameter(LAsmJSParameter *lir);
     bool visitAsmJSReturn(LAsmJSReturn *ret);
     bool visitAsmJSVoidReturn(LAsmJSVoidReturn *ret);
 
     bool visitCheckOverRecursed(LCheckOverRecursed *lir);
     bool visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
-    bool visitAsmJSCheckOverRecursed(LAsmJSCheckOverRecursed *lir);
 
     bool visitCheckOverRecursedPar(LCheckOverRecursedPar *lir);
     bool visitCheckOverRecursedFailurePar(CheckOverRecursedFailurePar *ool);
 
     bool visitInterruptCheckPar(LInterruptCheckPar *lir);
     bool visitOutOfLineInterruptCheckPar(OutOfLineInterruptCheckPar *ool);
 
     bool visitInterruptCheckImplicit(LInterruptCheckImplicit *ins);
@@ -345,22 +344,16 @@ class CodeGenerator : public CodeGenerat
 
     bool visitAssertRangeI(LAssertRangeI *ins);
     bool visitAssertRangeD(LAssertRangeD *ins);
     bool visitAssertRangeF(LAssertRangeF *ins);
     bool visitAssertRangeV(LAssertRangeV *ins);
 
     bool visitRecompileCheck(LRecompileCheck *ins);
 
-    IonScriptCounts *extractUnassociatedScriptCounts() {
-        IonScriptCounts *counts = unassociatedScriptCounts_;
-        unassociatedScriptCounts_ = nullptr;  // prevent delete in dtor
-        return counts;
-    }
-
   private:
     bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
                              PropertyName *name, TypedOrValueRegister output,
                              bool monitoredResult);
     bool addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
                             TypedOrValueRegister output, bool monitoredResult,
                             bool allowDoubleResult);
     bool addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
@@ -442,30 +435,25 @@ class CodeGenerator : public CodeGenerat
     Label *getJumpLabelForBranch(MBasicBlock *block);
 
     // Bailout if an element about to be written to is a hole.
     bool emitStoreHoleCheck(Register elements, const LAllocation *index, LSnapshot *snapshot);
 
     bool emitAssertRangeI(const Range *r, Register input);
     bool emitAssertRangeD(const Range *r, FloatRegister input, FloatRegister temp);
 
-    bool omitOverRecursedCheck() const;
-
     Vector<CodeOffsetLabel, 0, IonAllocPolicy> ionScriptLabels_;
 #ifdef DEBUG
     bool branchIfInvalidated(Register temp, Label *invalidated);
 
     bool emitDebugResultChecks(LInstruction *ins);
     bool emitObjectOrStringResultChecks(LInstruction *lir, MDefinition *mir);
     bool emitValueResultChecks(LInstruction *lir, MDefinition *mir);
 #endif
 
-    // Script counts created when compiling code with no associated JSScript.
-    IonScriptCounts *unassociatedScriptCounts_;
-
 #if defined(JS_ION_PERF)
     PerfSpewer perfSpewer_;
 #endif
 };
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1623,48 +1623,41 @@ GenerateLIR(MIRGenerator *mir)
         return nullptr;
     IonSpewPass("Unsplit Critical Edges");
     AssertBasicGraphCoherency(graph);
 
     return lir;
 }
 
 CodeGenerator *
-GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm)
+GenerateCode(MIRGenerator *mir, LIRGraph *lir)
 {
-    CodeGenerator *codegen = js_new<CodeGenerator>(mir, lir, maybeMasm);
+    CodeGenerator *codegen = js_new<CodeGenerator>(mir, lir);
     if (!codegen)
         return nullptr;
 
-    if (mir->compilingAsmJS()) {
-        if (!codegen->generateAsmJS()) {
-            js_delete(codegen);
-            return nullptr;
-        }
-    } else {
-        if (!codegen->generate()) {
-            js_delete(codegen);
-            return nullptr;
-        }
+    if (!codegen->generate()) {
+        js_delete(codegen);
+        return nullptr;
     }
 
     return codegen;
 }
 
 CodeGenerator *
-CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm)
+CompileBackEnd(MIRGenerator *mir)
 {
     if (!OptimizeMIR(mir))
         return nullptr;
 
     LIRGraph *lir = GenerateLIR(mir);
     if (!lir)
         return nullptr;
 
-    return GenerateCode(mir, lir, maybeMasm);
+    return GenerateCode(mir, lir);
 }
 
 void
 AttachFinishedCompilations(JSContext *cx)
 {
 #ifdef JS_THREADSAFE
     JitCompartment *ion = cx->compartment()->jitCompartment();
     if (!ion)
@@ -2655,17 +2648,17 @@ jit::StopAllOffThreadCompilations(JSComp
 
 void
 jit::InvalidateAll(FreeOp *fop, Zone *zone)
 {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next())
         StopAllOffThreadCompilations(comp);
 
     for (JitActivationIterator iter(fop->runtime()); !iter.done(); ++iter) {
-        if (iter.activation()->compartment()->zone() == zone) {
+        if (iter->compartment()->zone() == zone) {
             IonContext ictx(CompileRuntime::get(fop->runtime()));
             AutoFlushCache afc("InvalidateAll", fop->runtime()->jitRuntime());
             IonSpew(IonSpew_Invalidate, "Invalidating all frames for GC");
             InvalidateActivation(fop, iter.jitTop(), true);
         }
     }
 }
 
@@ -3076,17 +3069,17 @@ AutoDebugModeInvalidation::~AutoDebugMod
             StopAllOffThreadCompilations(comp);
     }
 
     // Don't discard active baseline scripts. They are recompiled for debug
     // mode.
     jit::MarkActiveBaselineScripts(zone);
 
     for (JitActivationIterator iter(rt); !iter.done(); ++iter) {
-        JSCompartment *comp = iter.activation()->compartment();
+        JSCompartment *comp = iter->compartment();
         if (comp_ == comp || zone_ == comp->zone()) {
             IonContext ictx(CompileRuntime::get(rt));
             AutoFlushCache afc("AutoDebugModeInvalidation", rt->jitRuntime());
             IonSpew(IonSpew_Invalidate, "Invalidating frames for debug mode toggle");
             InvalidateActivation(fop, iter.jitTop(), true);
         }
     }
 
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -144,18 +144,18 @@ void ToggleBarriers(JS::Zone *zone, bool
 
 class IonBuilder;
 class MIRGenerator;
 class LIRGraph;
 class CodeGenerator;
 
 bool OptimizeMIR(MIRGenerator *mir);
 LIRGraph *GenerateLIR(MIRGenerator *mir);
-CodeGenerator *GenerateCode(MIRGenerator *mir, LIRGraph *lir, MacroAssembler *maybeMasm = nullptr);
-CodeGenerator *CompileBackEnd(MIRGenerator *mir, MacroAssembler *maybeMasm = nullptr);
+CodeGenerator *GenerateCode(MIRGenerator *mir, LIRGraph *lir);
+CodeGenerator *CompileBackEnd(MIRGenerator *mir);
 
 void AttachFinishedCompilations(JSContext *cx);
 void FinishOffThreadBuilder(IonBuilder *builder);
 void StopAllOffThreadCompilations(JSCompartment *comp);
 
 static inline bool
 IsIonEnabled(JSContext *cx)
 {
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -87,17 +87,17 @@ JitFrameIterator::JitFrameIterator(JSCon
 }
 
 JitFrameIterator::JitFrameIterator(const ActivationIterator &activations)
     : current_(activations.jitTop()),
       type_(JitFrame_Exit),
       returnAddressToFp_(nullptr),
       frameSize_(0),
       cachedSafepointIndex_(nullptr),
-      activation_(activations.activation()->asJit()),
+      activation_(activations->asJit()),
       mode_(SequentialExecution)
 {
 }
 
 JitFrameIterator::JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode)
   : current_((uint8_t *)fp),
     type_(JitFrame_IonJS),
     returnAddressToFp_(fp->returnAddress()),
@@ -1169,17 +1169,17 @@ MarkRectifierFrame(JSTracer *trc, const 
     // it if we're calling a constructor that returns a primitive value.
     IonRectifierFrameLayout *layout = (IonRectifierFrameLayout *)frame.fp();
     gc::MarkValueRoot(trc, &layout->argv()[0], "ion-thisv");
 }
 
 static void
 MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
 {
-    JitActivation *activation = activations.activation()->asJit();
+    JitActivation *activation = activations->asJit();
 
 #ifdef CHECK_OSIPOINT_REGISTERS
     if (js_JitOptions.checkOsiPointRegisters) {
         // GC can modify spilled registers, breaking our register checks.
         // To handle this, we disable these checks for the current VM call
         // when a GC happens.
         activation->setCheckRegs(false);
     }
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -5990,26 +5990,16 @@ class LAsmJSCall MOZ_FINAL : public LIns
     MBasicBlock *getSuccessor(size_t i) const {
         MOZ_ASSUME_UNREACHABLE("no successors");
     }
     void setSuccessor(size_t i, MBasicBlock *) {
         MOZ_ASSUME_UNREACHABLE("no successors");
     }
 };
 
-class LAsmJSCheckOverRecursed : public LInstructionHelper<0, 0, 0>
-{
-  public:
-    LIR_HEADER(AsmJSCheckOverRecursed)
-
-    MAsmJSCheckOverRecursed *mir() const {
-        return mir_->toAsmJSCheckOverRecursed();
-    }
-};
-
 class LAssertRangeI : public LInstructionHelper<0, 1, 0>
 {
   public:
     LIR_HEADER(AssertRangeI)
 
     LAssertRangeI(const LAllocation &input) {
         setOperand(0, input);
     }
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -287,17 +287,16 @@
     _(AsmJSLoadGlobalVar)           \
     _(AsmJSStoreGlobalVar)          \
     _(AsmJSLoadFFIFunc)             \
     _(AsmJSParameter)               \
     _(AsmJSReturn)                  \
     _(AsmJSVoidReturn)              \
     _(AsmJSPassStackArg)            \
     _(AsmJSCall)                    \
-    _(AsmJSCheckOverRecursed)       \
     _(InterruptCheckPar)            \
     _(RecompileCheck)               \
     _(AssertRangeI)                 \
     _(AssertRangeD)                 \
     _(AssertRangeF)                 \
     _(AssertRangeV)
 
 #if defined(JS_CODEGEN_X86)
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3498,22 +3498,16 @@ LIRGenerator::visitAsmJSCall(MAsmJSCall 
     LInstruction *lir = new(alloc()) LAsmJSCall(args, ins->numOperands());
     if (ins->type() == MIRType_None) {
         return add(lir, ins);
     }
     return defineReturn(lir, ins);
 }
 
 bool
-LIRGenerator::visitAsmJSCheckOverRecursed(MAsmJSCheckOverRecursed *ins)
-{
-    return add(new(alloc()) LAsmJSCheckOverRecursed(), ins);
-}
-
-bool
 LIRGenerator::visitSetDOMProperty(MSetDOMProperty *ins)
 {
     MDefinition *val = ins->value();
 
     Register cxReg, objReg, privReg, valueReg;
     GetTempRegForIntArg(0, 0, &cxReg);
     GetTempRegForIntArg(1, 0, &objReg);
     GetTempRegForIntArg(2, 0, &privReg);
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -249,17 +249,16 @@ class LIRGenerator : public LIRGenerator
     bool visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins);
     bool visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins);
     bool visitAsmJSLoadFFIFunc(MAsmJSLoadFFIFunc *ins);
     bool visitAsmJSParameter(MAsmJSParameter *ins);
     bool visitAsmJSReturn(MAsmJSReturn *ins);
     bool visitAsmJSVoidReturn(MAsmJSVoidReturn *ins);
     bool visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
     bool visitAsmJSCall(MAsmJSCall *ins);
-    bool visitAsmJSCheckOverRecursed(MAsmJSCheckOverRecursed *ins);
     bool visitSetDOMProperty(MSetDOMProperty *ins);
     bool visitGetDOMProperty(MGetDOMProperty *ins);
     bool visitGetDOMMember(MGetDOMMember *ins);
     bool visitRecompileCheck(MRecompileCheck *ins);
 };
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2963,22 +2963,20 @@ MAsmJSUnsignedToFloat32::foldsTo(TempAll
                 return MConstant::NewAsmJS(alloc, JS::Float32Value(float(dval)), MIRType_Float32);
         }
     }
 
     return this;
 }
 
 MAsmJSCall *
-MAsmJSCall::New(TempAllocator &alloc, Callee callee, const Args &args, MIRType resultType,
-                size_t spIncrement)
+MAsmJSCall::New(TempAllocator &alloc, const CallSiteDesc &desc, Callee callee,
+                const Args &args, MIRType resultType, size_t spIncrement)
 {
-    MAsmJSCall *call = new(alloc) MAsmJSCall;
-    call->spIncrement_ = spIncrement;
-    call->callee_ = callee;
+    MAsmJSCall *call = new(alloc) MAsmJSCall(desc, callee, spIncrement);
     call->setResultType(resultType);
 
     if (!call->argRegs_.init(alloc, args.length()))
         return nullptr;
     for (size_t i = 0; i < call->argRegs_.length(); i++)
         call->argRegs_[i] = args[i].reg;
 
     if (!call->operands_.init(alloc, call->argRegs_.length() + (callee.which() == Callee::Dynamic ? 1 : 0)))
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9977,21 +9977,26 @@ class MAsmJSCall MOZ_FINAL : public MIns
     };
 
   private:
     struct Operand {
         AnyRegister reg;
         MUse use;
     };
 
+    CallSiteDesc desc_;
     Callee callee_;
     FixedList<MUse> operands_;
     FixedList<AnyRegister> argRegs_;
     size_t spIncrement_;
 
+    MAsmJSCall(const CallSiteDesc &desc, Callee callee, size_t spIncrement)
+     : desc_(desc), callee_(callee), spIncrement_(spIncrement)
+    { }
+
   protected:
     void setOperand(size_t index, MDefinition *operand) {
         operands_[index].set(operand, this, index);
         operand->addUse(&operands_[index]);
     }
     MUse *getUseFor(size_t index) {
         return &operands_[index];
     }
@@ -10001,33 +10006,36 @@ class MAsmJSCall MOZ_FINAL : public MIns
 
     struct Arg {
         AnyRegister reg;
         MDefinition *def;
         Arg(AnyRegister reg, MDefinition *def) : reg(reg), def(def) {}
     };
     typedef Vector<Arg, 8> Args;
 
-    static MAsmJSCall *New(TempAllocator &alloc, Callee callee, const Args &args,
-                           MIRType resultType, size_t spIncrement);
+    static MAsmJSCall *New(TempAllocator &alloc, const CallSiteDesc &desc, Callee callee,
+                           const Args &args, MIRType resultType, size_t spIncrement);
 
     size_t numOperands() const {
         return operands_.length();
     }
     MDefinition *getOperand(size_t index) const {
         JS_ASSERT(index < numOperands());
         return operands_[index].producer();
     }
     size_t numArgs() const {
         return argRegs_.length();
     }
     AnyRegister registerForArg(size_t index) const {
         JS_ASSERT(index < numArgs());
         return argRegs_[index];
     }
+    const CallSiteDesc &desc() const {
+        return desc_;
+    }
     Callee callee() const {
         return callee_;
     }
     size_t dynamicCalleeOperandIndex() const {
         JS_ASSERT(callee_.which() == Callee::Dynamic);
         JS_ASSERT(numArgs() == numOperands() - 1);
         return numArgs();
     }
@@ -10035,30 +10043,16 @@ class MAsmJSCall MOZ_FINAL : public MIns
         return spIncrement_;
     }
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
-// The asm.js version doesn't use the bail mechanism: instead it throws and
-// exception by jumping to the given label.
-class MAsmJSCheckOverRecursed : public MNullaryInstruction
-{
-    Label *onError_;
-    MAsmJSCheckOverRecursed(Label *onError) : onError_(onError) {}
-  public:
-    INSTRUCTION_HEADER(AsmJSCheckOverRecursed);
-    static MAsmJSCheckOverRecursed *New(TempAllocator &alloc, Label *onError) {
-        return new(alloc) MAsmJSCheckOverRecursed(onError);
-    }
-    Label *onError() const { return onError_; }
-};
-
 #undef INSTRUCTION_HEADER
 
 // Implement opcode casts now that the compiler can see the inheritance.
 #define OPCODE_CASTS(opcode)                                                \
     M##opcode *MDefinition::to##opcode()                                    \
     {                                                                       \
         JS_ASSERT(is##opcode());                                            \
         return static_cast<M##opcode *>(this);                              \
--- a/js/src/jit/MIRGenerator.h
+++ b/js/src/jit/MIRGenerator.h
@@ -115,34 +115,22 @@ class MIRGenerator
         JS_ASSERT(compilingAsmJS());
         setPerformsCall();
         performsAsmJSCall_ = true;
     }
     bool performsAsmJSCall() const {
         JS_ASSERT(compilingAsmJS());
         return performsAsmJSCall_;
     }
-    bool noteHeapAccess(AsmJSHeapAccess heapAccess) {
-        return asmJSHeapAccesses_.append(heapAccess);
-    }
-    const Vector<AsmJSHeapAccess, 0, IonAllocPolicy> &heapAccesses() const {
-        return asmJSHeapAccesses_;
-    }
     void noteMinAsmJSHeapLength(uint32_t len) {
         minAsmJSHeapLength_ = len;
     }
     uint32_t minAsmJSHeapLength() const {
         return minAsmJSHeapLength_;
     }
-    bool noteGlobalAccess(unsigned offset, unsigned globalDataOffset) {
-        return asmJSGlobalAccesses_.append(AsmJSGlobalAccess(offset, globalDataOffset));
-    }
-    const Vector<AsmJSGlobalAccess, 0, IonAllocPolicy> &globalAccesses() const {
-        return asmJSGlobalAccesses_;
-    }
 
     bool modifiesFrameArguments() const {
         return modifiesFrameArguments_;
     }
 
   public:
     CompileCompartment *compartment;
 
@@ -154,18 +142,16 @@ class MIRGenerator
     uint32_t nslots_;
     MIRGraph *graph_;
     bool error_;
     mozilla::Atomic<bool, mozilla::Relaxed> cancelBuild_;
 
     uint32_t maxAsmJSStackArgBytes_;
     bool performsCall_;
     bool performsAsmJSCall_;
-    AsmJSHeapAccessVector asmJSHeapAccesses_;
-    AsmJSGlobalAccessVector asmJSGlobalAccesses_;
     uint32_t minAsmJSHeapLength_;
 
     // Keep track of whether frame arguments are modified during execution.
     // RegAlloc needs to know this as spilling values back to their register
     // slots is not compatible with that.
     bool modifiesFrameArguments_;
 
 #if defined(JS_ION_PERF)
--- a/js/src/jit/MIRGraph.cpp
+++ b/js/src/jit/MIRGraph.cpp
@@ -24,18 +24,16 @@ MIRGenerator::MIRGenerator(CompileCompar
     optimizationInfo_(optimizationInfo),
     alloc_(alloc),
     graph_(graph),
     error_(false),
     cancelBuild_(false),
     maxAsmJSStackArgBytes_(0),
     performsCall_(false),
     performsAsmJSCall_(false),
-    asmJSHeapAccesses_(*alloc),
-    asmJSGlobalAccesses_(*alloc),
     minAsmJSHeapLength_(AsmJSAllocationGranularity),
     modifiesFrameArguments_(false),
     options(options)
 { }
 
 bool
 MIRGenerator::abortFmt(const char *message, va_list ap)
 {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -205,17 +205,16 @@ namespace jit {
     _(AsmJSStoreGlobalVar)                                                  \
     _(AsmJSLoadFuncPtr)                                                     \
     _(AsmJSLoadFFIFunc)                                                     \
     _(AsmJSReturn)                                                          \
     _(AsmJSParameter)                                                       \
     _(AsmJSVoidReturn)                                                      \
     _(AsmJSPassStackArg)                                                    \
     _(AsmJSCall)                                                            \
-    _(AsmJSCheckOverRecursed)                                               \
     _(CheckOverRecursedPar)                                                 \
     _(NewCallObjectPar)                                                     \
     _(NewPar)                                                               \
     _(NewDenseArrayPar)                                                     \
     _(NewDerivedTypedObject)                                                \
     _(AbortPar)                                                             \
     _(LambdaPar)                                                            \
     _(RestPar)                                                              \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -316,17 +316,16 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(AsmJSStoreGlobalVar)
     UNSAFE_OP(AsmJSLoadFuncPtr)
     UNSAFE_OP(AsmJSLoadFFIFunc)
     UNSAFE_OP(AsmJSReturn)
     UNSAFE_OP(AsmJSVoidReturn)
     UNSAFE_OP(AsmJSPassStackArg)
     UNSAFE_OP(AsmJSParameter)
     UNSAFE_OP(AsmJSCall)
-    UNSAFE_OP(AsmJSCheckOverRecursed)
     DROP_OP(RecompileCheck)
 
     // It looks like this could easily be made safe:
     UNSAFE_OP(ConvertElementsToDoubles)
 };
 
 bool
 ParallelSafetyAnalysis::analyze()
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -796,78 +796,12 @@ class ABIArg
     Register gpr() const { JS_ASSERT(kind() == GPR); return Register::FromCode(u.gpr_); }
     FloatRegister fpu() const { JS_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); }
     uint32_t offsetFromArgBase() const { JS_ASSERT(kind() == Stack); return u.offset_; }
 
     bool argInRegister() const { return kind() != Stack; }
     AnyRegister reg() const { return kind_ == GPR ? AnyRegister(gpr()) : AnyRegister(fpu()); }
 };
 
-// Summarizes a heap access made by asm.js code that needs to be patched later
-// and/or looked up by the asm.js signal handlers. Different architectures need
-// to know different things (x64: offset and length, ARM: where to patch in
-// heap length, x86: where to patch in heap length and base) hence the massive
-// #ifdefery.
-class AsmJSHeapAccess
-{
-    uint32_t offset_;
-#if defined(JS_CODEGEN_X86)
-    uint8_t cmpDelta_;  // the number of bytes from the cmp to the load/store instruction
-#endif
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-    uint8_t opLength_;  // the length of the load/store instruction
-    uint8_t isFloat32Load_;
-    AnyRegister::Code loadedReg_ : 8;
-#endif
-
-    JS_STATIC_ASSERT(AnyRegister::Total < UINT8_MAX);
-
-  public:
-    AsmJSHeapAccess() {}
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-    // If 'cmp' equals 'offset' or if it is not supplied then the
-    // cmpDelta_ is zero indicating that there is no length to patch.
-    AsmJSHeapAccess(uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
-                    AnyRegister loadedReg, uint32_t cmp = UINT32_MAX)
-      : offset_(offset),
-# if defined(JS_CODEGEN_X86)
-        cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
-# endif
-        opLength_(after - offset),
-        isFloat32Load_(vt == ArrayBufferView::TYPE_FLOAT32),
-        loadedReg_(loadedReg.code())
-    {}
-    AsmJSHeapAccess(uint32_t offset, uint8_t after, uint32_t cmp = UINT32_MAX)
-      : offset_(offset),
-# if defined(JS_CODEGEN_X86)
-        cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
-# endif
-        opLength_(after - offset),
-        isFloat32Load_(false),
-        loadedReg_(UINT8_MAX)
-    {}
-#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
-    explicit AsmJSHeapAccess(uint32_t offset)
-      : offset_(offset)
-    {}
-#endif
-
-    uint32_t offset() const { return offset_; }
-    void setOffset(uint32_t offset) { offset_ = offset; }
-#if defined(JS_CODEGEN_X86)
-    bool hasLengthCheck() const { return cmpDelta_ > 0; }
-    void *patchLengthAt(uint8_t *code) const { return code + (offset_ - cmpDelta_); }
-    void *patchOffsetAt(uint8_t *code) const { return code + (offset_ + opLength_); }
-#endif
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-    unsigned opLength() const { return opLength_; }
-    bool isLoad() const { return loadedReg_ != UINT8_MAX; }
-    bool isFloat32Load() const { return isFloat32Load_; }
-    AnyRegister loadedReg() const { return AnyRegister::FromCode(loadedReg_); }
-#endif
-};
-
-typedef Vector<AsmJSHeapAccess, 0, IonAllocPolicy> AsmJSHeapAccessVector;
-
 } // namespace jit
 } // namespace js
 
 #endif /* jit_RegisterSets_h */
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -1121,17 +1121,17 @@ class Operand
 };
 
 void
 PatchJump(CodeLocationJump &jump_, CodeLocationLabel label);
 class InstructionIterator;
 class Assembler;
 typedef js::jit::AssemblerBufferWithConstantPool<1024, 4, Instruction, Assembler, 1> ARMBuffer;
 
-class Assembler
+class Assembler : public AssemblerShared
 {
   public:
     // ARM conditional constants
     enum ARMCondition {
         EQ = 0x00000000, // Zero
         NE = 0x10000000, // Non-zero
         CS = 0x20000000,
         CC = 0x30000000,
@@ -1256,17 +1256,16 @@ class Assembler
 
     // TODO: this should actually be a pool-like object
     //       It is currently a big hack, and probably shouldn't exist
     js::Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_;
     js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
     js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpJumpRelocations_;
     js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpDataRelocations_;
     js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpPreBarriers_;
-    AsmJSAbsoluteLinkVector asmJSAbsoluteLinks_;
 
     CompactBufferWriter jumpRelocations_;
     CompactBufferWriter dataRelocations_;
     CompactBufferWriter relocations_;
     CompactBufferWriter preBarriers_;
 
     bool enoughMemory_;
 
@@ -1378,23 +1377,16 @@ class Assembler
     bool addCodeLabel(CodeLabel label);
     size_t numCodeLabels() const {
         return codeLabels_.length();
     }
     CodeLabel codeLabel(size_t i) {
         return codeLabels_[i];
     }
 
-    size_t numAsmJSAbsoluteLinks() const {
-        return asmJSAbsoluteLinks_.length();
-    }
-    AsmJSAbsoluteLink asmJSAbsoluteLink(size_t i) const {
-        return asmJSAbsoluteLinks_[i];
-    }
-
     // Size of the instruction stream, in bytes.
     size_t size() const;
     // Size of the jump relocation table, in bytes.
     size_t jumpRelocationTableBytes() const;
     size_t dataRelocationTableBytes() const;
     size_t preBarrierTableBytes() const;
 
     // Size of the data table, in bytes.
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -35,26 +35,44 @@ using JS::GenericNaN;
 CodeGeneratorARM::CodeGeneratorARM(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
   : CodeGeneratorShared(gen, graph, masm)
 {
 }
 
 bool
 CodeGeneratorARM::generatePrologue()
 {
-    if (gen->compilingAsmJS()) {
-        masm.Push(lr);
-        // Note that this automatically sets MacroAssembler::framePushed().
-        masm.reserveStack(frameDepth_);
-    } else {
-        // Note that this automatically sets MacroAssembler::framePushed().
-        masm.reserveStack(frameSize());
-        masm.checkStackAlignment();
+    JS_ASSERT(!gen->compilingAsmJS());
+
+    // Note that this automatically sets MacroAssembler::framePushed().
+    masm.reserveStack(frameSize());
+    masm.checkStackAlignment();
+    return true;
+}
+
+bool
+CodeGeneratorARM::generateAsmJSPrologue(Label *stackOverflowLabel)
+{
+    JS_ASSERT(gen->compilingAsmJS());
+
+    masm.Push(lr);
+
+    // The asm.js over-recursed handler wants to be able to assume that SP
+    // points to the return address, so perform the check after pushing lr but
+    // before pushing frameDepth.
+    if (!omitOverRecursedCheck()) {
+        masm.branchPtr(Assembler::AboveOrEqual,
+                       AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
+                       StackPointer,
+                       stackOverflowLabel);
     }
 
+    // Note that this automatically sets MacroAssembler::framePushed().
+    masm.reserveStack(frameDepth_);
+    masm.checkStackAlignment();
     return true;
 }
 
 bool
 CodeGeneratorARM::generateEpilogue()
 {
     masm.bind(&returnLabel_);
 
@@ -2006,17 +2024,17 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAs
             masm.ma_vmov(NANReg, dst, Assembler::AboveOrEqual);
             masm.ma_vldr(vd, HeapReg, ptrReg, 0, Assembler::Below);
         }
     } else {
         Register d = ToRegister(ins->output());
         masm.ma_mov(Imm32(0), d, NoSetCond, Assembler::AboveOrEqual);
         masm.ma_dataTransferN(IsLoad, size, isSigned, HeapReg, ptrReg, d, Offset, Assembler::Below);
     }
-    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
+    return masm.append(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorARM::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
 {
     const MAsmJSStoreHeap *mir = ins->mir();
     bool isSigned;
     int size;
@@ -2073,17 +2091,17 @@ CodeGeneratorARM::visitAsmJSStoreHeap(LA
         if (size == 32)
             masm.ma_vstr(vd.singleOverlay(), HeapReg, ptrReg, 0, Assembler::Below);
         else
             masm.ma_vstr(vd, HeapReg, ptrReg, 0, Assembler::Below);
     } else {
         masm.ma_dataTransferN(IsStore, size, isSigned, HeapReg, ptrReg,
                               ToRegister(ins->value()), Offset, Assembler::Below);
     }
-    return gen->noteHeapAccess(AsmJSHeapAccess(bo.getOffset()));
+    return masm.append(AsmJSHeapAccess(bo.getOffset()));
 }
 
 bool
 CodeGeneratorARM::visitAsmJSPassStackArg(LAsmJSPassStackArg *ins)
 {
     const MAsmJSPassStackArg *mir = ins->mir();
     Operand dst(StackPointer, mir->spOffset());
     if (ins->arg()->isConstant()) {
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -66,16 +66,17 @@ class CodeGeneratorARM : public CodeGene
     template <typename T1, typename T2>
     bool bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) {
         masm.test32(lhs, rhs);
         return bailoutIf(c, snapshot);
     }
 
   protected:
     bool generatePrologue();
+    bool generateAsmJSPrologue(Label *stackOverflowLabel);
     bool generateEpilogue();
     bool generateOutOfLineCode();
 
     void emitRoundDouble(const FloatRegister &src, const Register &dest, Label *fail);
 
     // Emits a branch that directs control flow to the true block if |cond| is
     // true, and the false block if |cond| is false.
     void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -2036,18 +2036,17 @@ void
 MacroAssemblerARMCompat::movePtr(const AsmJSImmPtr &imm, const Register &dest)
 {
     RelocStyle rs;
     if (hasMOVWT())
         rs = L_MOVWT;
     else
         rs = L_LDR;
 
-    AsmJSAbsoluteLink link(nextOffset().getOffset(), imm.kind());
-    enoughMemory_ &= asmJSAbsoluteLinks_.append(link);
+    enoughMemory_ &= append(AsmJSAbsoluteLink(nextOffset().getOffset(), imm.kind()));
     ma_movPatchable(Imm32(-1), dest, Always, rs);
 }
 void
 MacroAssemblerARMCompat::load8ZeroExtend(const Address &address, const Register &dest)
 {
     ma_dataTransferN(IsLoad, 8, false, address.base, Imm32(address.offset), dest);
 }
 
@@ -3565,16 +3564,29 @@ MacroAssemblerARM::ma_call(ImmPtr dest)
     else
         rs = L_LDR;
 
     ma_movPatchable(dest, CallReg, Always, rs);
     as_blx(CallReg);
 }
 
 void
+MacroAssemblerARM::ma_callAndStoreRet(const Register r, uint32_t stackArgBytes)
+{
+    // Note: this function stores the return address to sp[0]. The caller must
+    // anticipate this by pushing additional space on the stack. The ABI does
+    // not provide space for a return address so this function may only be
+    // called if no argument are passed.
+    JS_ASSERT(stackArgBytes == 0);
+    AutoForbidPools afp(this);
+    as_dtr(IsStore, 32, Offset, pc, DTRAddr(sp, DtrOffImm(0)));
+    as_blx(r);
+}
+
+void
 MacroAssemblerARMCompat::breakpoint()
 {
     as_bkpt();
 }
 
 void
 MacroAssemblerARMCompat::ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure)
 {
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -394,16 +394,19 @@ class MacroAssemblerARM : public Assembl
     void ma_callIon(const Register reg);
     // callso an Ion function, assuming that sp has already been decremented
     void ma_callIonNoPush(const Register reg);
     // calls an ion function, assuming that the stack is currently not 8 byte aligned
     void ma_callIonHalfPush(const Register reg);
 
     void ma_call(ImmPtr dest);
 
+    // calls reg, storing the return address into sp[0]
+    void ma_callAndStoreRet(const Register reg, uint32_t stackArgBytes);
+
     // Float registers can only be loaded/stored in continuous runs
     // when using vstm/vldm.
     // This function breaks set into continuous runs and loads/stores
     // them at [rm]. rm will be modified and left in a state logically
     // suitable for the next load/store.
     // Returns the offset from [dm] for the logical next load/store.
     int32_t transferMultipleByRuns(FloatRegisterSet set, LoadStore ls,
                                    Register rm, DTMMode mode)
@@ -538,17 +541,16 @@ class MacroAssemblerARMCompat : public M
     }
     void mov(Address src, Register dest) {
         MOZ_ASSUME_UNREACHABLE("NYI-IC");
     }
 
     void call(const Register reg) {
         as_blx(reg);
     }
-
     void call(Label *label) {
         // for now, assume that it'll be nearby?
         as_bl(label, Always);
     }
     void call(ImmWord imm) {
         call(ImmPtr((void*)imm.value));
     }
     void call(ImmPtr imm) {
@@ -567,16 +569,48 @@ class MacroAssemblerARMCompat : public M
         if (hasMOVWT())
             rs = L_MOVWT;
         else
             rs = L_LDR;
 
         ma_movPatchable(ImmPtr(c->raw()), ScratchRegister, Always, rs);
         ma_callIonHalfPush(ScratchRegister);
     }
+
+    void appendCallSite(const CallSiteDesc &desc) {
+        enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_));
+    }
+
+    void call(const CallSiteDesc &desc, const Register reg) {
+        call(reg);
+        appendCallSite(desc);
+    }
+    void call(const CallSiteDesc &desc, Label *label) {
+        call(label);
+        appendCallSite(desc);
+    }
+    void call(const CallSiteDesc &desc, AsmJSImmPtr imm) {
+        call(imm);
+        appendCallSite(desc);
+    }
+    void callExit(AsmJSImmPtr imm, uint32_t stackArgBytes) {
+        movePtr(imm, CallReg);
+        ma_callAndStoreRet(CallReg, stackArgBytes);
+        appendCallSite(CallSiteDesc::Exit());
+    }
+    void callIonFromAsmJS(const Register reg) {
+        ma_callIonNoPush(reg);
+        appendCallSite(CallSiteDesc::Exit());
+
+        // The Ion ABI has the callee pop the return address off the stack.
+        // The asm.js caller assumes that the call leaves sp unchanged, so bump
+        // the stack.
+        subPtr(Imm32(sizeof(void*)), sp);
+    }
+
     void branch(JitCode *c) {
         BufferOffset bo = m_buffer.nextOffset();
         addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
         RelocStyle rs;
         if (hasMOVWT())
             rs = L_MOVWT;
         else
             rs = L_LDR;
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -4066,17 +4066,17 @@ Simulator::execute()
         } else {
             SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
             instructionDecode(instr);
             icount_++;
 
             int32_t rpc = resume_pc_;
             if (MOZ_UNLIKELY(rpc != 0)) {
                 // AsmJS signal handler ran and we have to adjust the pc.
-                activation->setResumePC((void *)get_pc());
+                activation->setInterrupted((void *)get_pc());
                 set_pc(rpc);
                 resume_pc_ = 0;
             }
         }
         program_counter = get_pc();
     }
 }
 
--- a/js/src/jit/mips/Assembler-mips.h
+++ b/js/src/jit/mips/Assembler-mips.h
@@ -560,17 +560,17 @@ class Operand
     }
 };
 
 void
 PatchJump(CodeLocationJump &jump_, CodeLocationLabel label);
 class Assembler;
 typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer;
 
-class Assembler
+class Assembler : public AssemblerShared
 {
   public:
 
     enum Condition {
         Equal,
         NotEqual,
         Above,
         AboveOrEqual,
@@ -665,17 +665,16 @@ class Assembler
             target(target),
             kind(kind)
         { }
     };
 
     js::Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_;
     js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
     js::Vector<uint32_t, 8, SystemAllocPolicy> longJumps_;
-    AsmJSAbsoluteLinkVector asmJSAbsoluteLinks_;
 
     CompactBufferWriter jumpRelocations_;
     CompactBufferWriter dataRelocations_;
     CompactBufferWriter relocations_;
     CompactBufferWriter preBarriers_;
 
     bool enoughMemory_;
 
@@ -727,23 +726,16 @@ class Assembler
     bool addCodeLabel(CodeLabel label);
     size_t numCodeLabels() const {
         return codeLabels_.length();
     }
     CodeLabel codeLabel(size_t i) {
         return codeLabels_[i];
     }
 
-    size_t numAsmJSAbsoluteLinks() const {
-        return asmJSAbsoluteLinks_.length();
-    }
-    AsmJSAbsoluteLink asmJSAbsoluteLink(size_t i) const {
-        return asmJSAbsoluteLinks_[i];
-    }
-
     // Size of the instruction stream, in bytes.
     size_t size() const;
     // Size of the jump relocation table, in bytes.
     size_t jumpRelocationTableBytes() const;
     size_t dataRelocationTableBytes() const;
     size_t preBarrierTableBytes() const;
 
     // Size of the data table, in bytes.
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -658,28 +658,163 @@ class CodeLocationLabel
         return raw_;
     }
     uint8_t *offset() const {
         JS_ASSERT(state_ == Relative);
         return raw_;
     }
 };
 
+// Describes the user-visible properties of a callsite.
+//
+// A few general notes about the stack-walking supported by CallSite(Desc):
+//  - This information facilitates stack-walking performed by FrameIter which
+//    is used by Error.stack and other user-visible stack-walking functions.
+//  - Ion/asm.js calling conventions do not maintain a frame-pointer so
+//    stack-walking must lookup the stack depth based on the PC.
+//  - Stack-walking only occurs from C++ after a synchronous calls (JS-to-JS and
+//    JS-to-C++). Thus, we do not need to map arbitrary PCs to stack-depths,
+//    just the return address at callsites.
+//  - An exception to the above rule is the interrupt callback which can happen
+//    at arbitrary PCs. In such cases, we drop frames from the stack-walk. In
+//    the future when a full PC->stack-depth map is maintained, we handle this
+//    case.
+class CallSiteDesc
+{
+    uint32_t line_;
+    uint32_t column_;
+    uint32_t functionNameIndex_;
+
+    static const uint32_t sEntryTrampoline = UINT32_MAX;
+    static const uint32_t sExit = UINT32_MAX - 1;
+
+  public:
+    static const uint32_t FUNCTION_NAME_INDEX_MAX = UINT32_MAX - 2;
+
+    CallSiteDesc() {}
+
+    CallSiteDesc(uint32_t line, uint32_t column, uint32_t functionNameIndex)
+     : line_(line), column_(column), functionNameIndex_(functionNameIndex)
+    {}
+
+    static CallSiteDesc Entry() { return CallSiteDesc(0, 0, sEntryTrampoline); }
+    static CallSiteDesc Exit() { return CallSiteDesc(0, 0, sExit); }
+
+    bool isEntry() const { return functionNameIndex_ == sEntryTrampoline; }
+    bool isExit() const { return functionNameIndex_ == sExit; }
+    bool isNormal() const { return !(isEntry() || isExit()); }
+
+    uint32_t line() const { JS_ASSERT(isNormal()); return line_; }
+    uint32_t column() const { JS_ASSERT(isNormal()); return column_; }
+    uint32_t functionNameIndex() const { JS_ASSERT(isNormal()); return functionNameIndex_; }
+};
+
+// Adds to CallSiteDesc the metadata necessary to walk the stack given an
+// initial stack-pointer.
+struct CallSite : public CallSiteDesc
+{
+    uint32_t returnAddressOffset_;
+    uint32_t stackDepth_;
+
+  public:
+    CallSite() {}
+
+    CallSite(CallSiteDesc desc, uint32_t returnAddressOffset, uint32_t stackDepth)
+      : CallSiteDesc(desc),
+        returnAddressOffset_(returnAddressOffset),
+        stackDepth_(stackDepth)
+    { }
+
+    void setReturnAddressOffset(uint32_t r) { returnAddressOffset_ = r; }
+    uint32_t returnAddressOffset() const { return returnAddressOffset_; }
+
+    // The stackDepth measures the amount of stack space pushed since the
+    // function was called. In particular, this includes the word pushed by the
+    // call instruction on x86/x64.
+    uint32_t stackDepth() const { JS_ASSERT(!isEntry()); return stackDepth_; }
+};
+
+typedef Vector<CallSite, 0, SystemAllocPolicy> CallSiteVector;
+
+// Summarizes a heap access made by asm.js code that needs to be patched later
+// and/or looked up by the asm.js signal handlers. Different architectures need
+// to know different things (x64: offset and length, ARM: where to patch in
+// heap length, x86: where to patch in heap length and base) hence the massive
+// #ifdefery.
+class AsmJSHeapAccess
+{
+    uint32_t offset_;
+#if defined(JS_CODEGEN_X86)
+    uint8_t cmpDelta_;  // the number of bytes from the cmp to the load/store instruction
+#endif
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+    uint8_t opLength_;  // the length of the load/store instruction
+    uint8_t isFloat32Load_;
+    AnyRegister::Code loadedReg_ : 8;
+#endif
+
+    JS_STATIC_ASSERT(AnyRegister::Total < UINT8_MAX);
+
+  public:
+    AsmJSHeapAccess() {}
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+    // If 'cmp' equals 'offset' or if it is not supplied then the
+    // cmpDelta_ is zero indicating that there is no length to patch.
+    AsmJSHeapAccess(uint32_t offset, uint32_t after, ArrayBufferView::ViewType vt,
+                    AnyRegister loadedReg, uint32_t cmp = UINT32_MAX)
+      : offset_(offset),
+# if defined(JS_CODEGEN_X86)
+        cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
+# endif
+        opLength_(after - offset),
+        isFloat32Load_(vt == ArrayBufferView::TYPE_FLOAT32),
+        loadedReg_(loadedReg.code())
+    {}
+    AsmJSHeapAccess(uint32_t offset, uint8_t after, uint32_t cmp = UINT32_MAX)
+      : offset_(offset),
+# if defined(JS_CODEGEN_X86)
+        cmpDelta_(cmp == UINT32_MAX ? 0 : offset - cmp),
+# endif
+        opLength_(after - offset),
+        isFloat32Load_(false),
+        loadedReg_(UINT8_MAX)
+    {}
+#elif defined(JS_CODEGEN_ARM)
+    explicit AsmJSHeapAccess(uint32_t offset)
+      : offset_(offset)
+    {}
+#endif
+
+    uint32_t offset() const { return offset_; }
+    void setOffset(uint32_t offset) { offset_ = offset; }
+#if defined(JS_CODEGEN_X86)
+    bool hasLengthCheck() const { return cmpDelta_ > 0; }
+    void *patchLengthAt(uint8_t *code) const { return code + (offset_ - cmpDelta_); }
+    void *patchOffsetAt(uint8_t *code) const { return code + (offset_ + opLength_); }
+#endif
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
+    unsigned opLength() const { return opLength_; }
+    bool isLoad() const { return loadedReg_ != UINT8_MAX; }
+    bool isFloat32Load() const { return isFloat32Load_; }
+    AnyRegister loadedReg() const { return AnyRegister::FromCode(loadedReg_); }
+#endif
+};
+
+typedef Vector<AsmJSHeapAccess, 0, SystemAllocPolicy> AsmJSHeapAccessVector;
+
 struct AsmJSGlobalAccess
 {
     CodeOffsetLabel patchAt;
     unsigned globalDataOffset;
 
     AsmJSGlobalAccess(CodeOffsetLabel patchAt, unsigned globalDataOffset)
       : patchAt(patchAt), globalDataOffset(globalDataOffset)
     {}
 };
 
-typedef Vector<AsmJSGlobalAccess, 0, IonAllocPolicy> AsmJSGlobalAccessVector;
-
 // Describes the intended pointee of an immediate to be embedded in asm.js
 // code. By representing the pointee as a symbolic enum, the pointee can be
 // patched after deserialization when the address of global things has changed.
 enum AsmJSImmKind
 {
     AsmJSImm_Runtime,
     AsmJSImm_StackLimit,
     AsmJSImm_ReportOverRecursed,
@@ -742,14 +877,36 @@ class AsmJSAbsoluteAddress
 struct AsmJSAbsoluteLink
 {
     AsmJSAbsoluteLink(CodeOffsetLabel patchAt, AsmJSImmKind target)
       : patchAt(patchAt), target(target) {}
     CodeOffsetLabel patchAt;
     AsmJSImmKind target;
 };
 
-typedef Vector<AsmJSAbsoluteLink, 0, SystemAllocPolicy> AsmJSAbsoluteLinkVector;
+// The base class of all Assemblers for all archs.
+class AssemblerShared
+{
+    Vector<CallSite, 0, SystemAllocPolicy> callsites_;
+    Vector<AsmJSHeapAccess, 0, SystemAllocPolicy> asmJSHeapAccesses_;
+    Vector<AsmJSGlobalAccess, 0, SystemAllocPolicy> asmJSGlobalAccesses_;
+    Vector<AsmJSAbsoluteLink, 0, SystemAllocPolicy> asmJSAbsoluteLinks_;
+
+  public:
+    bool append(CallSite callsite) { return callsites_.append(callsite); }
+    CallSiteVector &&extractCallSites() { return Move(callsites_); }
+
+    bool append(AsmJSHeapAccess access) { return asmJSHeapAccesses_.append(access); }
+    AsmJSHeapAccessVector &&extractAsmJSHeapAccesses() { return Move(asmJSHeapAccesses_); }
+
+    bool append(AsmJSGlobalAccess access) { return asmJSGlobalAccesses_.append(access); }
+    size_t numAsmJSGlobalAccesses() const { return asmJSGlobalAccesses_.length(); }
+    AsmJSGlobalAccess asmJSGlobalAccess(size_t i) const { return asmJSGlobalAccesses_[i]; }
+
+    bool append(AsmJSAbsoluteLink link) { return asmJSAbsoluteLinks_.append(link); }
+    size_t numAsmJSAbsoluteLinks() const { return asmJSAbsoluteLinks_.length(); }
+    AsmJSAbsoluteLink asmJSAbsoluteLink(size_t i) const { return asmJSAbsoluteLinks_[i]; }
+};
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_shared_Assembler_shared_h */
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -109,34 +109,33 @@ class Operand
         return disp_;
     }
     void *address() const {
         JS_ASSERT(kind() == MEM_ADDRESS32);
         return reinterpret_cast<void *>(disp_);
     }
 };
 
-class AssemblerX86Shared
+class AssemblerX86Shared : public AssemblerShared
 {
   protected:
     struct RelativePatch {
         int32_t offset;
         void *target;
         Relocation::Kind kind;
 
         RelativePatch(int32_t offset, void *target, Relocation::Kind kind)
           : offset(offset),
             target(target),
             kind(kind)
         { }
     };
 
     Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_;
     Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
-    AsmJSAbsoluteLinkVector asmJSAbsoluteLinks_;
     CompactBufferWriter jumpRelocations_;
     CompactBufferWriter dataRelocations_;
     CompactBufferWriter preBarriers_;
     bool enoughMemory_;
 
     void writeDataRelocation(const Value &val) {
         if (val.isMarkable()) {
             JS_ASSERT(static_cast<gc::Cell*>(val.toGCThing())->isTenured());
@@ -288,23 +287,16 @@ class AssemblerX86Shared
     }
     size_t numCodeLabels() const {
         return codeLabels_.length();
     }
     CodeLabel codeLabel(size_t i) {
         return codeLabels_[i];
     }
 
-    size_t numAsmJSAbsoluteLinks() const {
-        return asmJSAbsoluteLinks_.length();
-    }
-    const AsmJSAbsoluteLink &asmJSAbsoluteLink(size_t i) const {
-        return asmJSAbsoluteLinks_[i];
-    }
-
     // Size of the instruction stream, in bytes.
     size_t size() const {
         return masm.size();
     }
     // Size of the jump relocation table, in bytes.
     size_t jumpRelocationTableBytes() const {
         return jumpRelocations_.length();
     }
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -771,16 +771,27 @@ CodeGeneratorShared::visitOutOfLineTrunc
         masm.pop(src);
 
     restoreVolatile(dest);
 
     masm.jump(ool->rejoin());
     return true;
 }
 
+bool
+CodeGeneratorShared::omitOverRecursedCheck() const
+{
+    // If the current function makes no calls (which means it isn't recursive)
+    // and it uses only a small amount of stack space, it doesn't need a
+    // stack overflow check. Note that the actual number here is somewhat
+    // arbitrary, and codegen actually uses small bounded amounts of
+    // additional stack space in some cases too.
+    return frameSize() < 64 && !gen->performsCall();
+}
+
 void
 CodeGeneratorShared::emitPreBarrier(Register base, const LAllocation *index, MIRType type)
 {
     if (index->isConstant()) {
         Address address(base, ToInt32(index) * sizeof(Value));
         masm.patchableCallPreBarrier(address, type);
     } else {
         BaseIndex address(base, ToRegister(index), TimesEight);
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -430,16 +430,18 @@ class CodeGeneratorShared : public LInst
     CodeGeneratorShared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm);
 
   public:
     template <class ArgSeq, class StoreOutputTo>
     bool visitOutOfLineCallVM(OutOfLineCallVM<ArgSeq, StoreOutputTo> *ool);
 
     bool visitOutOfLineTruncateSlow(OutOfLineTruncateSlow *ool);
 
+    bool omitOverRecursedCheck() const;
+
   public:
     bool callTraceLIR(uint32_t blockIndex, LInstruction *lir, const char *bailoutName = nullptr);
 
     // Parallel aborts:
     //
     //    Parallel aborts work somewhat differently from sequential
     //    bailouts.  When an abort occurs, we first invoke
     //    ReportAbortPar() and then we return JS_ION_ERROR.  Each
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -34,23 +34,45 @@ namespace jit {
 CodeGeneratorX86Shared::CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm)
   : CodeGeneratorShared(gen, graph, masm)
 {
 }
 
 bool
 CodeGeneratorX86Shared::generatePrologue()
 {
+    JS_ASSERT(!gen->compilingAsmJS());
+
     // Note that this automatically sets MacroAssembler::framePushed().
     masm.reserveStack(frameSize());
 
     return true;
 }
 
 bool
+CodeGeneratorX86Shared::generateAsmJSPrologue(Label *stackOverflowLabel)
+{
+    JS_ASSERT(gen->compilingAsmJS());
+
+    // The asm.js over-recursed handler wants to be able to assume that SP
+    // points to the return address, so perform the check before pushing
+    // frameDepth.
+    if (!omitOverRecursedCheck()) {
+        masm.branchPtr(Assembler::AboveOrEqual,
+                       AsmJSAbsoluteAddress(AsmJSImm_StackLimit),
+                       StackPointer,
+                       stackOverflowLabel);
+    }
+
+    // Note that this automatically sets MacroAssembler::framePushed().
+    masm.reserveStack(frameSize());
+    return true;
+}
+
+bool
 CodeGeneratorX86Shared::generateEpilogue()
 {
     masm.bind(&returnLabel_);
 
 #ifdef JS_TRACE_LOGGING
     if (!gen->compilingAsmJS() && gen->info().executionMode() == SequentialExecution) {
         if (!emitTracelogStopEvent(TraceLogger::IonMonkey))
             return false;
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -73,16 +73,17 @@ class CodeGeneratorX86Shared : public Co
     template <typename T1, typename T2>
     bool bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) {
         masm.test32(lhs, rhs);
         return bailoutIf(c, snapshot);
     }
 
   protected:
     bool generatePrologue();
+    bool generateAsmJSPrologue(Label *stackOverflowLabe);
     bool generateEpilogue();
     bool generateOutOfLineCode();
 
     Operand createArrayElementOperand(Register elements, const LAllocation *index);
 
     void emitCompare(MCompare::CompareType type, const LAllocation *left, const LAllocation *right);
 
     // Emits a branch that directs control flow to the true block if |cond| is
--- a/js/src/jit/shared/MacroAssembler-x86-shared.h
+++ b/js/src/jit/shared/MacroAssembler-x86-shared.h
@@ -25,16 +25,18 @@ class MacroAssemblerX86Shared : public A
     // Bytes pushed onto the frame by the callee; includes frameDepth_. This is
     // needed to compute offsets to stack slots while temporary space has been
     // reserved for unexpected spills or C++ function calls. It is maintained
     // by functions which track stack alignment, which for clear distinction
     // use StudlyCaps (for example, Push, Pop).
     uint32_t framePushed_;
 
   public:
+    using Assembler::call;
+
     MacroAssemblerX86Shared()
       : framePushed_(0)
     { }
 
     void compareDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs) {
         if (cond & DoubleConditionBitInvert)
             ucomisd(rhs, lhs);
         else
@@ -657,16 +659,34 @@ class MacroAssemblerX86Shared : public A
     // non-function. Returns offset to be passed to markSafepointAt().
     bool buildFakeExitFrame(const Register &scratch, uint32_t *offset);
     void callWithExitFrame(JitCode *target);
 
     void callIon(const Register &callee) {
         call(callee);
     }
 
+    void appendCallSite(const CallSiteDesc &desc) {
+        // Add an extra sizeof(void*) to include the return address that was
+        // pushed by the call instruction (see CallSite::stackDepth).
+        enoughMemory_ &= append(CallSite(desc, currentOffset(), framePushed_ + sizeof(void*)));
+    }
+
+    void call(const CallSiteDesc &desc, Label *label) {
+        call(label);
+        appendCallSite(desc);
+    }
+    void call(const CallSiteDesc &desc, const Register &reg) {
+        call(reg);
+        appendCallSite(desc);
+    }
+    void callIonFromAsmJS(const Register &reg) {
+        call(CallSiteDesc::Exit(), reg);
+    }
+
     void checkStackAlignment() {
         // Exists for ARM compatibility.
     }
 
     CodeOffsetLabel labelForPatch() {
         return CodeOffsetLabel(size());
     }
 
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -523,18 +523,17 @@ class Assembler : public AssemblerX86Sha
         else
             movq(word, dest);
     }
     void mov(ImmPtr imm, const Register &dest) {
         movq(imm, dest);
     }
     void mov(AsmJSImmPtr imm, const Register &dest) {
         masm.movq_i64r(-1, dest.code());
-        AsmJSAbsoluteLink link(masm.currentOffset(), imm.kind());
-        enoughMemory_ &= asmJSAbsoluteLinks_.append(link);
+        enoughMemory_ &= append(AsmJSAbsoluteLink(masm.currentOffset(), imm.kind()));
     }
     void mov(const Operand &src, const Register &dest) {
         movq(src, dest);
     }
     void mov(const Register &src, const Operand &dest) {
         movq(src, dest);
     }
     void mov(const Imm32 &imm32, const Operand &dest) {
--- a/js/src/jit/x64/CodeGenerator-x64.cpp
+++ b/js/src/jit/x64/CodeGenerator-x64.cpp
@@ -417,17 +417,17 @@ CodeGeneratorX64::visitAsmJSLoadHeap(LAs
       case ArrayBufferView::TYPE_UINT16:  masm.movzwl(srcAddr, ToRegister(ins->output())); break;
       case ArrayBufferView::TYPE_INT32:
       case ArrayBufferView::TYPE_UINT32:  masm.movl(srcAddr, ToRegister(ins->output())); break;
       case ArrayBufferView::TYPE_FLOAT32: masm.loadFloat32(srcAddr, ToFloatRegister(ins->output())); break;
       case ArrayBufferView::TYPE_FLOAT64: masm.loadDouble(srcAddr, ToFloatRegister(ins->output())); break;
       default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
     }
     uint32_t after = masm.size();
-    return skipNote || gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(ins->output())));
+    return skipNote || masm.append(AsmJSHeapAccess(before, after, vt, ToAnyRegister(ins->output())));
 }
 
 bool
 CodeGeneratorX64::visitAsmJSStoreHeap(LAsmJSStoreHeap *ins)
 {
     MAsmJSStoreHeap *mir = ins->mir();
     ArrayBufferView::ViewType vt = mir->viewType();
     const LAllocation *ptr = ins->ptr();
@@ -465,73 +465,73 @@ CodeGeneratorX64::visitAsmJSStoreHeap(LA
           case ArrayBufferView::TYPE_INT32:
           case ArrayBufferView::TYPE_UINT32:  masm.movl(ToRegister(ins->value()), dstAddr); break;
           case ArrayBufferView::TYPE_FLOAT32: masm.storeFloat32(ToFloatRegister(ins->value()), dstAddr); break;
           case ArrayBufferView::TYPE_FLOAT64: masm.storeDouble(ToFloatRegister(ins->value()), dstAddr); break;
           default: MOZ_ASSUME_UNREACHABLE("unexpected array type");
         }
     }
     uint32_t after = masm.size();
-    return skipNote || gen->noteHeapAccess(AsmJSHeapAccess(before, after));
+    return skipNote || masm.append(AsmJSHeapAccess(before, after));
 }
 
 bool
 CodeGeneratorX64::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
 {
     MAsmJSLoadGlobalVar *mir = ins->mir();
 
     CodeOffsetLabel label;
     if (mir->type() == MIRType_Int32)
         label = masm.loadRipRelativeInt32(ToRegister(ins->output()));
     else
         label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output()));
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 bool
 CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
 {
     MAsmJSStoreGlobalVar *mir = ins->mir();
 
     MIRType type = mir->value()->type();
     JS_ASSERT(IsNumberType(type));
 
     CodeOffsetLabel label;
     if (type == MIRType_Int32)
         label = masm.storeRipRelativeInt32(ToRegister(ins->value()));
     else
         label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value()));
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 bool
 CodeGeneratorX64::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins)
 {
     MAsmJSLoadFuncPtr *mir = ins->mir();
 
     Register index = ToRegister(ins->index());
     Register tmp = ToRegister(ins->temp());
     Register out = ToRegister(ins->output());
 
     CodeOffsetLabel label = masm.leaRipRelative(tmp);
     masm.loadPtr(Operand(tmp, index, TimesEight, 0), out);
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 bool
 CodeGeneratorX64::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins)
 {
     MAsmJSLoadFFIFunc *mir = ins->mir();
 
     CodeOffsetLabel label = masm.loadRipRelativeInt64(ToRegister(ins->output()));
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 void
 DispatchIonCache::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
 {
     // Can always use the scratch register on x64.
     addState->dispatchScratch = ScratchReg;
 }
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -105,16 +105,24 @@ class MacroAssemblerX64 : public MacroAs
     void call(ImmPtr target) {
         call(ImmWord(uintptr_t(target.value)));
     }
     void call(AsmJSImmPtr target) {
         mov(target, rax);
         call(rax);
     }
 
+    void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
+        call(target);
+        appendCallSite(desc);
+    }
+    void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
+        call(CallSiteDesc::Exit(), target);
+    }
+
     // Refers to the upper 32 bits of a 64-bit Value operand.
     // On x86_64, the upper 32 bits do not necessarily only contain the type.
     Operand ToUpper32(Operand base) {
         switch (base.kind()) {
           case Operand::MEM_REG_DISP:
             return Operand(Register::FromCode(base.base()), base.disp() + 4);
 
           case Operand::MEM_SCALE:
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -255,18 +255,17 @@ class Assembler : public AssemblerX86Sha
         else
             movl(imm, dest);
     }
     void mov(ImmPtr imm, Register dest) {
         mov(ImmWord(uintptr_t(imm.value)), dest);
     }
     void mov(AsmJSImmPtr imm, Register dest) {
         masm.movl_i32r(-1, dest.code());
-        AsmJSAbsoluteLink link(masm.currentOffset(), imm.kind());
-        enoughMemory_ &= asmJSAbsoluteLinks_.append(link);
+        enoughMemory_ &= append(AsmJSAbsoluteLink(masm.currentOffset(), imm.kind()));
     }
     void mov(const Operand &src, const Register &dest) {
         movl(src, dest);
     }
     void mov(const Register &src, const Operand &dest) {
         movl(src, dest);
     }
     void mov(Imm32 imm, const Operand &dest) {
@@ -337,18 +336,17 @@ class Assembler : public AssemblerX86Sha
             writeDataRelocation(imm);
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
         }
     }
     void cmpl(const AsmJSAbsoluteAddress &lhs, const Register &rhs) {
         masm.cmpl_rm_force32(rhs.code(), (void*)-1);
-        AsmJSAbsoluteLink link(masm.currentOffset(), lhs.kind());
-        enoughMemory_ &= asmJSAbsoluteLinks_.append(link);
+        enoughMemory_ &= append(AsmJSAbsoluteLink(masm.currentOffset(), lhs.kind()));
     }
     CodeOffsetLabel cmplWithPatch(const Register &lhs, Imm32 rhs) {
         masm.cmpl_ir_force32(rhs.value, lhs.code());
         return masm.currentOffset();
     }
 
     void jmp(ImmPtr target, Relocation::Kind reloc = Relocation::HARDCODED) {
         JmpSrc src = masm.jmp();
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -439,17 +439,17 @@ CodeGeneratorX86::loadViewTypeElement(Ar
 template<typename T>
 bool
 CodeGeneratorX86::loadAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const T &srcAddr,
                                              const LDefinition *out)
 {
     uint32_t before = masm.size();
     loadViewTypeElement(vt, srcAddr, out);
     uint32_t after = masm.size();
-    return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out)));
+    return masm.append(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out)));
 }
 
 bool
 CodeGeneratorX86::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins)
 {
     const MLoadTypedArrayElementStatic *mir = ins->mir();
     ArrayBufferView::ViewType vt = mir->viewType();
     JS_ASSERT_IF(vt == ArrayBufferView::TYPE_FLOAT32, mir->type() == MIRType_Float32);
@@ -512,17 +512,17 @@ CodeGeneratorX86::visitAsmJSLoadHeap(LAs
 
     CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
     masm.j(Assembler::AboveOrEqual, ool->entry());
 
     uint32_t before = masm.size();
     loadViewTypeElement(vt, srcAddr, out);
     uint32_t after = masm.size();
     masm.bind(ool->rejoin());
-    return gen->noteHeapAccess(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out), cmp.offset()));
+    return masm.append(AsmJSHeapAccess(before, after, vt, ToAnyRegister(out), cmp.offset()));
 }
 
 bool
 CodeGeneratorX86::visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds *ool)
 {
     if (ool->dest().isFloat()) {
         if (ool->isFloat32Load())
             masm.loadConstantFloat32(float(GenericNaN()), ool->dest().fpu());
@@ -558,17 +558,17 @@ CodeGeneratorX86::storeViewTypeElement(A
 template<typename T>
 bool
 CodeGeneratorX86::storeAndNoteViewTypeElement(ArrayBufferView::ViewType vt, const LAllocation *value,
                                               const T &dstAddr)
 {
     uint32_t before = masm.size();
     storeViewTypeElement(vt, value, dstAddr);
     uint32_t after = masm.size();
-    return gen->noteHeapAccess(AsmJSHeapAccess(before, after));
+    return masm.append(AsmJSHeapAccess(before, after));
 }
 
 bool
 CodeGeneratorX86::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins)
 {
     MStoreTypedArrayElementStatic *mir = ins->mir();
     ArrayBufferView::ViewType vt = mir->viewType();
 
@@ -611,17 +611,17 @@ CodeGeneratorX86::visitAsmJSStoreHeap(LA
     CodeOffsetLabel cmp = masm.cmplWithPatch(ptrReg, Imm32(0));
     Label rejoin;
     masm.j(Assembler::AboveOrEqual, &rejoin);
 
     uint32_t before = masm.size();
     storeViewTypeElement(vt, value, dstAddr);
     uint32_t after = masm.size();
     masm.bind(&rejoin);
-    return gen->noteHeapAccess(AsmJSHeapAccess(before, after, cmp.offset()));
+    return masm.append(AsmJSHeapAccess(before, after, cmp.offset()));
 }
 
 bool
 CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins)
 {
     MAsmJSLoadGlobalVar *mir = ins->mir();
     MIRType type = mir->type();
     JS_ASSERT(IsNumberType(type));
@@ -629,17 +629,17 @@ CodeGeneratorX86::visitAsmJSLoadGlobalVa
     CodeOffsetLabel label;
     if (type == MIRType_Int32)
         label = masm.movlWithPatch(PatchedAbsoluteAddress(), ToRegister(ins->output()));
     else if (type == MIRType_Float32)
         label = masm.movssWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
     else
         label = masm.movsdWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 bool
 CodeGeneratorX86::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
 {
     MAsmJSStoreGlobalVar *mir = ins->mir();
 
     MIRType type = mir->value()->type();
@@ -648,40 +648,40 @@ CodeGeneratorX86::visitAsmJSStoreGlobalV
     CodeOffsetLabel label;
     if (type == MIRType_Int32)
         label = masm.movlWithPatch(ToRegister(ins->value()), PatchedAbsoluteAddress());
     else if (type == MIRType_Float32)
         label = masm.movssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
     else
         label = masm.movsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 bool
 CodeGeneratorX86::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins)
 {
     MAsmJSLoadFuncPtr *mir = ins->mir();
 
     Register index = ToRegister(ins->index());
     Register out = ToRegister(ins->output());
     CodeOffsetLabel label = masm.movlWithPatch(PatchedAbsoluteAddress(), index, TimesFour, out);
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 bool
 CodeGeneratorX86::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins)
 {
     MAsmJSLoadFFIFunc *mir = ins->mir();
 
     Register out = ToRegister(ins->output());
     CodeOffsetLabel label = masm.movlWithPatch(PatchedAbsoluteAddress(), out);
 
-    return gen->noteGlobalAccess(label.offset(), mir->globalDataOffset());
+    return masm.append(AsmJSGlobalAccess(label.offset(), mir->globalDataOffset()));
 }
 
 void
 CodeGeneratorX86::postAsmJSCall(LAsmJSCall *lir)
 {
     MAsmJSCall *mir = lir->mir();
     if (!IsFloatingPointType(mir->type()) || mir->callee().which() != MAsmJSCall::Callee::Builtin)
         return;
--- a/js/src/jit/x86/MacroAssembler-x86.h
+++ b/js/src/jit/x86/MacroAssembler-x86.h
@@ -66,16 +66,17 @@ class MacroAssemblerX86 : public MacroAs
 
   public:
     using MacroAssemblerX86Shared::Push;
     using MacroAssemblerX86Shared::Pop;
     using MacroAssemblerX86Shared::callWithExitFrame;
     using MacroAssemblerX86Shared::branch32;
     using MacroAssemblerX86Shared::load32;
     using MacroAssemblerX86Shared::store32;
+    using MacroAssemblerX86Shared::call;
 
     MacroAssemblerX86()
       : inCall_(false),
         enoughMemory_(true)
     {
     }
 
     // The buffer is about to be linked, make sure any constant pools or excess
@@ -1100,16 +1101,23 @@ class MacroAssemblerX86 : public MacroAs
     }
 
     void callWithExitFrame(JitCode *target, Register dynStack) {
         addPtr(Imm32(framePushed()), dynStack);
         makeFrameDescriptor(dynStack, JitFrame_IonJS);
         Push(dynStack);
         call(target);
     }
+    void call(const CallSiteDesc &desc, AsmJSImmPtr target) {
+        call(target);
+        appendCallSite(desc);
+    }
+    void callExit(AsmJSImmPtr target, uint32_t stackArgBytes) {
+        call(CallSiteDesc::Exit(), target);
+    }
 
     // Save an exit frame to the thread data of the current thread, given a
     // register that holds a PerThreadData *.
     void linkParallelExitFrame(const Register &pt) {
         movl(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop)));
     }
 
 #ifdef JSGC_GENERATIONAL
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1201,18 +1201,18 @@ JSContext::restoreFrameChain()
     if (Activation *act = mainThread().activation())
         act->restoreFrameChain();
 }
 
 bool
 JSContext::currentlyRunning() const
 {
     for (ActivationIterator iter(runtime()); !iter.done(); ++iter) {
-        if (iter.activation()->cx() == this) {
-            if (iter.activation()->hasSavedFrameChain())
+        if (iter->cx() == this) {
+            if (iter->hasSavedFrameChain())
                 return false;
             return true;
         }
     }
 
     return false;
 }
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -676,17 +676,17 @@ JSCompartment::setObjectMetadataCallback
 
     objectMetadataCallback = callback;
 }
 
 bool
 JSCompartment::hasScriptsOnStack()
 {
     for (ActivationIterator iter(runtimeFromMainThread()); !iter.done(); ++iter) {
-        if (iter.activation()->compartment() == this)
+        if (iter->compartment() == this)
             return true;
     }
 
     return false;
 }
 
 static bool
 AddInnerLazyFunctionsFromScript(JSScript *script, AutoObjectVector &lazyFunctions)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4272,17 +4272,17 @@ AutoGCSlice::AutoGCSlice(JSRuntime *rt)
 {
     /*
      * During incremental GC, the compartment's active flag determines whether
      * there are stack frames active for any of its scripts. Normally this flag
      * is set at the beginning of the mark phase. During incremental GC, we also
      * set it at the start of every phase.
      */
     for (ActivationIterator iter(rt); !iter.done(); ++iter)
-        iter.activation()->compartment()->zone()->active = true;
+        iter->compartment()->zone()->active = true;
 
     for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
         /*
          * Clear needsBarrier early so we don't do any write barriers during
          * GC. We don't need to update the Ion barriers (which is expensive)
          * because Ion code doesn't run during GC. If need be, we'll update the
          * Ion barriers in ~AutoGCSlice.
          */
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -4020,17 +4020,18 @@ ConstraintTypeSet::sweep(Zone *zone, boo
                     HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
                         (zone->types.typeLifoAlloc, objectSet, objectCount, object);
                 if (pentry) {
                     *pentry = object;
                 } else {
                     *oom = true;
                     flags |= TYPE_FLAG_ANYOBJECT;
                     clearObjects();
-                    return;
+                    objectCount = 0;
+                    break;
                 }
             }
         }
         setBaseObjectCount(objectCount);
     } else if (objectCount == 1) {
         TypeObjectKey *object = (TypeObjectKey *) objectSet;
         if (IsAboutToBeFinalized(object)) {
             objectSet = nullptr;
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -109,17 +109,17 @@ GetValueType(const Value &val)
         return Type::ObjectType(&val.toObject());
     return Type::PrimitiveType(val.extractNonDoubleType());
 }
 
 inline Type
 GetMaybeOptimizedOutValueType(const Value &val)
 {
     if (val.isMagic() && val.whyMagic() == JS_OPTIMIZED_OUT)
-        return Type::UndefinedType();
+        return Type::UnknownType();
     return GetValueType(val);
 }
 
 inline TypeFlags
 PrimitiveTypeFlag(JSValueType type)
 {
     switch (type) {
       case JSVAL_TYPE_UNDEFINED:
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1177,18 +1177,18 @@ JSScript::initScriptCounts(JSContext *cx
         return false;
     }
     hasScriptCounts_ = true; // safe to set this;  we can't fail after this point
 
     JS_ASSERT(size_t(cursor - base) == bytes);
 
     /* Enable interrupts in any interpreter frames running on this script. */
     for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
-        if (iter.activation()->isInterpreter())
-            iter.activation()->asInterpreter()->enableInterruptsIfRunning(this);
+        if (iter->isInterpreter())
+            iter->asInterpreter()->enableInterruptsIfRunning(this);
     }
 
     return true;
 }
 
 static inline ScriptCountsMap::Ptr GetScriptCountsMapEntry(JSScript *script)
 {
     JS_ASSERT(script->hasScriptCounts());
@@ -3145,18 +3145,18 @@ JSScript::ensureHasDebugScript(JSContext
     hasDebugScript_ = true; // safe to set this;  we can't fail after this point
 
     /*
      * Ensure that any Interpret() instances running on this script have
      * interrupts enabled. The interrupts must stay enabled until the
      * debug state is destroyed.
      */
     for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
-        if (iter.activation()->isInterpreter())
-            iter.activation()->asInterpreter()->enableInterruptsIfRunning(this);
+        if (iter->isInterpreter())
+            iter->asInterpreter()->enableInterruptsIfRunning(this);
     }
 
     return true;
 }
 
 void
 JSScript::setNewStepMode(FreeOp *fop, uint32_t newValue)
 {
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -184,20 +184,20 @@ class WeakMap : public HashMap<Key, Valu
             /* If the entry is live, ensure its key and value are marked. */
             Key key(e.front().key());
             if (gc::IsMarked(const_cast<Key *>(&key))) {
                 if (markValue(trc, &e.front().value()))
                     markedAny = true;
                 if (e.front().key() != key)
                     entryMoved(e, key);
             } else if (keyNeedsMark(key)) {
+                gc::Mark(trc, &e.front().value(), "WeakMap entry value");
                 gc::Mark(trc, &key, "proxy-preserved WeakMap entry key");
                 if (e.front().key() != key)
                     entryMoved(e, key);
-                gc::Mark(trc, &e.front().value(), "WeakMap entry value");
                 markedAny = true;
             }
             key.unsafeSet(nullptr);
         }
         return markedAny;
     }
 
     void sweep() {
--- a/js/src/vm/OldDebugAPI.cpp
+++ b/js/src/vm/OldDebugAPI.cpp
@@ -265,18 +265,18 @@ JS_ClearAllTrapsForCompartment(JSContext
 
 JS_PUBLIC_API(bool)
 JS_SetInterrupt(JSRuntime *rt, JSInterruptHook hook, void *closure)
 {
     rt->debugHooks.interruptHook = hook;
     rt->debugHooks.interruptHookData = closure;
 
     for (ActivationIterator iter(rt); !iter.done(); ++iter) {
-        if (iter.activation()->isInterpreter())
-            iter.activation()->asInterpreter()->enableInterruptsUnconditionally();
+        if (iter->isInterpreter())
+            iter->asInterpreter()->enableInterruptsUnconditionally();
     }
 
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *hoop, void **closurep)
 {
@@ -838,44 +838,16 @@ JS_DumpCompartmentPCCounts(JSContext *cx
     for (CellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
         RootedScript script(cx, i.get<JSScript>());
         if (script->compartment() != cx->compartment())
             continue;
 
         if (script->hasScriptCounts())
             JS_DumpPCCounts(cx, script);
     }
-
-#if defined(JS_ION)
-    for (unsigned thingKind = FINALIZE_OBJECT0; thingKind < FINALIZE_OBJECT_LIMIT; thingKind++) {
-        for (CellIter i(cx->zone(), (AllocKind) thingKind); !i.done(); i.next()) {
-            JSObject *obj = i.get<JSObject>();
-            if (obj->compartment() != cx->compartment())
-                continue;
-
-            if (obj->is<AsmJSModuleObject>()) {
-                AsmJSModule &module = obj->as<AsmJSModuleObject>().module();
-
-                Sprinter sprinter(cx);
-                if (!sprinter.init())
-                    return;
-
-                fprintf(stdout, "--- Asm.js Module ---\n");
-
-                for (size_t i = 0; i < module.numFunctionCounts(); i++) {
-                    jit::IonScriptCounts *counts = module.functionCounts(i);
-                    DumpIonScriptCounts(&sprinter, counts);
-                }
-
-                fputs(sprinter.string(), stdout);
-                fprintf(stdout, "--- END Asm.js Module ---\n");
-            }
-        }
-    }
-#endif
 }
 
 JS_FRIEND_API(bool)
 js::CanCallContextDebugHandler(JSContext *cx)
 {
     return !!cx->runtime()->debugHooks.debuggerHandler;
 }
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -581,28 +581,33 @@ FrameIter::settleOnActivation()
                 continue;
             }
 
             nextJitFrame();
             data_.state_ = JIT;
             return;
         }
 
+        if (activation->isAsmJS()) {
+            data_.asmJSFrames_ = AsmJSFrameIterator(data_.activations_->asAsmJS());
+
+            if (data_.asmJSFrames_.done()) {
+                ++data_.activations_;
+                continue;
+            }
+
+            data_.state_ = ASMJS;
+            return;
+        }
+
         // ForkJoin activations don't contain iterable frames, so skip them.
         if (activation->isForkJoin()) {
             ++data_.activations_;
             continue;
         }
-
-        // Until asm.js has real stack-walking, we have each AsmJSActivation
-        // expose a single function (the entry function).
-        if (activation->isAsmJS()) {
-            data_.state_ = ASMJS;
-            return;
-        }
 #endif
 
         JS_ASSERT(activation->isInterpreter());
 
         InterpreterActivation *interpAct = activation->asInterpreter();
         data_.interpFrames_ = InterpreterFrameIterator(interpAct);
 
         // If we OSR'ed into JIT code, skip the interpreter frame so that
@@ -629,32 +634,34 @@ FrameIter::Data::Data(JSContext *cx, Sav
     contextOption_(contextOption),
     principals_(principals),
     pc_(nullptr),
     interpFrames_(nullptr),
     activations_(cx->runtime())
 #ifdef JS_ION
   , jitFrames_((uint8_t *)nullptr, SequentialExecution)
   , ionInlineFrameNo_(0)
+  , asmJSFrames_(nullptr)
 #endif
 {
 }
 
 FrameIter::Data::Data(const FrameIter::Data &other)
   : cx_(other.cx_),
     savedOption_(other.savedOption_),
     contextOption_(other.contextOption_),
     principals_(other.principals_),
     state_(other.state_),
     pc_(other.pc_),
     interpFrames_(other.interpFrames_),
     activations_(other.activations_)
 #ifdef JS_ION
   , jitFrames_(other.jitFrames_)
   , ionInlineFrameNo_(other.ionInlineFrameNo_)
+  , asmJSFrames_(other.asmJSFrames_)
 #endif
 {
 }
 
 FrameIter::FrameIter(JSContext *cx, SavedOption savedOption)
   : data_(cx, savedOption, CURRENT_CONTEXT, nullptr)
 #ifdef JS_ION
   , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
@@ -726,16 +733,26 @@ FrameIter::popJitFrame()
 
     if (!data_.jitFrames_.done()) {
         nextJitFrame();
         return;
     }
 
     popActivation();
 }
+
+void
+FrameIter::popAsmJSFrame()
+{
+    JS_ASSERT(data_.state_ == ASMJS);
+
+    ++data_.asmJSFrames_;
+    if (data_.asmJSFrames_.done())
+        popActivation();
+}
 #endif
 
 FrameIter &
 FrameIter::operator++()
 {
     switch (data_.state_) {
       case DONE:
         MOZ_ASSUME_UNREACHABLE("Unexpected state");
@@ -762,34 +779,30 @@ FrameIter::operator++()
 #endif
                 } else {
                     popInterpreterFrame();
                 }
             }
 
             data_.contextOption_ = prevContextOption;
             data_.savedOption_ = prevSavedOption;
-            data_.cx_ = data_.activations_.activation()->cx();
+            data_.cx_ = data_.activations_->cx();
             break;
         }
         popInterpreterFrame();
         break;
       case JIT:
 #ifdef JS_ION
         popJitFrame();
         break;
 #else
         MOZ_ASSUME_UNREACHABLE("Unexpected state");
 #endif
       case ASMJS:
-        // As described in settleOnActivation, an AsmJSActivation currently only
-        // represents a single asm.js function, so, if the FrameIter is
-        // currently stopped on an ASMJS frame, then we can pop the entire
-        // AsmJSActivation.
-        popActivation();
+        popAsmJSFrame();
         break;
     }
     return *this;
 }
 
 FrameIter::Data *
 FrameIter::copyData() const
 {
@@ -815,17 +828,17 @@ JSCompartment *
 FrameIter::compartment() const
 {
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
       case ASMJS:
-        return data_.activations_.activation()->compartment();
+        return data_.activations_->compartment();
     }
     MOZ_ASSUME_UNREACHABLE("Unexpected state");
 }
 
 bool
 FrameIter::isFunctionFrame() const
 {
     switch (data_.state_) {
@@ -935,18 +948,17 @@ FrameIter::functionDisplayAtom() const
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
         return callee()->displayAtom();
       case ASMJS: {
 #ifdef JS_ION
-        AsmJSActivation &act = *data_.activations_.activation()->asAsmJS();
-        return act.module().exportedFunction(act.exportIndex()).name();
+        return data_.asmJSFrames_.functionDisplayAtom();
 #else
         break;
 #endif
       }
     }
 
     MOZ_ASSUME_UNREACHABLE("Unexpected state");
 }
@@ -957,17 +969,17 @@ FrameIter::scriptSource() const
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
         return script()->scriptSource();
       case ASMJS:
 #ifdef JS_ION
-        return data_.activations_.activation()->asAsmJS()->module().scriptSource();
+        return data_.activations_->asAsmJS()->module().scriptSource();
 #else
         break;
 #endif
     }
 
     MOZ_ASSUME_UNREACHABLE("Unexpected state");
 }
 
@@ -977,17 +989,17 @@ FrameIter::scriptFilename() const
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
         return script()->filename();
       case ASMJS:
 #ifdef JS_ION
-        return data_.activations_.activation()->asAsmJS()->module().scriptSource()->filename();
+        return data_.activations_->asAsmJS()->module().scriptSource()->filename();
 #else
         break;
 #endif
     }
 
     MOZ_ASSUME_UNREACHABLE("Unexpected state");
 }
 
@@ -995,44 +1007,39 @@ unsigned
 FrameIter::computeLine(uint32_t *column) const
 {
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
         return PCToLineNumber(script(), pc(), column);
-      case ASMJS: {
+      case ASMJS:
 #ifdef JS_ION
-        AsmJSActivation &act = *data_.activations_.activation()->asAsmJS();
-        AsmJSModule::ExportedFunction &func = act.module().exportedFunction(act.exportIndex());
-        if (column)
-            *column = func.column();
-        return func.line();
+        return data_.asmJSFrames_.computeLine(column);
 #else
         break;
 #endif
-      }
     }
 
     MOZ_ASSUME_UNREACHABLE("Unexpected state");
 }
 
 JSPrincipals *
 FrameIter::originPrincipals() const
 {
     switch (data_.state_) {
       case DONE:
         break;
       case INTERP:
       case JIT:
         return script()->originPrincipals();
       case ASMJS: {
 #ifdef JS_ION
-        return data_.activations_.activation()->asAsmJS()->module().scriptSource()->originPrincipals();
+        return data_.activations_->asAsmJS()->module().scriptSource()->originPrincipals();
 #else
         break;
 #endif
       }
     }
 
     MOZ_ASSUME_UNREACHABLE("Unexpected state");
 }
@@ -1123,33 +1130,33 @@ void
 FrameIter::updatePcQuadratic()
 {
     switch (data_.state_) {
       case DONE:
       case ASMJS:
         break;
       case INTERP: {
         InterpreterFrame *frame = interpFrame();
-        InterpreterActivation *activation = data_.activations_.activation()->asInterpreter();
+        InterpreterActivation *activation = data_.activations_->asInterpreter();
 
         // Look for the current frame.
         data_.interpFrames_ = InterpreterFrameIterator(activation);
         while (data_.interpFrames_.frame() != frame)
             ++data_.interpFrames_;
 
         // Update the pc.
         JS_ASSERT(data_.interpFrames_.frame() == frame);
         data_.pc_ = data_.interpFrames_.pc();
         return;
       }
       case JIT:
 #ifdef JS_ION
         if (data_.jitFrames_.isBaselineJS()) {
             jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame();
-            jit::JitActivation *activation = data_.activations_.activation()->asJit();
+            jit::JitActivation *activation = data_.activations_->asJit();
 
             // ActivationIterator::ionTop_ may be invalid, so create a new
             // activation iterator.
             data_.activations_ = ActivationIterator(data_.cx_->runtime());
             while (data_.activations_.activation() != activation)
                 ++data_.activations_;
 
             // Look for the current frame.
@@ -1649,23 +1656,23 @@ jit::JitActivation::markRematerializedFr
         RematerializedFrameVector &frames = e.front().value();
         for (size_t i = 0; i < frames.length(); i++)
             frames[i]->mark(trc);
     }
 }
 
 #endif // JS_ION
 
-AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module, unsigned exportIndex)
+AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module)
   : Activation(cx, AsmJS),
     module_(module),
     errorRejoinSP_(nullptr),
     profiler_(nullptr),
     resumePC_(nullptr),
-    exportIndex_(exportIndex)
+    exitSP_(nullptr)
 {
     if (cx->runtime()->spsProfiler.enabled()) {
         // Use a profiler string that matches jsMatch regex in
         // browser/devtools/profiler/cleopatra/js/parserWorker.js.
         // (For now use a single static string to avoid further slowing down
         // calls into asm.js.)
         profiler_ = &cx->runtime()->spsProfiler;
         profiler_->enterNative("asm.js code :0", this);
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -7,16 +7,17 @@
 #ifndef vm_Stack_h
 #define vm_Stack_h
 
 #include "mozilla/MemoryReporting.h"
 
 #include "jsfun.h"
 #include "jsscript.h"
 
+#include "jit/AsmJSLink.h"
 #include "jit/JitFrameIterator.h"
 #ifdef CHECK_OSIPOINT_REGISTERS
 #include "jit/Registers.h" // for RegisterDump
 #endif
 #include "js/OldDebugAPI.h"
 
 struct JSCompartment;
 struct JSGenerator;
@@ -1299,16 +1300,19 @@ class ActivationIterator
   private:
     void settle();
 
   public:
     explicit ActivationIterator(JSRuntime *rt);
 
     ActivationIterator &operator++();
 
+    Activation *operator->() const {
+        return activation_;
+    }
     Activation *activation() const {
         return activation_;
     }
     uint8_t *jitTop() const {
         JS_ASSERT(activation_->isJit());
         return jitTop_;
     }
     bool done() const {
@@ -1494,39 +1498,44 @@ class InterpreterFrameIterator
 // all kinds of jit code.
 class AsmJSActivation : public Activation
 {
     AsmJSModule &module_;
     AsmJSActivation *prevAsmJS_;
     void *errorRejoinSP_;
     SPSProfiler *profiler_;
     void *resumePC_;
+    uint8_t *exitSP_;
 
-    // These bits are temporary and will be replaced when real asm.js
-    // stack-walking support lands:
-    unsigned exportIndex_;
+    static const intptr_t InterruptedSP = -1;
 
   public:
-    AsmJSActivation(JSContext *cx, AsmJSModule &module, unsigned exportIndex);
+    AsmJSActivation(JSContext *cx, AsmJSModule &module);
     ~AsmJSActivation();
 
     JSContext *cx() { return cx_; }
     AsmJSModule &module() const { return module_; }
-    unsigned exportIndex() const { return exportIndex_; }
     AsmJSActivation *prevAsmJS() const { return prevAsmJS_; }
 
     // Read by JIT code:
     static unsigned offsetOfContext() { return offsetof(AsmJSActivation, cx_); }
     static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); }
 
     // Initialized by JIT code:
     static unsigned offsetOfErrorRejoinSP() { return offsetof(AsmJSActivation, errorRejoinSP_); }
+    static unsigned offsetOfExitSP() { return offsetof(AsmJSActivation, exitSP_); }
 
     // Set from SIGSEGV handler:
-    void setResumePC(void *pc) { resumePC_ = pc; }
+    void setInterrupted(void *pc) { resumePC_ = pc; exitSP_ = (uint8_t*)InterruptedSP; }
+    bool isInterruptedSP() const { return exitSP_ == (uint8_t*)InterruptedSP; }
+
+    // Note: exitSP is the sp right before the call instruction. On x86, this
+    // means before the return address is pushed on the stack, on ARM, this
+    // means after.
+    uint8_t *exitSP() const { JS_ASSERT(!isInterruptedSP()); return exitSP_; }
 };
 
 // A FrameIter walks over the runtime's stack of JS script activations,
 // abstracting over whether the JS scripts were running in the interpreter or
 // different modes of compiled code.
 //
 // FrameIter is parameterized by what it includes in the stack iteration:
 //  - The SavedOption controls whether FrameIter stops when it finds an
@@ -1567,16 +1576,17 @@ class FrameIter
         jsbytecode *    pc_;
 
         InterpreterFrameIterator interpFrames_;
         ActivationIterator activations_;
 
 #ifdef JS_ION
         jit::JitFrameIterator jitFrames_;
         unsigned ionInlineFrameNo_;
+        AsmJSFrameIterator asmJSFrames_;
 #endif
 
         Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption,
              JSPrincipals *principals);
         Data(const Data &other);
     };
 
     FrameIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
@@ -1693,16 +1703,17 @@ class FrameIter
     jit::InlineFrameIterator ionInlineFrames_;
 #endif
 
     void popActivation();
     void popInterpreterFrame();
 #ifdef JS_ION
     void nextJitFrame();
     void popJitFrame();
+    void popAsmJSFrame();
 #endif
     void settleOnActivation();
 
     friend class ::JSBrokenFrameIterator;
 };
 
 class ScriptFrameIter : public FrameIter
 {
--- a/js/xpconnect/loader/XPCOMUtils.jsm
+++ b/js/xpconnect/loader/XPCOMUtils.jsm
@@ -274,23 +274,23 @@ this.XPCOMUtils = {
     }
     return factory;
   },
 
   /**
    * Allows you to fake a relative import. Expects the global object from the
    * module that's calling us, and the relative filename that we wish to import.
    */
-  importRelative: function XPCOMUtils__importRelative(that, path) {
+  importRelative: function XPCOMUtils__importRelative(that, path, scope) {
     if (!("__URI__" in that))
       throw Error("importRelative may only be used from a JSM, and its first argument "+
                   "must be that JSM's global object (hint: use this)");
     let uri = that.__URI__;
     let i = uri.lastIndexOf("/");
-    Components.utils.import(uri.substring(0, i+1) + path, that);
+    Components.utils.import(uri.substring(0, i+1) + path, scope || that);
   },
 
   /**
    * generates a singleton nsIFactory implementation that can be used as
    * the _xpcom_factory of the component.
    * @param aServiceConstructor
    *        Constructor function of the component.
    */
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -13,17 +13,18 @@
 #include "mozilla/StaticPtr.h"
 
 using namespace mozilla::dom;
 using namespace JS;
 
 /***************************************************************************/
 // nsJSID
 
-NS_IMPL_ISUPPORTS1(nsJSID, nsIJSID)
+NS_IMPL_CLASSINFO(nsJSID, nullptr, 0, NS_JS_ID_CID)
+NS_IMPL_ISUPPORTS1_CI(nsJSID, nsIJSID)
 
 char nsJSID::gNoString[] = "";
 
 nsJSID::nsJSID()
     : mID(GetInvalidIID()), mNumber(gNoString), mName(gNoString)
 {
 }
 
--- a/js/xpconnect/tests/mochitest/test_bug790732.html
+++ b/js/xpconnect/tests/mochitest/test_bug790732.html
@@ -36,17 +36,16 @@ https://bugzilla.mozilla.org/show_bug.cg
   is(Ci.nsIDOMSimpleGestureEvent, SimpleGestureEvent);
   is(Ci.nsIDOMUIEvent, UIEvent);
   is(Ci.nsIDOMHTMLMediaElement, HTMLMediaElement);
   is(Ci.nsIDOMMediaError, MediaError);
   is(Ci.nsIDOMOfflineResourceList, OfflineResourceList);
   is(Ci.nsIDOMRange, Range);
   is(Ci.nsIDOMSVGLength, SVGLength);
   is(Ci.nsIDOMNodeFilter, NodeFilter);
-  is(Ci.nsIDOMXPathNamespace, XPathNamespace);
   is(Ci.nsIDOMXPathResult, XPathResult);
 
   // Test for Bug 895231
   for (var k of Object.keys(Components.interfaces)) {
     ok(SpecialPowers.Ci.hasOwnProperty(k),
        k + " should be removed from the Components shim");
   }
 
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_bug1001094.js
@@ -0,0 +1,4 @@
+function run_test() {
+  // Make sure nsJSID implements classinfo.
+  do_check_eq(Components.ID("{a6e2a27f-5521-4b35-8b52-99799a744aee}").equals, Components.ID("{daa47351-7d2e-44a7-b8e3-281802a1eab7}").equals);
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -36,16 +36,17 @@ support-files =
 [test_bug851895.js]
 [test_bug854558.js]
 [test_bug868675.js]
 [test_bug867486.js]
 [test_bug872772.js]
 [test_bug885800.js]
 [test_bug961054.js]
 [test_bug976151.js]
+[test_bug1001094.js]
 [test_bug_442086.js]
 [test_file.js]
 [test_blob.js]
 [test_blob2.js]
 [test_file2.js]
 [test_import.js]
 [test_import_fail.js]
 [test_js_weak_references.js]
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1407,16 +1407,20 @@ RestyleManager::DoRebuildAllStyleData(Re
 
 void
 RestyleManager::ProcessPendingRestyles()
 {
   NS_PRECONDITION(mPresContext->Document(), "No document?  Pshaw!");
   NS_PRECONDITION(!nsContentUtils::IsSafeToRunScript(),
                   "Missing a script blocker!");
 
+  // First do any queued-up frame creation.  (We should really
+  // merge this into the rest of the process, though; see bug 827239.)
+  mPresContext->FrameConstructor()->CreateNeededFrames();
+
   // Process non-animation restyles...
   NS_ABORT_IF_FALSE(!mPresContext->IsProcessingRestyles(),
                     "Nesting calls to ProcessPendingRestyles?");
   mPresContext->SetProcessingRestyles(true);
 
   // Before we process any restyles, we need to ensure that style
   // resulting from any throttled animations (animations that we're
   // running entirely on the compositor thread) is up-to-date, so that
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -24,17 +24,17 @@
 #include "nsISelectionController.h"
 #include "nsCaret.h"
 #include "nsTextFrame.h"
 #include "nsXULPopupManager.h"
 #include "nsMenuPopupFrame.h"
 #include "nsTextFragment.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include <algorithm>
 
 // The bidi indicator hangs off the caret to one side, to show which
 // direction the typing is in. It needs to be at least 2x2 to avoid looking like 
 // an insignificant dot
 static const int32_t kMinBidiIndicatorPixels = 2;
 
 #include "nsIBidiKeyboard.h"
@@ -1096,17 +1096,17 @@ void nsCaret::CaretBlinkCallback(nsITime
 //-----------------------------------------------------------------------------
 nsFrameSelection*
 nsCaret::GetFrameSelection()
 {
   nsCOMPtr<nsISelection> sel = do_QueryReferent(mDomSelectionWeak);
   if (!sel)
     return nullptr;
 
-  return static_cast<Selection*>(sel.get())->GetFrameSelection();
+  return static_cast<dom::Selection*>(sel.get())->GetFrameSelection();
 }
 
 void
 nsCaret::SetIgnoreUserModify(bool aIgnoreUserModify)
 {
   if (!aIgnoreUserModify && mIgnoreUserModify && mDrawn) {
     // We're turning off mIgnoreUserModify. If the caret's drawn
     // in a read-only node we must erase it, else the next call
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -90,21 +90,21 @@ class DocAccessible;
 #endif
 class nsIWidget;
 struct nsArenaMemoryStats;
 
 typedef short SelectionType;
 
 namespace mozilla {
 class EventStates;
-class Selection;
 
 namespace dom {
 class Element;
 class Touch;
+class Selection;
 class ShadowRoot;
 } // namespace dom
 
 namespace layers {
 class LayerManager;
 } // namespace layers
 
 namespace gfx {
@@ -770,17 +770,17 @@ public:
 
   /**
     * Gets the current state of non text selection effects
     * @return   current state of non text selection,
     *           as set by SetDisplayNonTextSelection
     */
   int16_t GetSelectionFlags() const { return mSelectionFlags; }
 
-  virtual mozilla::Selection* GetCurrentSelection(SelectionType aType) = 0;
+  virtual mozilla::dom::Selection* GetCurrentSelection(SelectionType aType) = 0;
 
   /**
     * Interface to dispatch events via the presshell
     * @note The caller must have a strong reference to the PresShell.
     */
   virtual NS_HIDDEN_(nsresult) HandleEventWithTarget(
                                  mozilla::WidgetEvent* aEvent,
                                  nsIFrame* aFrame,
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -57,17 +57,17 @@
 #include "nsView.h"
 #include "nsCRTGlue.h"
 #include "prprf.h"
 #include "prinrval.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 #include "nsContainerFrame.h"
 #include "nsISelection.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsGkAtoms.h"
 #include "nsIDOMRange.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMElement.h"
 #include "nsRange.h"
 #include "nsCOMPtr.h"
@@ -1847,17 +1847,16 @@ PresShell::Initialize(nscoord aWidth, ns
 
     // Constructors may have killed us too
     NS_ENSURE_STATE(!mHaveShutDown);
 
     // Now flush out pending restyles before we actually reflow, in
     // case XBL constructors changed styles somewhere.
     {
       nsAutoScriptBlocker scriptBlocker;
-      mFrameConstructor->CreateNeededFrames();
       mPresContext->RestyleManager()->ProcessPendingRestyles();
     }
 
     // And that might have run _more_ XBL constructors
     NS_ENSURE_STATE(!mHaveShutDown);
   }
 
   NS_ASSERTION(rootFrame, "How did that happen?");
@@ -1982,17 +1981,16 @@ PresShell::ResizeReflowIgnoreOverride(ns
   if (!GetPresContext()->SupressingResizeReflow()) {
     // Have to make sure that the content notifications are flushed before we
     // start messing with the frame model; otherwise we can get content doubling.
     mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
 
     // Make sure style is up to date
     {
       nsAutoScriptBlocker scriptBlocker;
-      mFrameConstructor->CreateNeededFrames();
       mPresContext->RestyleManager()->ProcessPendingRestyles();
     }
 
     rootFrame = mFrameConstructor->GetRootFrame();
     if (!mIsDestroying && rootFrame) {
       // XXX Do a full invalidate at the beginning so that invalidates along
       // the way don't have region accumulation issues?
 
@@ -4046,17 +4044,16 @@ PresShell::FlushPendingNotifications(moz
         mPresContext->TransitionManager()->
           FlushTransitions(CommonAnimationManager::Cannot_Throttle);
         mPresContext->TickLastStyleUpdateForAllAnimations();
       }
 
       // The FlushResampleRequests() above flushed style changes.
       if (!mIsDestroying) {
         nsAutoScriptBlocker scriptBlocker;
-        mFrameConstructor->CreateNeededFrames();
         mPresContext->RestyleManager()->ProcessPendingRestyles();
       }
     }
 
     // Dispatch any 'animationstart' events those (or earlier) restyles
     // queued up.
     if (!mIsDestroying) {
       mPresContext->AnimationManager()->DispatchEvents();
@@ -4073,17 +4070,16 @@ PresShell::FlushPendingNotifications(moz
     // events.  At the same time, we still need up-to-date style data.
     // In particular, reflow depends on style being completely up to
     // date.  If it's not, then style context reparenting, which can
     // happen during reflow, might suddenly pick up the new rules and
     // we'll end up with frames whose style doesn't match the frame
     // type.
     if (!mIsDestroying) {
       nsAutoScriptBlocker scriptBlocker;
-      mFrameConstructor->CreateNeededFrames();
       mPresContext->RestyleManager()->ProcessPendingRestyles();
     }
 
 
     // There might be more pending constructors now, but we're not going to
     // worry about them.  They can't be triggered during reflow, so we should
     // be good.
 
@@ -6715,17 +6711,17 @@ PresShell::HandleEvent(nsIFrame* aFrame,
       uint32_t flags = 0;
       if (aEvent->message == NS_TOUCH_START) {
         flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME;
         WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
         // if this is a continuing session, ensure that all these events are
         // in the same document by taking the target of the events already in
         // the capture list
         nsCOMPtr<nsIContent> anyTarget;
-        if (gCaptureTouchList->Count() > 0) {
+        if (gCaptureTouchList->Count() > 0 && touchEvent->touches.Length() > 1) {
           gCaptureTouchList->Enumerate(&FindAnyTarget, &anyTarget);
         } else {
           gPreventMouseEvents = false;
         }
 
         for (int32_t i = touchEvent->touches.Length(); i; ) {
           --i;
           dom::Touch* touch = touchEvent->touches[i];
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -71,17 +71,17 @@ public:
             nsViewManager* aViewManager, nsStyleSet* aStyleSet,
             nsCompatibility aCompatMode);
   virtual NS_HIDDEN_(void) Destroy() MOZ_OVERRIDE;
   virtual NS_HIDDEN_(void) MakeZombie() MOZ_OVERRIDE;
 
   virtual NS_HIDDEN_(nsresult) SetPreferenceStyleRules(bool aForceReflow) MOZ_OVERRIDE;
 
   NS_IMETHOD GetSelection(SelectionType aType, nsISelection** aSelection);
-  virtual mozilla::Selection* GetCurrentSelection(SelectionType aType) MOZ_OVERRIDE;
+  virtual mozilla::dom::Selection* GetCurrentSelection(SelectionType aType) MOZ_OVERRIDE;
 
   NS_IMETHOD SetDisplaySelection(int16_t aToggle) MOZ_OVERRIDE;
   NS_IMETHOD GetDisplaySelection(int16_t *aToggle) MOZ_OVERRIDE;
   NS_IMETHOD ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion,
                                      int16_t aFlags) MOZ_OVERRIDE;
   NS_IMETHOD RepaintSelection(SelectionType aType) MOZ_OVERRIDE;
 
   virtual NS_HIDDEN_(void) BeginObservingDocument() MOZ_OVERRIDE;
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -48,16 +48,17 @@ support-files =
   bug570378-persian-3-ref.html
   bug570378-persian-4.html
   bug570378-persian-4-ref.html
   bug570378-persian-5.html
   bug570378-persian-5-ref.html
 
 [test_preserve3d_sorting_hit_testing.html]
 [test_after_paint_pref.html]
+[test_bug993936.html]
 skip-if = e10s
 [test_border_radius_hit_testing.html]
 [test_bug66619.html]
 [test_bug93077-1.html]
 [test_bug93077-2.html]
 [test_bug93077-3.html]
 [test_bug93077-4.html]
 [test_bug93077-5.html]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug993936.html
@@ -0,0 +1,161 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=993936
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 993936</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 993936 **/
+
+var currentId = 0;
+var evictedTouchesCount = 0;
+
+function testtouch(aOptions) {
+  if (!aOptions)
+    aOptions = {};
+  this.identifier = aOptions.identifier || 0;
+  this.target = aOptions.target || 0;
+  this.page = aOptions.page || {x: 0, y: 0};
+  this.radius = aOptions.radius || {x: 0, y: 0};
+  this.rotationAngle = aOptions.rotationAngle || 0;
+  this.force = aOptions.force || 1;
+}
+
+function touchEvent(aOptions) {
+  if (!aOptions) {
+    aOptions = {};
+  }
+  this.ctrlKey = aOptions.ctrlKey || false;
+  this.altKey = aOptions.altKey || false;
+  this.shiftKey = aOptions.shiftKey || false;
+  this.metaKey = aOptions.metaKey || false;
+  this.touches = aOptions.touches || [];
+  this.targetTouches = aOptions.targetTouches || [];
+  this.changedTouches = aOptions.changedTouches || [];
+}
+
+function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
+  var ids = [], xs=[], ys=[], rxs = [], rys = [],
+      rotations = [], forces = [];
+
+  for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
+    for (var i = 0; i < aEvent[touchType].length; i++) {
+      if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
+        ids.push(aEvent[touchType][i].identifier);
+        xs.push(aEvent[touchType][i].page.x);
+        ys.push(aEvent[touchType][i].page.y);
+        rxs.push(aEvent[touchType][i].radius.x);
+        rys.push(aEvent[touchType][i].radius.y);
+        rotations.push(aEvent[touchType][i].rotationAngle);
+        forces.push(aEvent[touchType][i].force);
+      }
+    }
+  }
+  return windowUtils.sendTouchEvent(aType,
+                                    ids, xs, ys, rxs, rys,
+                                    rotations, forces,
+                                    ids.length, aModifiers, 0);
+}
+
+function getSingleTouchEventForTarget(target, cwu) {
+  currentId++;
+  var bcr = target.getBoundingClientRect();
+  var touch = new testtouch({
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target,
+    identifier: currentId,
+  });
+  var event = new touchEvent({
+    touches: [touch],
+    targetTouches: [touch],
+    changedTouches: [touch]
+  });
+  return event;
+}
+
+function getMultiTouchEventForTarget(target, cwu) {
+  currentId++;
+  var bcr = target.getBoundingClientRect();
+  var touch1 = new testtouch({
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target,
+    identifier: currentId,
+  });
+  currentId++;
+  var touch2 = new testtouch({
+    page: {x: Math.round(bcr.left + bcr.width),
+           y: Math.round(bcr.top  + bcr.height)},
+    target: target,
+    identifier: currentId,
+  });
+  var event = new touchEvent({
+    touches: [touch1, touch2],
+    targetTouches: [touch1, touch2],
+    changedTouches: [touch1, touch2]
+  });
+  return event;
+}
+
+function runTests() {
+  var cwu = SpecialPowers.getDOMWindowUtils(window);
+
+  var event1 = getMultiTouchEventForTarget(d0, cwu);
+  sendTouchEvent(cwu, "touchstart", event1, 0);
+  sendTouchEvent(cwu, "touchmove", event1, 0);
+  is(evictedTouchesCount, 0, "Still no evicted touches");
+
+  var event2 = getSingleTouchEventForTarget(d0, cwu);
+  sendTouchEvent(cwu, "touchstart", event2, 0);
+
+  // By now we should get touchend event
+  ok(evictedTouchesCount > 0, "Got evicted touch");
+
+  finishTest();
+}
+
+function finishTest() {
+  // Let window.onerror have a chance to fire
+  setTimeout(function() {
+    SimpleTest.finish();
+  }, 0);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=993936">Mozilla Bug 993936</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+<div id="d0">
+    Test div
+</div>
+
+<script>
+var d0 = document.getElementById("d0");
+
+d0.addEventListener("touchend", function(ev) {
+  evictedTouchesCount++;
+});
+
+window.onload = function () {
+  setTimeout(function() {
+    runTests();
+  }, 0);
+}
+
+</script>
+</body>
+</html>
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -35,17 +35,17 @@
 #include "nsIDOMNode.h"
 
 #include "nsIDOMText.h" //for multiline getselection
 #include "nsFocusManager.h"
 #include "nsTextEditRules.h"
 #include "nsPresState.h"
 #include "nsContentList.h"
 #include "nsAttrValueInlines.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsContentUtils.h"
 #include "nsTextNode.h"
 #include "nsStyleSet.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/MathAlgorithms.h"
 
 #define DEFAULT_COLUMN_WIDTH 20
 
@@ -1010,17 +1010,17 @@ nsTextControlFrame::GetSelectionRange(in
   NS_ASSERTION(txtCtrl, "Content not a text control element");
   nsISelectionController* selCon = txtCtrl->GetSelectionController();
   NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE);
   nsCOMPtr<nsISelection> selection;
   rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));  
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
 
-  Selection* sel = static_cast<Selection*>(selection.get());
+  dom::Selection* sel = static_cast<dom::Selection*>(selection.get());
   if (aDirection) {
     nsDirection direction = sel->GetSelectionDirection();
     if (direction == eDirNext) {
       *aDirection = eForward;
     } else if (direction == eDirPrevious) {
       *aDirection = eBackward;
     } else {
       NS_NOTREACHED("Invalid nsDirection enum value");
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -33,22 +33,23 @@ struct RangeData
   RangeData(nsRange* aRange)
     : mRange(aRange)
   {}
 
   nsRefPtr<nsRange> mRange;
   mozilla::TextRangeStyle mTextRangeStyle;
 };
 
-// Note, the ownership of mozilla::Selection depends on which way the object is
-// created. When nsFrameSelection has created Selection, addreffing/releasing
-// the Selection object is aggregated to nsFrameSelection. Otherwise normal
-// addref/release is used.  This ensures that nsFrameSelection is never deleted
-// before its Selections.
+// Note, the ownership of mozilla::dom::Selection depends on which way the
+// object is created. When nsFrameSelection has created Selection,
+// addreffing/releasing the Selection object is aggregated to nsFrameSelection.
+// Otherwise normal addref/release is used.  This ensures that nsFrameSelection
+// is never deleted before its Selections.
 namespace mozilla {
+namespace dom {
 
 class Selection : public nsISelectionPrivate,
                   public nsWrapperCache,
                   public nsSupportsWeakReference
 {
 public:
   Selection();
   Selection(nsFrameSelection *aList);
@@ -275,11 +276,12 @@ private:
   nsRefPtr<nsAutoScrollTimer> mAutoScrollTimer;
   nsCOMArray<nsISelectionListener> mSelectionListeners;
   nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;
   CachedOffsetForFrame *mCachedOffsetForFrame;
   nsDirection mDirection;
   SelectionType mType;
 };
 
+} // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_Selection_h__
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -29,17 +29,17 @@ EXPORTS += [
     'nsObjectFrame.h',
     'nsQueryFrame.h',
     'nsSubDocumentFrame.h',
     'ScrollbarActivity.h',
     'Selection.h',
     'WritingModes.h',
 ]
 
-EXPORTS.mozilla += [
+EXPORTS.mozilla.dom += [
     'Selection.h',
 ]
 
 EXPORTS.mozilla.layout += [
     'FrameChildList.h',
 ]
 
 UNIFIED_SOURCES += [
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFrameSelection_h___
 #define nsFrameSelection_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "mozilla/TextRange.h"
 #include "nsIFrame.h"
 #include "nsIContent.h"
 #include "nsISelectionController.h"
 #include "nsITableCellLayout.h"
 #include "nsIDOMElement.h"
 #include "nsRange.h"
 
@@ -169,18 +169,20 @@ struct nsPrevNextBidiLevels
   }
   nsIFrame* mFrameBefore;
   nsIFrame* mFrameAfter;
   uint8_t mLevelBefore;
   uint8_t mLevelAfter;
 };
 
 namespace mozilla {
+namespace dom {
 class Selection;
 }
+}
 class nsIScrollableFrame;
 
 /**
  * Methods which are marked with *unsafe* should be handled with special care.
  * They may cause nsFrameSelection to be deleted, if strong pointer isn't used,
  * or they may cause other objects to be deleted.
  */
 
@@ -348,17 +350,17 @@ public:
    */
   bool GetTableCellSelection() const { return mSelectingTableCellMode != 0; }
   void ClearTableCellSelection() { mSelectingTableCellMode = 0; }
 
   /** GetSelection
    * no query interface for selection. must use this method now.
    * @param aSelectionType enum value defined in nsISelection for the seleciton you want.
    */
-  mozilla::Selection* GetSelection(SelectionType aType) const;
+  mozilla::dom::Selection* GetSelection(SelectionType aType) const;
 
   /**
    * ScrollSelectionIntoView scrolls a region of the selection,
    * so that it is visible in the scrolled view.
    *
    * @param aType the selection to scroll into view.
    * @param aRegion the region inside the selection to scroll into view.
    * @param aFlags the scroll flags.  Valid bits include:
@@ -614,17 +616,17 @@ private:
   void    PostReason(int16_t aReason) { mSelectionChangeReason = aReason; }
   int16_t PopReason()
   {
     int16_t retval = mSelectionChangeReason;
     mSelectionChangeReason = 0;
     return retval;
   }
 
-  friend class mozilla::Selection;
+  friend class mozilla::dom::Selection;
 #ifdef DEBUG
   void printSelection();       // for debugging
 #endif /* DEBUG */
 
   void ResizeBuffer(uint32_t aNewBufSize);
 /*HELPER METHODS*/
   nsresult     MoveCaret(uint32_t aKeycode, bool aContinueSelection,
                          nsSelectionAmount aAmount);
@@ -641,17 +643,17 @@ private:
   uint32_t     GetBatching() const {return mBatching; }
   bool         GetNotifyFrames() const { return mNotifyFrames; }
   void         SetDirty(bool aDirty=true){if (mBatching) mChangesDuringBatching = aDirty;}
 
   // nsFrameSelection may get deleted when calling this,
   // so remember to use nsCOMPtr when needed.
   nsresult     NotifySelectionListeners(SelectionType aType);     // add parameters to say collapsed etc?
 
-  nsRefPtr<mozilla::Selection> mDomSelections[nsISelectionController::NUM_SELECTIONTYPES];
+  nsRefPtr<mozilla::dom::Selection> mDomSelections[nsISelectionController::NUM_SELECTIONTYPES];
 
   // Table selection support.
   nsITableCellLayout* GetCellLayout(nsIContent *aCellContent) const;
 
   nsresult SelectBlockOfCells(nsIContent *aStartNode, nsIContent *aEndNode);
   nsresult SelectRowOrColumn(nsIContent *aCellContent, uint32_t aTarget);
   nsresult UnselectCells(nsIContent *aTable,
                          int32_t aStartRowIndex, int32_t aStartColumnIndex,
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -3,17 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
  * Implementation of selection: nsISelection,nsISelectionPrivate and nsFrameSelection
  */
 
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventStates.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsFrameSelection.h"
 #include "nsISelectionListener.h"
@@ -73,16 +73,17 @@ static NS_DEFINE_CID(kFrameTraversalCID,
 
 #include "nsError.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ShadowRoot.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/SelectionBinding.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 //#define DEBUG_TABLE 1
 
 static bool IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsINode *aNode);
 
 static nsIAtom *GetTag(nsINode *aNode);
 // returns the parent
 static nsINode* ParentOffset(nsINode *aNode, int32_t *aChildOffset);
@@ -2967,17 +2968,17 @@ nsFrameSelection::DeleteFromDocument()
     return NS_ERROR_NULL_POINTER;
 
   mDomSelections[index]->GetIsCollapsed( &isCollapsed);
   if (isCollapsed)
   {
     return NS_OK;
   }
 
-  nsRefPtr<mozilla::Selection> selection = mDomSelections[index];
+  nsRefPtr<Selection> selection = mDomSelections[index];
   for (int32_t rangeIdx = 0; rangeIdx < selection->GetRangeCount(); ++rangeIdx) {
     nsRefPtr<nsRange> range = selection->GetRangeAt(rangeIdx);
     res = range->DeleteContents();
     if (NS_FAILED(res))
       return res;
   }
 
   // Collapse to the new location.
@@ -3018,17 +3019,17 @@ nsFrameSelection::DisconnectFromPresShel
 }
 
 //END nsISelection interface implementations
 
 #if 0
 #pragma mark -
 #endif
 
-// mozilla::Selection implementation
+// mozilla::dom::Selection implementation
 
 // note: this can return a nil anchor node
 
 Selection::Selection()
   : mCachedOffsetForFrame(nullptr)
   , mDirection(eDirNext)
   , mType(nsISelectionController::SELECTION_NORMAL)
 {
--- a/layout/mathml/mathml.css
+++ b/layout/mathml/mathml.css
@@ -191,52 +191,18 @@ mtable[frame="dashed"] > mtr > mtd:first
   -moz-padding-start: 0.4em; /* framespacing.left (or right in rtl)*/
 }
 mtable[frame="solid"] > mtr > mtd:last-child,
 mtable[frame="dashed"] > mtr > mtd:last-child {
   -moz-padding-end: 0.4em; /* framespacing.right (or left in rtl)*/
 }
 
 /**************************************************************************/
-/* Style used for stretchy symbols *must* be normal to avoid misaligments */
-/* By leaving the font-family empty, the MathML engine will use the value
-   provided by the mathfont-family property in the mathfont.properties file
-   or the value of the user's pref("font.mathfont-family", "...").
-
-   Authors can make elements on a document to be stretched with different
-   fonts, e.g.,
-
-   To request the use of STIX fonts, you can add a <style>...</style> with:
-   <mo myfonts="stix">...</mo> with the associated CSS declaration
-   mo[myfonts="stix"]::-moz-math-stretchy {
-     font-family: STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral;
-   }
-
-   To request the use of Asana fonts, you can add a <style>...</style> with:
-   <mo myfonts="asana">...</mo> with the associated CSS declaration
-   mo[myfonts="asana"]::-moz-math-stretchy {
-     font-family: Asana Math;
-   }
-
-   Of course, if you just want all of the stretchy characters in your
-   document to be stretched with your preferred list, you can just do:
-   ::-moz-math-stretchy {
-     font-family: [your-particular-list]
-   }
-
-   Note that like other fonts in the document, users can override this by
-   clicking the pref to override document fonts.
-/**************************************************************************/
-
-::-moz-math-stretchy {
-  font-style: normal;
-  font-family: serif; /* an empty family is ignored as an error and behaves like inherit */
-/*  background-color: #3C6; */
-}
-/* Don't actually style -moz-math-anonymous by default */
+/* This rule is used to give a style context suitable for nsMathMLChars.
+   We don't actually style -moz-math-anonymous by default. */
 /*
 ::-moz-math-anonymous {
 }
 */
 
 /**********************************************************************/
 /* This is used when wrapping non-MathML inline elements inside math. */
 *|*::-moz-mathml-anonymous-block {
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -74,21 +74,19 @@ nsMathMLFrame::UpdatePresentationData(ui
 // Helper to give a style context suitable for doing the stretching of
 // a MathMLChar. Frame classes that use this should ensure that the 
 // extra leaf style contexts given to the MathMLChars are accessible to
 // the Style System via the Get/Set AdditionalStyleContext() APIs.
 /* static */ void
 nsMathMLFrame::ResolveMathMLCharStyle(nsPresContext*  aPresContext,
                                       nsIContent*      aContent,
                                       nsStyleContext*  aParentStyleContext,
-                                      nsMathMLChar*    aMathMLChar,
-                                      bool             aIsMutableChar)
+                                      nsMathMLChar*    aMathMLChar)
 {
-  nsCSSPseudoElements::Type pseudoType = (aIsMutableChar) ?
-    nsCSSPseudoElements::ePseudo_mozMathStretchy :
+  nsCSSPseudoElements::Type pseudoType =
     nsCSSPseudoElements::ePseudo_mozMathAnonymous; // savings
   nsRefPtr<nsStyleContext> newStyleContext;
   newStyleContext = aPresContext->StyleSet()->
     ResolvePseudoElementStyle(aContent->AsElement(), pseudoType,
                               aParentStyleContext, nullptr);
 
   aMathMLChar->SetStyleContext(newStyleContext);
 }
--- a/layout/mathml/nsMathMLFrame.h
+++ b/layout/mathml/nsMathMLFrame.h
@@ -106,18 +106,17 @@ public:
 
   // helper to give a style context suitable for doing the stretching to the
   // MathMLChar. Frame classes that use this should make the extra style contexts
   // accessible to the Style System via Get/Set AdditionalStyleContext.
   static void
   ResolveMathMLCharStyle(nsPresContext*  aPresContext,
                          nsIContent*      aContent,
                          nsStyleContext*  aParenStyleContext,
-                         nsMathMLChar*    aMathMLChar,
-                         bool             aIsMutableChar);
+                         nsMathMLChar*    aMathMLChar);
 
   // helper to get the mEmbellishData of a frame
   // The MathML REC precisely defines an "embellished operator" as:
   // - an <mo> element;
   // - or one of the elements <msub>, <msup>, <msubsup>, <munder>, <mover>,
   //   <munderover>, <mmultiscripts>, <mfrac>, or <semantics>, whose first 
   //   argument exists and is an embellished operator;
   //- or one of the elements <mstyle>, <mphantom>, or <mpadded>, such that
--- a/layout/mathml/nsMathMLOperators.cpp
+++ b/layout/mathml/nsMathMLOperators.cpp
@@ -423,35 +423,16 @@ nsMathMLOperators::LookupOperators(const
     if (found) {
       aFlags[NS_MATHML_OPERATOR_FORM_PREFIX] = found->mFlags;
       aLeadingSpace[NS_MATHML_OPERATOR_FORM_PREFIX] = found->mLeadingSpace;
       aTrailingSpace[NS_MATHML_OPERATOR_FORM_PREFIX] = found->mTrailingSpace;
     }
   }
 }
 
-bool
-nsMathMLOperators::IsMutableOperator(const nsString& aOperator)
-{
-  if (!gGlobalsInitialized) {
-    InitGlobals();
-  }
-  // lookup all the variants of the operator and return true if there
-  // is a variant that is stretchy or largeop
-  nsOperatorFlags flags[4];
-  float lspace[4], rspace[4];
-  nsMathMLOperators::LookupOperators(aOperator, flags, lspace, rspace);
-  nsOperatorFlags allFlags =
-    flags[NS_MATHML_OPERATOR_FORM_INFIX] |
-    flags[NS_MATHML_OPERATOR_FORM_POSTFIX] |
-    flags[NS_MATHML_OPERATOR_FORM_PREFIX];
-  return NS_MATHML_OPERATOR_IS_STRETCHY(allFlags) ||
-         NS_MATHML_OPERATOR_IS_LARGEOP(allFlags);
-}
-
 /* static */ bool
 nsMathMLOperators::IsMirrorableOperator(const nsString& aOperator)
 {
   // LookupOperator will search infix, postfix and prefix forms of aOperator and
   // return the first form found. It is assumed that all these forms have same
   // mirrorability.
   nsOperatorFlags flags = 0;
   float dummy;
--- a/layout/mathml/nsMathMLOperators.h
+++ b/layout/mathml/nsMathMLOperators.h
@@ -87,21 +87,16 @@ public:
    // particular form. If the operator wasn't found under a form, its entry
    // aFlags[form] is set to zero.
    static void
    LookupOperators(const nsString&       aOperator,
                    nsOperatorFlags*      aFlags,
                    float*                aLeadingSpace,
                    float*                aTrailingSpace);
 
-  // IsMutableOperator:
-  // Return true if the operator exists and is stretchy or largeop
-  static bool
-  IsMutableOperator(const nsString& aOperator);
-
   // Helper functions used by the nsMathMLChar class.
   static bool
   IsMirrorableOperator(const nsString& aOperator);
 
   // Helper function used by the nsMathMLChar class.
   static nsStretchDirection GetStretchyDirection(const nsString& aOperator);
 };
 
--- a/layout/mathml/nsMathMLmencloseFrame.cpp
+++ b/layout/mathml/nsMathMLmencloseFrame.cpp
@@ -67,19 +67,17 @@ nsresult nsMathMLmencloseFrame::Allocate
     mLongDivCharIndex = i;
   } else if (mask == NOTATION_RADICAL) {
     Char.Assign(kRadicalChar);
     mRadicalCharIndex = i;
   }
 
   nsPresContext *presContext = PresContext();
   mMathMLChar[i].SetData(presContext, Char);
-  ResolveMathMLCharStyle(presContext, mContent, mStyleContext,
-                         &mMathMLChar[i],
-                         true);
+  ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar[i]);
 
   return NS_OK;
 }
 
 /*
  * Add a notation to draw, if the argument is the name of a known notation.
  * @param aNotation string name of a notation
  */
--- a/layout/mathml/nsMathMLmfencedFrame.cpp
+++ b/layout/mathml/nsMathMLmfencedFrame.cpp
@@ -92,46 +92,43 @@ nsMathMLmfencedFrame::RemoveFencesAndSep
   mSeparatorsChar = nullptr;
   mSeparatorsCount = 0;
 }
 
 void
 nsMathMLmfencedFrame::CreateFencesAndSeparators(nsPresContext* aPresContext)
 {
   nsAutoString value;
-  bool isMutable = false;
 
   //////////////  
   // see if the opening fence is there ...
   if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::open, value)) {
     value = char16_t('('); // default as per the MathML REC
   } else {
     value.CompressWhitespace();
   }
 
   if (!value.IsEmpty()) {
     mOpenChar = new nsMathMLChar;
     mOpenChar->SetData(aPresContext, value);
-    isMutable = nsMathMLOperators::IsMutableOperator(value);
-    ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar, isMutable);
+    ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mOpenChar);
   }
 
   //////////////
   // see if the closing fence is there ...
   if(!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::close, value)) {
     value = char16_t(')'); // default as per the MathML REC
   } else {
     value.CompressWhitespace();
   }
 
   if (!value.IsEmpty()) {
     mCloseChar = new nsMathMLChar;
     mCloseChar->SetData(aPresContext, value);
-    isMutable = nsMathMLOperators::IsMutableOperator(value);
-    ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar, isMutable);
+    ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, mCloseChar);
   }
 
   //////////////
   // see if separators are there ...
   if (!mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::separators_, value)) {
     value = char16_t(','); // default as per the MathML REC
   } else {
     value.StripWhitespace();
@@ -141,24 +138,22 @@ nsMathMLmfencedFrame::CreateFencesAndSep
   if (0 < mSeparatorsCount) {
     int32_t sepCount = mFrames.GetLength() - 1;
     if (0 < sepCount) {
       mSeparatorsChar = new nsMathMLChar[sepCount];
       nsAutoString sepChar;
       for (int32_t i = 0; i < sepCount; i++) {
         if (i < mSeparatorsCount) {
           sepChar = value[i];
-          isMutable = nsMathMLOperators::IsMutableOperator(sepChar);
         }
         else {
           sepChar = value[mSeparatorsCount-1];
-          // keep the value of isMutable that was set earlier
         }
         mSeparatorsChar[i].SetData(aPresContext, sepChar);
-        ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i], isMutable);
+        ResolveMathMLCharStyle(aPresContext, mContent, mStyleContext, &mSeparatorsChar[i]);
       }
       mSeparatorsCount = sepCount;
     } else {
       // No separators.  Note that sepCount can be -1 here, so don't
       // set mSeparatorsCount to it.
       mSeparatorsCount = 0;
     }
   }
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -131,17 +131,17 @@ nsMathMLmoFrame::ProcessTextData()
     mFlags |= NS_MATHML_OPERATOR_INVISIBLE;
   }
 
   // don't bother doing anything special if we don't have a single child
   nsPresContext* presContext = PresContext();
   if (mFrames.GetLength() != 1) {
     data.Truncate(); // empty data to reset the char
     mMathMLChar.SetData(presContext, data);
-    ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar, false);
+    ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar);
     return;
   }
 
   // special... in math mode, the usual minus sign '-' looks too short, so
   // what we do here is to remap <mo>-</mo> to the official Unicode minus
   // sign (U+2212) which looks much better. For background on this, see
   // http://groups.google.com/groups?hl=en&th=66488daf1ade7635&rnum=1
   if (1 == length && ch == '-') {
@@ -187,17 +187,17 @@ nsMathMLmoFrame::ProcessTextData()
   mEmbellishData.direction = mMathMLChar.GetStretchDirection();
 
   bool isMutable =
     NS_MATHML_OPERATOR_IS_LARGEOP(allFlags) ||
     (mEmbellishData.direction != NS_STRETCH_DIRECTION_UNSUPPORTED);
   if (isMutable)
     mFlags |= NS_MATHML_OPERATOR_MUTABLE;
 
-  ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar, isMutable);
+  ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mMathMLChar);
 }
 
 // get our 'form' and lookup in the Operator Dictionary to fetch 
 // our default data that may come from there. Then complete our setup
 // using attributes that we may have. To stay in sync, this function is
 // called very often. We depend on many things that may change around us.
 // However, we re-use unchanged values.
 void
--- a/layout/mathml/nsMathMLmrootFrame.cpp
+++ b/layout/mathml/nsMathMLmrootFrame.cpp
@@ -54,17 +54,17 @@ nsMathMLmrootFrame::Init(nsIContent*    
   
   nsPresContext *presContext = PresContext();
 
   // No need to track the style context given to our MathML char. 
   // The Style System will use Get/SetAdditionalStyleContext() to keep it
   // up-to-date if dynamic changes arise.
   nsAutoString sqrChar; sqrChar.Assign(kSqrChar);
   mSqrChar.SetData(presContext, sqrChar);
-  ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mSqrChar, true);
+  ResolveMathMLCharStyle(presContext, mContent, mStyleContext, &mSqrChar);
 }
 
 NS_IMETHODIMP
 nsMathMLmrootFrame::TransmitAutomaticData()
 {
   // 1. The REC says:
   //    The <mroot> element increments scriptlevel by 2, and sets displaystyle to
   //    "false", within index, but leaves both attributes unchanged within base.
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -5,17 +5,17 @@
 
 #include "nsPrintEngine.h"
 
 #include "nsIStringBundle.h"
 #include "nsReadableUtils.h"
 #include "nsCRT.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
-#include "mozilla/Selection.h"
+#include "mozilla/dom/Selection.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsIFrame.h"
 #include "nsIURI.h"
 #include "nsITextToSubURI.h"
 #include "nsError.h"
 
--- a/layout/reftests/mathml/opentype-stretchy-ref.html
+++ b/layout/reftests/mathml/opentype-stretchy-ref.html
@@ -7,20 +7,16 @@
       @font-face {
         font-family: stretchy;
         src: url(../fonts/math/stretchy.otf);
       }
       math {
         font-family: stretchy;
         font-size: 10px;
       }
-      ::-moz-math-stretchy {
-        font-family: stretchy;
-        font-size: 10px;
-      }
     </style>
   </head>
   <body>
 
 <!--
 hstretchy = [
     0x219C, # leftwards wave arrow
     0x219D, # rightwards wave arrow
--- a/layout/reftests/mathml/opentype-stretchy.html
+++ b/layout/reftests/mathml/opentype-stretchy.html
@@ -7,20 +7,16 @@
       @font-face {
         font-family: stretchy;
         src: url(../fonts/math/stretchy.otf);
       }
       math {
         font-family: stretchy;
         font-size: 10px;
       }
-      ::-moz-math-stretchy {
-        font-family: stretchy;
-        font-size: 10px;
-      }
     </style>
   </head>
   <body>
 
 <!--
 hstretchy = [
     0x219C, # leftwards wave arrow
     0x219D, # rightwards wave arrow
--- a/layout/reftests/mathml/reftest.list
+++ b/layout/reftests/mathml/reftest.list
@@ -30,17 +30,17 @@ skip-if(B2G) fails-if(smallScreen&&Andro
 == mfenced-5a.xhtml mfenced-5-ref.xhtml
 == mfenced-5b.xhtml mfenced-5-ref.xhtml
 == mfenced-5c.xhtml mfenced-5-ref.xhtml
 == mfenced-5d.xhtml mfenced-5-ref.xhtml
 == mfenced-6.html mfenced-6-ref.html
 == mfenced-7.html mfenced-7-ref.html
 != mfenced-8.html mfenced-8-ref.html
 == mfenced-9.html mfenced-9-ref.html
-fails-if(winWidget) == mfenced-10.html mfenced-10-ref.html
+== mfenced-10.html mfenced-10-ref.html
 == mi-mathvariant-1.xhtml mi-mathvariant-1-ref.xhtml
 == mi-mathvariant-2.xhtml mi-mathvariant-2-ref.xhtml
 != non-spacing-accent-1.xhtml non-spacing-accent-1-ref.xhtml
 == overbar-width-1.xhtml overbar-width-1-ref.xhtml
 skip-if(B2G) == quotes-1.xhtml quotes-1-ref.xhtml
 != stretchy-underbar-1.xhtml stretchy-underbar-1-ref.xhtml 
 == table-width-1.xhtml table-width-1-ref.xhtml
 == table-width-2.html table-width-2-ref.html
@@ -63,17 +63,17 @@ skip-if(B2G) == quotes-1.xhtml quotes-1-
 != embellished-op-3-3.html embellished-op-3-3-ref.html
 != embellished-op-3-4.html embellished-op-3-4-ref.html
 != embellished-op-3-5.html embellished-op-3-5-ref.html
 == embellished-op-4-1.html embellished-op-4-1-ref.html
 == embellished-op-4-2.html embellished-op-4-2-ref.html
 == embellished-op-4-3.html embellished-op-4-3-ref.html
 == embellished-op-5-1.html embellished-op-5-ref.html
 == embellished-op-5-2.html embellished-op-5-ref.html
-== semantics-1.xhtml semantics-1-ref.xhtml
+fails-if(winWidget&&!/^Windows\x20NT\x205\.1/.test(http.oscpu)) == semantics-1.xhtml semantics-1-ref.xhtml # Windows versions with Cambria Math
 == semantics-2.html semantics-2-ref.html
 == semantics-3.html semantics-3-ref.html
 != mathcolor-1.xml mathcolor-1-ref.xml
 != mathcolor-2.xml mathcolor-2-ref.xml
 != mathcolor-3.xml mathcolor-3-ref.xml
 == mathcolor-4.xml mathcolor-4-ref.xml
 != mathbackground-1.xml mathbackground-1-ref.xml
 != mathbackground-2.xml mathbackground-2-ref.xml
@@ -177,17 +177,17 @@ fails-if(B2G) == multiscripts-1.html mul
 != menclose-1p.html menclose-1-ref.html
 fails-if(B2G) == menclose-2-actuarial.html menclose-2-actuarial-ref.html # B2G slight thickness variation
 == menclose-2-bottom.html menclose-2-bottom-ref.html
 fails-if(B2G) == menclose-2-box.html menclose-2-box-ref.html # B2G slight thickness variation
 == menclose-2-circle.html menclose-2-circle-ref.html
 == menclose-2-downdiagonalstrike.html menclose-2-downdiagonalstrike-ref.html
 == menclose-2-horizontalstrike.html menclose-2-horizontalstrike-ref.html
 fails-if(B2G) == menclose-2-left.html menclose-2-left-ref.html # B2G slight thickness variation
-== menclose-2-longdiv.html menclose-2-longdiv-ref.html
+fails-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == menclose-2-longdiv.html menclose-2-longdiv-ref.html # Windows versions without Cambria Math
 == menclose-2-right.html menclose-2-right-ref.html
 fails-if(B2G) == menclose-2-roundedbox.html menclose-2-roundedbox-ref.html # B2G slight thickness variation
 fails-if(B2G) == menclose-2-top.html menclose-2-top-ref.html # B2G slight thickness variation
 fails-if(B2G) == menclose-2-updiagonalarrow.html menclose-2-updiagonalarrow-ref.html # B2G slight thickness variation
 == menclose-2-updiagonalstrike.html menclose-2-updiagonalstrike-ref.html
 == menclose-2-verticalstrike.html menclose-2-verticalstrike-ref.html
 fails-if(B2G) == menclose-2-roundedbox.html menclose-2-roundedbox-ref.html # B2G slight thickness variation
 == menclose-3-box.html menclose-3-box-ref.html
--- a/layout/style/nsCSSPseudoElementList.h
+++ b/layout/style/nsCSSPseudoElementList.h
@@ -43,17 +43,16 @@ CSS_PSEUDO_ELEMENT(mozSelection, ":-moz-
 CSS_PSEUDO_ELEMENT(mozFocusInner, ":-moz-focus-inner", 0)
 CSS_PSEUDO_ELEMENT(mozFocusOuter, ":-moz-focus-outer", 0)
 
 // XXXbz should we really allow random content to style these?  Maybe
 // use our flags to prevent that?
 CSS_PSEUDO_ELEMENT(mozListBullet, ":-moz-list-bullet", 0)
 CSS_PSEUDO_ELEMENT(mozListNumber, ":-moz-list-number", 0)
 
-CSS_PSEUDO_ELEMENT(mozMathStretchy, ":-moz-math-stretchy", 0)
 CSS_PSEUDO_ELEMENT(mozMathAnonymous, ":-moz-math-anonymous", 0)
 
 // HTML5 Forms pseudo elements
 CSS_PSEUDO_ELEMENT(mozNumberWrapper, ":-moz-number-wrapper",
                    CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE |
                    CSS_PSEUDO_ELEMENT_IS_CHROME_ONLY)
 CSS_PSEUDO_ELEMENT(mozNumberText, ":-moz-number-text",
                    CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE |
--- a/layout/tools/reftest/reftest-preferences.js
+++ b/layout/tools/reftest/reftest-preferences.js
@@ -24,18 +24,16 @@
     branch.setIntPref("urlclassifier.updateinterval", 172800);
     // Disable high-quality downscaling, since it makes reftests more difficult.
     branch.setBoolPref("image.high_quality_downscaling.enabled", false);
     // Checking whether two files are the same is slow on Windows.
     // Setting this pref makes tests run much faster there.
     branch.setBoolPref("security.fileuri.strict_origin_policy", false);
     // Disable the thumbnailing service
     branch.setBoolPref("browser.pagethumbnails.capturing_disabled", true);
-    // Enable APZC so we can test it
-    branch.setBoolPref("layers.async-pan-zoom.enabled", true);
     // Since our tests are 800px wide, set the assume-designed-for width of all
     // pages to be 800px (instead of the default of 980px). This ensures that
     // in our 800px window we don't zoom out by default to try to fit the
     // assumed 980px content.
     branch.setIntPref("browser.viewport.desktopWidth", 800);
     // Disable the fade out (over time) of overlay scrollbars, since we
     // can't guarantee taking both reftest snapshots at the same point
     // during the fade.
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -2090,16 +2090,22 @@ ClearReports()
   if (!gIsDMDRunning) {
     return;
   }
 
   AutoLockState lock;
   ClearReportsInternal();
 }
 
+MOZ_EXPORT bool
+IsEnabled()
+{
+  return gIsDMDRunning;
+}
+
 MOZ_EXPORT void
 Dump(Writer aWriter)
 {
   if (!gIsDMDRunning) {
     const char* msg = "cannot Dump();  DMD was not enabled at startup\n";
     StatusMsg("%s", msg);
     W("%s", msg);
     return;
--- a/memory/replace/dmd/DMD.h
+++ b/memory/replace/dmd/DMD.h
@@ -73,12 +73,16 @@ struct Sizes
   void Clear() { memset(this, 0, sizeof(Sizes)); }
 };
 
 // Gets the size of various data structures.  Used to implement a memory
 // reporter for DMD.
 MOZ_EXPORT void
 SizeOf(Sizes* aSizes);
 
+// Indicates whether or not DMD is enabled.
+MOZ_EXPORT bool
+IsEnabled();
+
 } // namespace mozilla
 } // namespace dmd
 
 #endif /* DMD_h___ */
--- a/mfbt/Assertions.h
+++ b/mfbt/Assertions.h
@@ -7,16 +7,17 @@
 /* Implementations of runtime and static assertion macros for C and C++. */
 
 #ifndef mozilla_Assertions_h
 #define mozilla_Assertions_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/Likely.h"
+#include "mozilla/MacroArgs.h"
 
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #ifdef WIN32
    /*
     * TerminateProcess and GetCurrentProcess are defined in <winbase.h>, which
     * further depends on <windef.h>.  We hardcode these few definitions manually
@@ -290,40 +291,23 @@ MOZ_ReportCrash(const char* s, const cha
 /* Now the two-argument form. */
 #define MOZ_ASSERT_HELPER2(expr, explain) \
    do { \
      if (MOZ_UNLIKELY(!(expr))) { \
        MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \
        MOZ_REALLY_CRASH(); \
      } \
    } while (0)
-/* And now, helper macrology up the wazoo. */
-/*
- * Count the number of arguments passed to MOZ_ASSERT, very carefully
- * tiptoeing around an MSVC bug where it improperly expands __VA_ARGS__ as a
- * single token in argument lists.  See these URLs for details:
- *
- *   http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
- *   http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
- */
-#define MOZ_COUNT_ASSERT_ARGS_IMPL2(_1, _2, count, ...) \
-   count
-#define MOZ_COUNT_ASSERT_ARGS_IMPL(args) \
-       MOZ_COUNT_ASSERT_ARGS_IMPL2 args
-#define MOZ_COUNT_ASSERT_ARGS(...) \
-   MOZ_COUNT_ASSERT_ARGS_IMPL((__VA_ARGS__, 2, 1, 0))
-/* Pick the right helper macro to invoke. */
-#define MOZ_ASSERT_CHOOSE_HELPER2(count) MOZ_ASSERT_HELPER##count
-#define MOZ_ASSERT_CHOOSE_HELPER1(count) MOZ_ASSERT_CHOOSE_HELPER2(count)
-#define MOZ_ASSERT_CHOOSE_HELPER(count) MOZ_ASSERT_CHOOSE_HELPER1(count)
-/* The actual macros. */
-#define MOZ_ASSERT_GLUE(x, y) x y
+
+#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b
 #define MOZ_RELEASE_ASSERT(...) \
-   MOZ_ASSERT_GLUE(MOZ_ASSERT_CHOOSE_HELPER(MOZ_COUNT_ASSERT_ARGS(__VA_ARGS__)), \
-                   (__VA_ARGS__))
+   MOZ_RELEASE_ASSERT_GLUE( \
+     MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \
+     (__VA_ARGS__))
+
 #ifdef DEBUG
 #  define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__)
 #else
 #  define MOZ_ASSERT(...) do { } while(0)
 #endif /* DEBUG */
 
 /*
  * MOZ_ASSERT_IF(cond1, cond2) is equivalent to MOZ_ASSERT(cond2) if cond1 is
new file mode 100644
--- /dev/null
+++ b/mfbt/MacroArgs.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Implements various macros meant to ease the use of variadic macros.
+ */
+
+#ifndef mozilla_MacroArgs_h
+#define mozilla_MacroArgs_h
+
+/*
+ * MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) counts the number of variadic
+ * arguments and prefixes it with |aPrefix|. For example:
+ *
+ *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(, foo, 42) expands to 2
+ *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(A, foo, 42, bar) expands to A3
+ *
+ * You must pass in between 1 and 50 (inclusive) variadic arguments, past
+ * |aPrefix|. It is not legal to do
+ *
+ *   MOZ_PASTE_PREFIX_AND_ARG_COUNT(prefix)
+ *
+ * (that is, pass in 0 variadic arguments). To ensure that a compile-time
+ * error occurs when these constraints are violated, use the
+ * MOZ_STATIC_ASSERT_VALID_ARG_COUNT macro with the same variaidc arguments
+ * wherever this macro is used.
+ *
+ * Passing (__VA_ARGS__, <rest of arguments>) rather than simply calling
+ * MOZ_MACROARGS_ARG_COUNT_HELPER2(__VA_ARGS__, <rest of arguments>) very
+ * carefully tiptoes around a MSVC bug where it improperly expands __VA_ARGS__
+ * as a single token in argument lists. For details, see:
+ *
+ *   http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
+ *   http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/#comment-644
+ */
+#define MOZ_PASTE_PREFIX_AND_ARG_COUNT(aPrefix, ...) \
+  MOZ_MACROARGS_ARG_COUNT_HELPER((__VA_ARGS__, \
+    aPrefix##50, aPrefix##49, aPrefix##48, aPrefix##47, aPrefix##46, \
+    aPrefix##45, aPrefix##44, aPrefix##43, aPrefix##42, aPrefix##41, \
+    aPrefix##40, aPrefix##39, aPrefix##38, aPrefix##37, aPrefix##36, \
+    aPrefix##35, aPrefix##34, aPrefix##33, aPrefix##32, aPrefix##31, \
+    aPrefix##30, aPrefix##29, aPrefix##28, aPrefix##27, aPrefix##26, \
+    aPrefix##25, aPrefix##24, aPrefix##23, aPrefix##22, aPrefix##21, \
+    aPrefix##20, aPrefix##19, aPrefix##18, aPrefix##17, aPrefix##16, \
+    aPrefix##15, aPrefix##14, aPrefix##13, aPrefix##12, aPrefix##11, \
+    aPrefix##10, aPrefix##9,  aPrefix##8,  aPrefix##7,  aPrefix##6,  \
+    aPrefix##5,  aPrefix##4,  aPrefix##3,  aPrefix##2,  aPrefix##1, aPrefix##0))
+
+#define MOZ_MACROARGS_ARG_COUNT_HELPER(aArgs) \
+  MOZ_MACROARGS_ARG_COUNT_HELPER2 aArgs
+
+#define MOZ_MACROARGS_ARG_COUNT_HELPER2( \
+   a1,  a2,  a3,  a4,  a5,  a6,  a7,  a8,  a9, a10, \
+  a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \
+  a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, \
+  a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, \
+  a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, \
+  a51, ...) a51
+
+/*
+ * MOZ_STATIC_ASSERT_VALID_ARG_COUNT ensures that a compile-time error occurs
+ * when the argument count constraints of MOZ_PASTE_PREFIX_AND_ARG_COUNT are
+ * violated. Use this macro wherever MOZ_PASTE_PREFIX_AND_ARG_COUNT is used
+ * and pass it the same variadic arguments.
+ *
+ * This macro employs a few dirty tricks to function. To detect the zero
+ * argument case, |(__VA_ARGS__)| is stringified, sizeof-ed, and compared to
+ * what it should be in the absence of arguments.
+ *
+ * Detecting too many arguments is a little trickier. With a valid argument
+ * count and a prefix of 1, MOZ_PASTE_PREFIX_AND_ARG_COUNT expands to e.g. 14.
+ * With a prefix of 0.0, it expands to e.g. 0.04. If there are too many
+ * arguments, it expands to the first argument over the limit. If this
+ * exceeding argument is a number, the assertion will fail as there is no
+ * number than can simultaneously be both > 10 and < 0.1. If the exceeding
+ * argument is not a number, a compile-time error will still occur because the
+ * exceeding argument is compared to an int and a double.
+ */
+#define MOZ_MACROARGS_STRINGIFY_HELPER(x) #x
+#define MOZ_STATIC_ASSERT_VALID_ARG_COUNT(...) \
+  static_assert( \
+    sizeof(MOZ_MACROARGS_STRINGIFY_HELPER((__VA_ARGS__))) != sizeof("()") && \
+      MOZ_PASTE_PREFIX_AND_ARG_COUNT(1, __VA_ARGS__) > 10 && \
+      MOZ_PASTE_PREFIX_AND_ARG_COUNT(0.0, __VA_ARGS__) < 0.1, \
+    "MOZ_STATIC_ASSERT_VALID_ARG_COUNT requires 1 to 50 arguments") /* ; */
+
+/*
+ * MOZ_ARGS_AFTER_N expands to its arguments excluding the first |N|
+ * arguments. For example:
+ *
+ *   MOZ_ARGS_AFTER_2(a, b, c, d) expands to: c, d
+ */
+#define MOZ_ARGS_AFTER_1(a1, ...) __VA_ARGS__
+#define MOZ_ARGS_AFTER_2(a1, a2, ...) __VA_ARGS__
+
+/*
+ * MOZ_ARG_N expands to its |N|th argument.
+ */
+#define MOZ_ARG_1(a1, ...) a1
+#define MOZ_ARG_2(a1, a2, ...) a2
+
+#endif /* mozilla_MacroArgs_h */
new file mode 100644
--- /dev/null
+++ b/mfbt/MacroForEach.h
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+/*
+ * Implements a higher-order macro for iteratively calling another macro with
+ * fixed leading arguments, plus a trailing element picked from a second list
+ * of arguments.
+ */
+
+#ifndef mozilla_MacroForEach_h
+#define mozilla_MacroForEach_h
+
+#include "mozilla/MacroArgs.h"
+
+/*
+ * MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) expands to N calls to the macro
+ * |aMacro| where N is equal the number of items in the list |aArgs|. The
+ * arguments for each |aMacro| call are composed of *all* arguments in the list
+ * |aFixedArgs| as well as a single argument in the list |aArgs|. For example:
+ *
+ *   #define MACRO_A(x) x +
+ *   int a = MOZ_FOR_EACH(MACRO_A, (), (1, 2, 3)) 0;
+ *   // Expands to:     MACRO_A(1) MACRO_A(2) MACRO_A(3) 0;
+ *   // And further to: 1 + 2 + 3 + 0;
+ *
+ *   #define MACRO_B(k, x) (k + x) +
+ *   int b = MOZ_FOR_EACH(MACRO_B, (5,), (1, 2)) 0;
+ *   // Expands to: MACRO_B(5, 1) MACRO_B(5, 2) 0;
+ *
+ *   #define MACRO_C(k1, k2, x) (k1 + k2 + x) +
+ *   int c = MOZ_FOR_EACH(MACRO_C, (5, 8,), (1, 2)) 0;
+ *   // Expands to: MACRO_B(5, 8, 1) MACRO_B(5, 8, 2) 0;
+ *
+ * If the |aFixedArgs| list is not empty, a trailing comma must be included.
+ *
+ * The |aArgs| list must be not be empty and may be up to 50 items long. Use
+ * MOZ_STATIC_ASSERT_VALID_ARG_COUNT to ensure that violating this constraint
+ * results in a compile-time error.
+ */
+#define MOZ_FOR_EACH_EXPAND_HELPER(...) __VA_ARGS__
+#define MOZ_FOR_EACH_GLUE(a, b) a b
+#define MOZ_FOR_EACH(aMacro, aFixedArgs, aArgs) \
+  MOZ_FOR_EACH_GLUE( \
+    MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_FOR_EACH_, \
+                                   MOZ_FOR_EACH_EXPAND_HELPER aArgs), \
+    (aMacro, aFixedArgs, aArgs))
+
+#define MOZ_FOR_EACH_HELPER_GLUE(a, b) a b
+#define MOZ_FOR_EACH_HELPER(aMacro, aFixedArgs, aArgs) \
+  MOZ_FOR_EACH_HELPER_GLUE( \
+    aMacro, \
+    (MOZ_FOR_EACH_EXPAND_HELPER aFixedArgs MOZ_ARG_1 aArgs))
+
+#define MOZ_FOR_EACH_1(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a)
+#define MOZ_FOR_EACH_2(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_1(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_3(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_2(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_4(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_3(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_5(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_4(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_6(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_5(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_7(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_6(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_8(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_7(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_9(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_8(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_10(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_9(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_11(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_10(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_12(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_11(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_13(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_12(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_14(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_13(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_15(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_14(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_16(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_15(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_17(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_16(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_18(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_17(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_19(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_18(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_20(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_19(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_21(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_20(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_22(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_21(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_23(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_22(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_24(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_23(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_25(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_24(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_26(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_25(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_27(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_26(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_28(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_27(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_29(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_28(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_30(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_29(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_31(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_30(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_32(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_31(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_33(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_32(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_34(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_33(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_35(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_34(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_36(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_35(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_37(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_36(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_38(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_37(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_39(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_38(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_40(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_39(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_41(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_40(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_42(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_41(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_43(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_42(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_44(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_43(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_45(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_44(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_46(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_45(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_47(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_46(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_48(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_47(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_49(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_48(m, fa, (MOZ_ARGS_AFTER_1 a))
+#define MOZ_FOR_EACH_50(m, fa, a) \
+  MOZ_FOR_EACH_HELPER(m, fa, a) MOZ_FOR_EACH_49(m, fa, (MOZ_ARGS_AFTER_1 a))
+
+#endif /* mozilla_MacroForEach_h */
--- a/mfbt/TypedEnum.h
+++ b/mfbt/TypedEnum.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* Macros to emulate C++11 typed enums and enum classes. */
 
 #ifndef mozilla_TypedEnum_h
 #define mozilla_TypedEnum_h
 
 #include "mozilla/Attributes.h"
+#include "mozilla/MacroArgs.h"
 
 #if defined(__cplusplus)
 
 #if defined(__clang__)
    /*
     * Per Clang documentation, "Note that marketing version numbers should not
     * be used to check for language features, as different vendors use different
     * numbering schemes. Instead, use the feature checking macros."
@@ -285,43 +286,22 @@
    * as T depends on template parameters (more specifically here, T _is_ a