Merge m-c to fx-team.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 16 Apr 2014 22:53:31 -0400
changeset 179400 ccc9cd25ebda0454adaf5b870ba446ebbd51597d
parent 179399 a80a58607a35e2c7e892a276bb0dff81ab88d082 (current diff)
parent 179345 e71ed4135461b57a9c7f35995e4e1f1dc5f0e8bf (diff)
child 179401 0423a8e32248166ad5a23daef7a93f5dbe1c3e8c
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
Merge m-c to fx-team.
dom/icc/interfaces/nsIDOMIccManager.idl
rdf/base/idl/xulstubs.idl
--- a/accessible/src/base/TextRange.cpp
+++ b/accessible/src/base/TextRange.cpp
@@ -18,8 +18,20 @@ TextRange::TextRange(HyperTextAccessible
 {
 }
 
 void
 TextRange::Text(nsAString& aText) const
 {
 
 }
+
+void
+TextRange::Set(HyperTextAccessible* aRoot,
+               Accessible* aStartContainer, int32_t aStartOffset,
+               Accessible* aEndContainer, int32_t aEndOffset)
+{
+  mRoot = aRoot;
+  mStartContainer = aStartContainer;
+  mEndContainer = aEndContainer;
+  mStartOffset = aStartOffset;
+  mEndOffset = aEndOffset;
+}
--- a/accessible/src/base/TextRange.h
+++ b/accessible/src/base/TextRange.h
@@ -26,38 +26,53 @@ public:
             Accessible* aStartContainer, int32_t aStartOffset,
             Accessible* aEndContainer, int32_t aEndOffset);
   TextRange() {}
   TextRange(TextRange&& aRange) :
     mRoot(Move(aRange.mRoot)), mStartContainer(Move(aRange.mStartContainer)),
     mEndContainer(Move(aRange.mEndContainer)),
     mStartOffset(aRange.mStartOffset), mEndOffset(aRange.mEndOffset) {}
 
+  TextRange& operator= (TextRange&& aRange)
+  {
+    mRoot = Move(aRange.mRoot);
+    mStartContainer = Move(aRange.mStartContainer);
+    mEndContainer = Move(aRange.mEndContainer);
+    mStartOffset = aRange.mStartOffset;
+    mEndOffset = aRange.mEndOffset;
+    return *this;
+  }
+
   Accessible* StartContainer() const { return mStartContainer; }
   int32_t StartOffset() const { return mStartOffset; }
   Accessible* EndContainer() const { return mEndContainer; }
   int32_t EndOffset() const { return mEndOffset; }
 
   /**
    * Return text enclosed by the range.
    */
   void Text(nsAString& aText) const;
 
   /**
    * Return true if this TextRange object represents an actual range of text.
    */
   bool IsValid() const { return mRoot; }
 
 private:
+  TextRange(const TextRange& aRange) MOZ_DELETE;
+  TextRange& operator=(const TextRange& aRange) MOZ_DELETE;
+
   friend class HyperTextAccessible;
+  friend class xpcAccessibleTextRange;
 
-  TextRange(const TextRange&) MOZ_DELETE;
-  TextRange& operator=(const TextRange&) MOZ_DELETE;
+  void Set(HyperTextAccessible* aRoot,
+           Accessible* aStartContainer, int32_t aStartOffset,
+           Accessible* aEndContainer, int32_t aEndOffset);
 
-  const nsRefPtr<HyperTextAccessible> mRoot;
+  nsRefPtr<HyperTextAccessible> mRoot;
   nsRefPtr<Accessible> mStartContainer;
   nsRefPtr<Accessible> mEndContainer;
   int32_t mStartOffset;
   int32_t mEndOffset;
 };
 
 
 } // namespace a11y
--- a/accessible/src/generic/HyperTextAccessible.cpp
+++ b/accessible/src/generic/HyperTextAccessible.cpp
@@ -1503,38 +1503,76 @@ HyperTextAccessible::ScrollSubstringToPo
     }
     frame = parentFrame;
   }
 }
 
 void
 HyperTextAccessible::EnclosingRange(a11y::TextRange& aRange) const
 {
+  if (IsTextField()) {
+    aRange.Set(mDoc, const_cast<HyperTextAccessible*>(this), 0,
+               const_cast<HyperTextAccessible*>(this), ChildCount());
+  } else {
+    aRange.Set(mDoc, mDoc, 0, mDoc, mDoc->ChildCount());
+  }
 }
 
 void
 HyperTextAccessible::SelectionRanges(nsTArray<a11y::TextRange>* aRanges) const
 {
+  NS_ASSERTION(aRanges->Length() != 0, "TextRange array supposed to be empty");
+
+  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 =
+      nsAccUtils::GetTextContainer(DOMRange->GetStartParent());
+    HyperTextAccessible* endParent =
+      nsAccUtils::GetTextContainer(DOMRange->GetEndParent());
+    if (!startParent || !endParent)
+      continue;
+
+    int32_t startOffset =
+      startParent->DOMPointToOffset(DOMRange->GetStartParent(),
+                                    DOMRange->StartOffset(), false);
+    int32_t endOffset =
+      endParent->DOMPointToOffset(DOMRange->GetEndParent(),
+                                  DOMRange->EndOffset(), true);
+
+    TextRange tr(IsTextField() ? const_cast<HyperTextAccessible*>(this) : mDoc,
+                    startParent, startOffset, endParent, endOffset);
+    *(aRanges->AppendElement()) = Move(tr);
+  }
 }
 
 void
 HyperTextAccessible::VisibleRanges(nsTArray<a11y::TextRange>* aRanges) const
 {
 }
 
 void
 HyperTextAccessible::RangeByChild(Accessible* aChild,
                                   a11y::TextRange& aRange) const
 {
+  aRange.Set(mDoc, aChild, 0, aChild, aChild->ChildCount());
 }
 
 void
 HyperTextAccessible::RangeAtPoint(int32_t aX, int32_t aY,
                                   a11y::TextRange& aRange) const
 {
+  Accessible* child = mDoc->ChildAtPoint(aX, aY, eDeepestChild);
+  if (child)
+    aRange.Set(mDoc, child, 0, child, child->ChildCount());
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Accessible public
 
 // Accessible protected
 ENameValueFlag
 HyperTextAccessible::NativeName(nsString& aName)
--- a/accessible/src/xpcom/xpcAccessibleTextRange.cpp
+++ b/accessible/src/xpcom/xpcAccessibleTextRange.cpp
@@ -7,42 +7,54 @@
 #include "xpcAccessibleTextRange.h"
 
 #include "HyperTextAccessible.h"
 #include "TextRange.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
-// nsISupports
-NS_IMPL_ISUPPORTS1(xpcAccessibleTextRange, nsIAccessibleTextRange)
+// nsISupports and cycle collection
+
+NS_IMPL_CYCLE_COLLECTION_3(xpcAccessibleTextRange,
+                           mRange.mRoot,
+                           mRange.mStartContainer,
+                           mRange.mEndContainer)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(xpcAccessibleTextRange)
+  NS_INTERFACE_MAP_ENTRY(nsIAccessibleTextRange)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessibleTextRange)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(xpcAccessibleTextRange)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(xpcAccessibleTextRange)
 
 // nsIAccessibleTextRange
 
 NS_IMETHODIMP
 xpcAccessibleTextRange::GetStartContainer(nsIAccessible** aAnchor)
 {
   NS_ENSURE_ARG_POINTER(aAnchor);
-  *aAnchor = static_cast<nsIAccessible*>(mRange.StartContainer());
+  NS_IF_ADDREF(*aAnchor = static_cast<nsIAccessible*>(mRange.StartContainer()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibleTextRange::GetStartOffset(int32_t* aOffset)
 {
   NS_ENSURE_ARG_POINTER(aOffset);
   *aOffset = mRange.StartOffset();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibleTextRange::GetEndContainer(nsIAccessible** aAnchor)
 {
   NS_ENSURE_ARG_POINTER(aAnchor);
-  *aAnchor = static_cast<nsIAccessible*>(mRange.EndContainer());
+  NS_IF_ADDREF(*aAnchor = static_cast<nsIAccessible*>(mRange.EndContainer()));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 xpcAccessibleTextRange::GetEndOffset(int32_t* aOffset)
 {
   NS_ENSURE_ARG_POINTER(aOffset);
   *aOffset = mRange.EndOffset();
--- a/accessible/src/xpcom/xpcAccessibleTextRange.h
+++ b/accessible/src/xpcom/xpcAccessibleTextRange.h
@@ -6,26 +6,28 @@
 
 #ifndef mozilla_a11y_xpcAccessibleTextRange_h_
 #define mozilla_a11y_xpcAccessibleTextRange_h_
 
 #include "nsIAccessibleTextRange.h"
 #include "TextRange.h"
 
 #include "mozilla/Move.h"
+#include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 namespace a11y {
 
 class TextRange;
 
 class xpcAccessibleTextRange MOZ_FINAL : public nsIAccessibleTextRange
 {
 public:
-  NS_DECL_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS(xpcAccessibleTextRange)
 
   NS_IMETHOD GetStartContainer(nsIAccessible** aAnchor) MOZ_FINAL MOZ_OVERRIDE;
   NS_IMETHOD GetStartOffset(int32_t* aOffset) MOZ_FINAL MOZ_OVERRIDE;
   NS_IMETHOD GetEndContainer(nsIAccessible** aAnchor) MOZ_FINAL MOZ_OVERRIDE;
   NS_IMETHOD GetEndOffset(int32_t* aOffset) MOZ_FINAL MOZ_OVERRIDE;
   NS_IMETHOD GetText(nsAString& aText) MOZ_FINAL MOZ_OVERRIDE;
 
 private:
--- a/accessible/tests/mochitest/moz.build
+++ b/accessible/tests/mochitest/moz.build
@@ -29,10 +29,11 @@ DIRS += [
     'textselection',
     'treeupdate',
     'value',
 ]
 
 A11Y_MANIFESTS += [
     'a11y.ini',
     'events/a11y.ini',
+    'textrange/a11y.ini',
     'tree/a11y.ini',
 ]
--- a/accessible/tests/mochitest/text.js
+++ b/accessible/tests/mochitest/text.js
@@ -452,16 +452,29 @@ function testTextGetSelection(aID, aStar
   acc.getSelectionBounds(aSelectionIndex, startObj, endObj);
 
   is(startObj.value, aStartOffset, text + ": wrong start offset for index '" +
      aSelectionIndex + "'");
   is(endObj.value, aEndOffset, text + ": wrong end offset for index '" +
      aSelectionIndex + "'");
 }
 
+function testTextRange(aRange, aStartContainer, aStartOffset,
+                       aEndContainer, aEndOffset)
+{
+  is(aRange.startContainer, getAccessible(aStartContainer),
+     "Wrong start container");
+  is(aRange.startOffset, aStartOffset,
+     "Wrong start offset");
+  is(aRange.endContainer, getAccessible(aEndContainer),
+     "Wrong end container");
+  is(aRange.endOffset, aEndOffset,
+     "Wrong end offset");
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Private
 
 function testTextSuperHelper(aFuncName, aArgs)
 {
   // List of tests.
   if (aArgs[2] instanceof Array) {
     var ids = (aArgs[0] instanceof Array) ? aArgs[0] : [ aArgs[0] ];
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/textrange/a11y.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_general.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/textrange/test_general.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Text Range tests</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../text.js"></script>
+  <script type="application/javascript">
+
+    function doTest()
+    {
+      var input = getAccessible("input", [ nsIAccessibleText ]);
+      testTextRange(input.enclosingRange, input, 0, input, 1);
+
+      var ta = getAccessible("textarea", [ nsIAccessibleText ]);
+      testTextRange(ta.enclosingRange, ta, 0, ta, 1);
+
+      var iframeDoc = getAccessible(getNode("iframe").contentDocument,
+                                    [ nsIAccessibleText ]);
+      testTextRange(iframeDoc.enclosingRange, iframeDoc, 0, iframeDoc, 1);
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     title="Implement Text accessible text range methods"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=975065">Bug 975065</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <input id="input" value="hello">
+  <textarea id="textarea">hello</textarea>
+  <iframe id="iframe" src="data:text/html,<p>hello</p>"></iframe>
+
+</body>
+</html>
--- 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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="52c909ccead537f8f9dbf634f3e6639078a8b0bd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="55bcc2d7e44dc805c24b57d1e783fc26e8a2ee86"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="99a67a75855d8ca077018c819aedd90bf0447d9b"/>
   <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/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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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,28 +115,28 @@
   <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="c2c115bec6f5e9bc1daf7bb74bb4d14861c00b9c"/>
   <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="92f9b79e3a5ecf24cb0f66e20d5292b300f8cac9"/>
-  <project name="kernel/msm" path="kernel" revision="ecf7fb3e0178b28a61c4cccc9073ea111e5522ef"/>
+  <project name="kernel/msm" path="kernel" revision="39ca56deb6c4419c0220a762f6e340091032390d"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="f2914eacee9120680a41463708bb6ee8291749fc"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="c53977638eb8a7091f752d870e8e0f00f7a23d95"/>
   <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"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="33a2b51f78416536e1bfba0c0b7776db307f3a4f"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="484802559ed106bac4811bd01c024ca64f741e60"/>
-  <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="2ff71f0d6af6ae6a15b1c9eaa89f1e4c883115bb"/>
+  <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="d30227d7ae5cbe8bac8775358b472f44504a20d2"/>
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="81afa7f775b7559da52f468150d1fe090c3fbdc5"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="e38444b6ce12c7c25883272a439800376d5308eb"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="13312a5577db9261cb0fcee9ccbc58cdb5e6bc55"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="8b7736c56fa9a3fd8b4341eb243e12eec847efed"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "f1f04d6c6f247e9a83960903e2f15774f07ca579", 
+    "revision": "e1fc74c2ae523e7cce5be01e1a29b43defaec124", 
     "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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="37d029e584d79aeaca8d30474c394eddcdfade03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="7591e9dc782ac2e97d63a96f9deb71c7b3588328"/>
   <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/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -39,16 +39,17 @@ SEARCH_PATHS = [
     'dom/bindings',
     'dom/bindings/parser',
     'other-licenses/ply',
     'xpcom/idl-parser',
     'testing',
     'testing/xpcshell',
     'testing/marionette/client',
     'testing/marionette/client/marionette',
+    'testing/marionette/transport',
     'testing/mozbase/mozcrash',
     'testing/mozbase/mozdevice',
     'testing/mozbase/mozfile',
     'testing/mozbase/mozhttpd',
     'testing/mozbase/mozlog',
     'testing/mozbase/moznetwork',
     'testing/mozbase/mozprocess',
     'testing/mozbase/mozprofile',
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -1,8 +1,9 @@
+marionette_transport.pth:testing/marionette/transport
 marionette.pth:testing/marionette/client
 blessings.pth:python/blessings
 configobj.pth:python/configobj
 jsmin.pth:python/jsmin
 mach.pth:python/mach
 mozbuild.pth:python/mozbuild
 pymake.pth:build/pymake
 optional:setup.py:python/psutil:build_ext:--inplace
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1322,16 +1322,24 @@ public:
   static bool IsSystemPrincipal(nsIPrincipal* aPrincipal);
 
   /**
    * Returns true if aPrincipal is an nsExpandedPrincipal.
    */
   static bool IsExpandedPrincipal(nsIPrincipal* aPrincipal);
 
   /**
+   * Returns true if aPrincipal is the system or an nsExpandedPrincipal.
+   */
+  static bool IsSystemOrExpandedPrincipal(nsIPrincipal* aPrincipal)
+  {
+    return IsSystemPrincipal(aPrincipal) || IsExpandedPrincipal(aPrincipal);
+  }
+
+  /**
    * Gets the system principal from the security manager.
    */
   static nsIPrincipal* GetSystemPrincipal();
 
   /**
    * *aResourcePrincipal is a principal describing who may access the contents
    * of a resource. The resource can only be consumed by a principal that
    * subsumes *aResourcePrincipal. MAKE SURE THAT NOTHING EVER ACTS WITH THE
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -953,59 +953,56 @@ nsFrameMessageManager::ReceiveMessage(ns
         JS_ClearPendingException(cx);
         return NS_OK;
       }
       JS::Rooted<JSString*> jsMessage(cx,
         JS_NewUCStringCopyN(cx,
                             static_cast<const jschar*>(aMessage.BeginReading()),
                             aMessage.Length()));
       NS_ENSURE_TRUE(jsMessage, NS_ERROR_OUT_OF_MEMORY);
-      JS_DefineProperty(cx, param, "target", targetv, nullptr, nullptr, JSPROP_ENUMERATE);
-      JS_DefineProperty(cx, param, "name",
-                        STRING_TO_JSVAL(jsMessage), nullptr, nullptr, JSPROP_ENUMERATE);
-      JS_DefineProperty(cx, param, "sync",
-                        BOOLEAN_TO_JSVAL(aIsSync), nullptr, nullptr, JSPROP_ENUMERATE);
-      JS_DefineProperty(cx, param, "json", json, nullptr, nullptr, JSPROP_ENUMERATE); // deprecated
-      JS_DefineProperty(cx, param, "data", json, nullptr, nullptr, JSPROP_ENUMERATE);
-      JS_DefineProperty(cx, param, "objects", cpowsv, nullptr, nullptr, JSPROP_ENUMERATE);
+      JS::Rooted<JS::Value> syncv(cx, JS::BooleanValue(aIsSync));
+      JS_DefineProperty(cx, param, "target", targetv, JSPROP_ENUMERATE);
+      JS_DefineProperty(cx, param, "name", jsMessage, JSPROP_ENUMERATE);
+      JS_DefineProperty(cx, param, "sync", syncv, JSPROP_ENUMERATE);
+      JS_DefineProperty(cx, param, "json", json, JSPROP_ENUMERATE); // deprecated
+      JS_DefineProperty(cx, param, "data", json, JSPROP_ENUMERATE);
+      JS_DefineProperty(cx, param, "objects", cpowsv, JSPROP_ENUMERATE);
 
       // message.principal == null
       if (!aPrincipal) {
-        JS::Rooted<JS::Value> nullValue(cx);
-        JS_DefineProperty(cx, param, "principal", nullValue, nullptr, nullptr, JSPROP_ENUMERATE);
+        JS_DefineProperty(cx, param, "principal", JS::UndefinedHandleValue, JSPROP_ENUMERATE);
       }
 
       // message.principal = { appId: <id>, origin: <origin>, isInBrowserElement: <something> }
       else {
         JS::Rooted<JSObject*> principalObj(cx,
           JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
 
         uint32_t appId;
         nsresult rv = aPrincipal->GetAppId(&appId);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        JS::Rooted<JS::Value> appIdValue(cx, INT_TO_JSVAL(appId));
-        JS_DefineProperty(cx, principalObj, "appId", appIdValue, nullptr, nullptr, JSPROP_ENUMERATE);
+        JS_DefineProperty(cx, principalObj, "appId", appId, JSPROP_ENUMERATE);
 
         nsCString origin;
         rv = aPrincipal->GetOrigin(getter_Copies(origin));
         NS_ENSURE_SUCCESS(rv, rv);
 
-        JS::Rooted<JSString*> originValue(cx, JS_NewStringCopyN(cx, origin.get(), origin.Length()));
-        JS_DefineProperty(cx, principalObj, "origin", STRING_TO_JSVAL(originValue), nullptr, nullptr, JSPROP_ENUMERATE);
+        JS::Rooted<JSString*> originStr(cx, JS_NewStringCopyN(cx, origin.get(), origin.Length()));
+        NS_ENSURE_TRUE(originStr, NS_ERROR_OUT_OF_MEMORY);
+        JS_DefineProperty(cx, principalObj, "origin", originStr, JSPROP_ENUMERATE);
 
         bool browser;
         rv = aPrincipal->GetIsInBrowserElement(&browser);
         NS_ENSURE_SUCCESS(rv, rv);
 
-        JS::Rooted<JS::Value> browserValue(cx, BOOLEAN_TO_JSVAL(browser));
-        JS_DefineProperty(cx, principalObj, "isInBrowserElement", browserValue, nullptr, nullptr, JSPROP_ENUMERATE);
+        JS::Rooted<JS::Value> browserValue(cx, JS::BooleanValue(browser));
+        JS_DefineProperty(cx, principalObj, "isInBrowserElement", browserValue, JSPROP_ENUMERATE);
 
-        JS::Rooted<JS::Value> principalValue(cx, JS::ObjectValue(*principalObj));
-        JS_DefineProperty(cx, param, "principal", principalValue, nullptr, nullptr, JSPROP_ENUMERATE);
+        JS_DefineProperty(cx, param, "principal", principalObj, JSPROP_ENUMERATE);
       }
 
       JS::Rooted<JS::Value> thisValue(cx, JS::UndefinedValue());
 
       JS::Rooted<JS::Value> funval(cx);
       if (JS_ObjectIsCallable(cx, object)) {
         // If the listener is a JS function:
         funval.setObject(*object);
@@ -1358,39 +1355,32 @@ nsFrameScriptExecutor::DidCreateGlobal()
 
     nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner =
       new nsScriptCacheCleaner();
     scriptCacheCleaner.forget(&sScriptCacheCleaner);
   }
 }
 
 static PLDHashOperator
-CachedScriptUnrooter(const nsAString& aKey,
-                     nsFrameScriptObjectExecutorHolder*& aData,
-                     void* aUserArg)
+RemoveCachedScriptEntry(const nsAString& aKey,
+                        nsFrameScriptObjectExecutorHolder*& aData,
+                        void* aUserArg)
 {
-  JSContext* cx = static_cast<JSContext*>(aUserArg);
-  if (aData->mScript) {
-    JS_RemoveScriptRoot(cx, &aData->mScript);
-  }
-  if (aData->mFunction) {
-    JS_RemoveObjectRoot(cx, &aData->mFunction);
-  }
   delete aData;
   return PL_DHASH_REMOVE;
 }
 
 // static
 void
 nsFrameScriptExecutor::Shutdown()
 {
   if (sCachedScripts) {
     AutoSafeJSContext cx;
     NS_ASSERTION(sCachedScripts != nullptr, "Need cached scripts");
-    sCachedScripts->Enumerate(CachedScriptUnrooter, cx);
+    sCachedScripts->Enumerate(RemoveCachedScriptEntry, nullptr);
 
     delete sCachedScripts;
     sCachedScripts = nullptr;
 
     nsRefPtr<nsScriptCacheCleaner> scriptCacheCleaner;
     scriptCacheCleaner.swap(sScriptCacheCleaner);
   }
 }
@@ -1523,23 +1513,19 @@ nsFrameScriptExecutor::TryCacheLoadAndCo
       nsAutoCString scheme;
       uri->GetScheme(scheme);
       // We don't cache data: scripts!
       if (aShouldCache && !scheme.EqualsLiteral("data")) {
         nsFrameScriptObjectExecutorHolder* holder;
 
         // Root the object also for caching.
         if (script) {
-          holder = new nsFrameScriptObjectExecutorHolder(script);
-          JS_AddNamedScriptRoot(cx, &holder->mScript,
-                                "Cached message manager script");
+          holder = new nsFrameScriptObjectExecutorHolder(cx, script);
         } else {
-          holder = new nsFrameScriptObjectExecutorHolder(funobj);
-          JS_AddNamedObjectRoot(cx, &holder->mFunction,
-                                "Cached message manager function");
+          holder = new nsFrameScriptObjectExecutorHolder(cx, funobj);
         }
         sCachedScripts->Put(aURL, holder);
       }
     }
   }
 }
 
 void
@@ -1917,44 +1903,34 @@ nsFrameMessageManager::MarkForCC()
 
 nsSameProcessAsyncMessageBase::nsSameProcessAsyncMessageBase(JSContext* aCx,
                                                              const nsAString& aMessage,
                                                              const StructuredCloneData& aData,
                                                              JS::Handle<JSObject*> aCpows,
                                                              nsIPrincipal* aPrincipal)
   : mRuntime(js::GetRuntime(aCx)),
     mMessage(aMessage),
-    mCpows(aCpows),
+    mCpows(aCx, aCpows),
     mPrincipal(aPrincipal)
 {
   if (aData.mDataLength && !mData.copy(aData.mData, aData.mDataLength)) {
     NS_RUNTIMEABORT("OOM");
   }
-  if (mCpows && !js_AddObjectRoot(mRuntime, &mCpows)) {
-    NS_RUNTIMEABORT("OOM");
-  }
   mClosure = aData.mClosure;
 }
 
-nsSameProcessAsyncMessageBase::~nsSameProcessAsyncMessageBase()
-{
-  if (mCpows) {
-    JS_RemoveObjectRootRT(mRuntime, &mCpows);
-  }
-}
-
 void
 nsSameProcessAsyncMessageBase::ReceiveMessage(nsISupports* aTarget,
                                               nsFrameMessageManager* aManager)
 {
   if (aManager) {
     StructuredCloneData data;
     data.mData = mData.data();
     data.mDataLength = mData.nbytes();
     data.mClosure = mClosure;
 
-    SameProcessCpowHolder cpows(mRuntime, JS::Handle<JSObject*>::fromMarkedLocation(&mCpows));
+    SameProcessCpowHolder cpows(mRuntime, mCpows);
 
     nsRefPtr<nsFrameMessageManager> mm = aManager;
     mm->ReceiveMessage(aTarget, mMessage, false, &data, &cpows,
                        mPrincipal, nullptr);
   }
 }
--- a/content/base/src/nsFrameMessageManager.h
+++ b/content/base/src/nsFrameMessageManager.h
@@ -332,48 +332,49 @@ class nsSameProcessAsyncMessageBase
 public:
   typedef mozilla::dom::StructuredCloneData StructuredCloneData;
 
   nsSameProcessAsyncMessageBase(JSContext* aCx,
                                 const nsAString& aMessage,
                                 const StructuredCloneData& aData,
                                 JS::Handle<JSObject*> aCpows,
                                 nsIPrincipal* aPrincipal);
-  ~nsSameProcessAsyncMessageBase();
 
   void ReceiveMessage(nsISupports* aTarget, nsFrameMessageManager* aManager);
 
 private:
   nsSameProcessAsyncMessageBase(const nsSameProcessAsyncMessageBase&);
 
   JSRuntime* mRuntime;
   nsString mMessage;
   JSAutoStructuredCloneBuffer mData;
   StructuredCloneClosure mClosure;
-  JSObject* mCpows;
+  JS::PersistentRooted<JSObject*> mCpows;
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
 
 class nsScriptCacheCleaner;
 
 struct nsFrameScriptObjectExecutorHolder
 {
-  nsFrameScriptObjectExecutorHolder(JSScript* aScript) : mScript(aScript), mFunction(nullptr)
+  nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSScript* aScript)
+   : mScript(aCx, aScript), mFunction(aCx, nullptr)
   { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
-  nsFrameScriptObjectExecutorHolder(JSObject* aFunction) : mScript(nullptr), mFunction(aFunction)
+
+  nsFrameScriptObjectExecutorHolder(JSContext* aCx, JSObject* aFunction)
+   : mScript(aCx, nullptr), mFunction(aCx, aFunction)
   { MOZ_COUNT_CTOR(nsFrameScriptObjectExecutorHolder); }
+
   ~nsFrameScriptObjectExecutorHolder()
   { MOZ_COUNT_DTOR(nsFrameScriptObjectExecutorHolder); }
 
   bool WillRunInGlobalScope() { return mScript; }
 
-  // We use JS_AddNamed{Script,Object}Root to root these fields explicitly, so
-  // no need for Heap<T>.
-  JSScript* mScript;
-  JSObject* mFunction;
+  JS::PersistentRooted<JSScript*> mScript;
+  JS::PersistentRooted<JSObject*> mFunction;
 };
 
 class nsFrameScriptObjectExecutorStackHolder;
 
 class nsFrameScriptExecutor
 {
 public:
   static void Shutdown();
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -1646,25 +1646,23 @@ typedef struct MOZ_STACK_CLASS {
 PLDHashOperator
 HTMLMediaElement::BuildObjectFromTags(nsCStringHashKey::KeyType aKey,
                                       nsCString aValue,
                                       void* aUserArg)
 {
   MetadataIterCx* args = static_cast<MetadataIterCx*>(aUserArg);
 
   nsString wideValue = NS_ConvertUTF8toUTF16(aValue);
-  JSString* string = JS_NewUCStringCopyZ(args->cx, wideValue.Data());
+  JS::Rooted<JSString*> string(args->cx, JS_NewUCStringCopyZ(args->cx, wideValue.Data()));
   if (!string) {
     NS_WARNING("Failed to perform string copy");
     args->error = true;
     return PL_DHASH_STOP;
   }
-  JS::Value value = STRING_TO_JSVAL(string);
-  if (!JS_DefineProperty(args->cx, args->tags, aKey.Data(), value,
-                         nullptr, nullptr, JSPROP_ENUMERATE)) {
+  if (!JS_DefineProperty(args->cx, args->tags, aKey.Data(), string, JSPROP_ENUMERATE)) {
     NS_WARNING("Failed to set metadata property");
     args->error = true;
     return PL_DHASH_STOP;
   }
 
   return PL_DHASH_NEXT;
 }
 
--- a/content/media/AudioStream.cpp
+++ b/content/media/AudioStream.cpp
@@ -407,17 +407,18 @@ AudioStream::Init(int32_t aNumChannels, 
   NS_ABORT_IF_FALSE(bufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
   mBuffer.SetCapacity(bufferLimit);
 
   if (aLatencyRequest == LowLatency) {
     // Don't block this thread to initialize a cubeb stream.
     // When this is done, it will start callbacks from Cubeb.  Those will
     // cause us to move from INITIALIZED to RUNNING.  Until then, we
     // can't access any cubeb functions.
-    AudioInitTask *init = new AudioInitTask(this, aLatencyRequest, params);
+    // Use a RefPtr to avoid leaks if Dispatch fails
+    RefPtr<AudioInitTask> init = new AudioInitTask(this, aLatencyRequest, params);
     init->Dispatch();
     return NS_OK;
   }
   // High latency - open synchronously
   nsresult rv = OpenCubeb(params, aLatencyRequest);
   // See if we need to start() the stream, since we must do that from this
   // thread for now (cubeb API issue)
   CheckForStart();
--- a/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
+++ b/content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
@@ -65,27 +65,26 @@ SVGMotionSMILAnimationFunction::SetAttr(
     if (aParseResult) {
       *aParseResult = rv;
     }
   } else if (aAttribute == nsGkAtoms::rotate) {
     nsresult rv = SetRotate(aValue, aResult);
     if (aParseResult) {
       *aParseResult = rv;
     }
-  } else if (aAttribute == nsGkAtoms::path) {
+  } else if (aAttribute == nsGkAtoms::path ||
+             aAttribute == nsGkAtoms::by ||
+             aAttribute == nsGkAtoms::from ||
+             aAttribute == nsGkAtoms::to ||
+             aAttribute == nsGkAtoms::values) {
     aResult.SetTo(aValue);
+    MarkStaleIfAttributeAffectsPath(aAttribute);
     if (aParseResult) {
       *aParseResult = NS_OK;
     }
-    MarkStaleIfAttributeAffectsPath(aAttribute);
-  } else if (aAttribute == nsGkAtoms::by ||
-             aAttribute == nsGkAtoms::from ||
-             aAttribute == nsGkAtoms::to ||
-             aAttribute == nsGkAtoms::values) {
-    MarkStaleIfAttributeAffectsPath(aAttribute);
   } else {
     // Defer to superclass method
     return nsSMILAnimationFunction::SetAttr(aAttribute, aValue,
                                             aResult, aParseResult);
   }
 
   return true;
 }
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -805,19 +805,20 @@ nsXULElement::RemoveChildAt(uint32_t aIn
       // and cells going away.
       // First, retrieve the tree.
       // Check first whether this element IS the tree
       controlElement = do_QueryObject(this);
 
       // If it's not, look at our parent
       if (!controlElement)
         GetParentTree(getter_AddRefs(controlElement));
+      nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(controlElement));
 
       nsCOMPtr<nsIDOMElement> oldKidElem = do_QueryInterface(oldKid);
-      if (controlElement && oldKidElem) {
+      if (xulElement && oldKidElem) {
         // Iterate over all of the items and find out if they are contained inside
         // the removed subtree.
         int32_t length;
         controlElement->GetSelectedCount(&length);
         for (int32_t i = 0; i < length; i++) {
           nsCOMPtr<nsIDOMXULSelectControlItemElement> node;
           controlElement->MultiGetSelectedItem(i, getter_AddRefs(node));
           // we need to QI here to do an XPCOM-correct pointercompare
@@ -831,17 +832,17 @@ nsXULElement::RemoveChildAt(uint32_t aIn
         }
 
         nsCOMPtr<nsIDOMXULSelectControlItemElement> curItem;
         controlElement->GetCurrentItem(getter_AddRefs(curItem));
         nsCOMPtr<nsIContent> curNode = do_QueryInterface(curItem);
         if (curNode && nsContentUtils::ContentIsDescendantOf(curNode, oldKid)) {
             // Current item going away
             nsCOMPtr<nsIBoxObject> box;
-            controlElement->GetBoxObject(getter_AddRefs(box));
+            xulElement->GetBoxObject(getter_AddRefs(box));
             listBox = do_QueryInterface(box);
             if (listBox && oldKidElem) {
               listBox->GetIndexOfItem(oldKidElem, &newCurrentIndex);
             }
 
             // If any of this fails, we'll just set the current item to null
             if (newCurrentIndex == -1)
               newCurrentIndex = -2;
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -1320,17 +1320,16 @@ nsDocShell::LoadURI(nsIURI * aURI,
                     "Unexpected flags");
     NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
     
     // Note: we allow loads to get through here even if mFiredUnloadEvent is
     // true; that case will get handled in LoadInternal or LoadHistoryEntry.
     if (IsPrintingOrPP()) {
       return NS_OK; // JS may not handle returning of an error code
     }
-    nsresult rv;
     nsCOMPtr<nsIURI> referrer;
     nsCOMPtr<nsIInputStream> postStream;
     nsCOMPtr<nsIInputStream> headersStream;
     nsCOMPtr<nsISupports> owner;
     bool inheritOwner = false;
     bool ownerIsExplicit = false;
     bool sendReferrer = true;
     bool isSrcdoc = false;
@@ -1539,41 +1538,30 @@ nsDocShell::LoadURI(nsIURI * aURI,
     //     from the current document. If none of these things are true, then
     // (4) we pass a null owner into the channel, and an owner will be
     //     created later from the channel's internal data.
     //
     // NOTE: This all only works because the only thing the owner is used  
     //       for in InternalLoad is data:, javascript:, and about:blank
     //       URIs.  For other URIs this would all be dead wrong!
 
-    nsCOMPtr<nsIScriptSecurityManager> secMan =
-        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     if (owner && mItemType != typeChrome) {
         nsCOMPtr<nsIPrincipal> ownerPrincipal = do_QueryInterface(owner);
-        bool isSystem;
-        rv = secMan->IsSystemPrincipal(ownerPrincipal, &isSystem);
-        NS_ENSURE_SUCCESS(rv, rv);
-        nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(ownerPrincipal);
-        if (isSystem || ep) {
+        if (nsContentUtils::IsSystemOrExpandedPrincipal(ownerPrincipal)) {
             if (ownerIsExplicit) {
                 return NS_ERROR_DOM_SECURITY_ERR;
             }
             owner = nullptr;
             inheritOwner = true;
         }
     }
     if (!owner && !inheritOwner && !ownerIsExplicit) {
         // See if there's system or chrome JS code running
-        rv = secMan->SubjectPrincipalIsSystem(&inheritOwner);
-        if (NS_FAILED(rv)) {
-            // Set it back to false
-            inheritOwner = false;
-        }
+        inheritOwner = nsContentUtils::IsSystemPrincipal(
+          nsContentUtils::GetSubjectPrincipal());
     }
 
     if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_OWNER) {
         inheritOwner = false;
         owner = do_CreateInstance("@mozilla.org/nullprincipal;1");
     }
 
     uint32_t flags = 0;
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -510,16 +510,21 @@ this.AlarmService = {
       case "webapps-clear-data":
         let params =
           aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
         if (!params) {
           debug("Error! Fail to remove alarms for an uninstalled app.");
           return;
         }
 
+        // Only remove alarms for apps.
+        if (params.browserOnly) {
+          return;
+        }
+
         let manifestURL = appsService.getManifestURLByLocalId(params.appId);
         if (!manifestURL) {
           debug("Error! Fail to remove alarms for an uninstalled app.");
           return;
         }
 
         this._db.getAll(
           manifestURL,
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -690,18 +690,17 @@ Console::ProfileMethod(JSContext* aCx, c
   if (!event.ToObject(aCx, &eventValue)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   JS::Rooted<JSObject*> eventObj(aCx, &eventValue.toObject());
   MOZ_ASSERT(eventObj);
 
-  if (!JS_DefineProperty(aCx, eventObj, "wrappedJSObject", eventValue,
-                         nullptr, nullptr, JSPROP_ENUMERATE)) {
+  if (!JS_DefineProperty(aCx, eventObj, "wrappedJSObject", eventValue, JSPROP_ENUMERATE)) {
     aRv.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   nsXPConnect*  xpc = nsXPConnect::XPConnect();
   nsCOMPtr<nsISupports> wrapper;
   const nsIID& iid = NS_GET_IID(nsISupports);
 
@@ -999,18 +998,17 @@ Console::ProcessCallData(ConsoleCallData
   if (!event.ToObject(cx, &eventValue)) {
     Throw(cx, NS_ERROR_FAILURE);
     return;
   }
 
   JS::Rooted<JSObject*> eventObj(cx, &eventValue.toObject());
   MOZ_ASSERT(eventObj);
 
-  if (!JS_DefineProperty(cx, eventObj, "wrappedJSObject", eventValue,
-                         nullptr, nullptr, JSPROP_ENUMERATE)) {
+  if (!JS_DefineProperty(cx, eventObj, "wrappedJSObject", eventValue, JSPROP_ENUMERATE)) {
     return;
   }
 
   if (!mStorage) {
     mStorage = do_GetService("@mozilla.org/consoleAPI-storage;1");
   }
 
   if (!mStorage) {
--- a/dom/base/DOMRequest.cpp
+++ b/dom/base/DOMRequest.cpp
@@ -228,73 +228,58 @@ DOMRequestService::FireDetailedError(nsI
   static_cast<DOMRequest*>(aRequest)->FireDetailedError(aError);
 
   return NS_OK;
 }
 
 class FireSuccessAsyncTask : public nsRunnable
 {
 
-  FireSuccessAsyncTask(DOMRequest* aRequest,
+  FireSuccessAsyncTask(JSContext* aCx,
+                       DOMRequest* aRequest,
                        const JS::Value& aResult) :
     mReq(aRequest),
-    mResult(aResult),
-    mIsSetup(false)
+    mResult(aCx, aResult)
   {
   }
 
 public:
 
-  void
-  Setup()
-  {
-    AutoSafeJSContext cx;
-    JS_AddValueRoot(cx, &mResult);
-    mIsSetup = true;
-  }
-
   // Due to the fact that initialization can fail during shutdown (since we
   // can't fetch a js context), set up an initiatization function to make sure
   // we can return the failure appropriately
   static nsresult
   Dispatch(DOMRequest* aRequest,
            const JS::Value& aResult)
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-    nsRefPtr<FireSuccessAsyncTask> asyncTask = new FireSuccessAsyncTask(aRequest, aResult);
-    asyncTask->Setup();
+    AutoSafeJSContext cx;
+    nsRefPtr<FireSuccessAsyncTask> asyncTask = new FireSuccessAsyncTask(cx, aRequest, aResult);
     if (NS_FAILED(NS_DispatchToMainThread(asyncTask))) {
       NS_WARNING("Failed to dispatch to main thread!");
       return NS_ERROR_FAILURE;
     }
     return NS_OK;
   }
 
   NS_IMETHODIMP
   Run()
   {
-    mReq->FireSuccess(JS::Handle<JS::Value>::fromMarkedLocation(&mResult));
+    mReq->FireSuccess(JS::Handle<JS::Value>::fromMarkedLocation(mResult.address()));
     return NS_OK;
   }
 
   ~FireSuccessAsyncTask()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-    if(!mIsSetup) {
-      // If we never set up, no reason to unroot
-      return;
-    }
+  }
 
-    AutoSafeJSContext cx;
-    JS_RemoveValueRoot(cx, &mResult);
-  }
 private:
   nsRefPtr<DOMRequest> mReq;
-  JS::Value mResult;
-  bool mIsSetup;
+  JS::PersistentRooted<JS::Value> mResult;
 };
 
 class FireErrorAsyncTask : public nsRunnable
 {
 public:
   FireErrorAsyncTask(DOMRequest* aRequest,
                      const nsAString& aError) :
     mReq(aRequest),
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1174,79 +1174,79 @@ Navigator::SendBeacon(const nsAString& a
   }
   bool isForeign = true;
   thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign);
   httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign);
 
   nsCString mimeType;
   if (!aData.IsNull()) {
     nsCOMPtr<nsIInputStream> in;
-  
+
     if (aData.Value().IsString()) {
       nsCString stringData = NS_ConvertUTF16toUTF8(aData.Value().GetAsString());
       nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       rv = strStream->SetData(stringData.BeginReading(), stringData.Length());
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType.AssignLiteral("text/plain;charset=UTF-8");
       in = strStream;
-  
+
     } else if (aData.Value().IsArrayBufferView()) {
-  
+
       nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
-  
+
       rv = strStream->SetData(reinterpret_cast<char*>(aData.Value().GetAsArrayBufferView().Data()),
                               aData.Value().GetAsArrayBufferView().Length());
-  
+
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType.AssignLiteral("application/octet-stream");
       in = strStream;
-  
+
     } else if (aData.Value().IsBlob()) {
       nsCOMPtr<nsIDOMBlob> blob = aData.Value().GetAsBlob();
       rv = blob->GetInternalStream(getter_AddRefs(in));
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       nsAutoString type;
       rv = blob->GetType(type);
       if (NS_FAILED(rv)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return false;
       }
       mimeType = NS_ConvertUTF16toUTF8(type);
-  
+
     } else if (aData.Value().IsFormData()) {
       nsFormData& form = aData.Value().GetAsFormData();
       uint64_t len;
       nsAutoCString charset;
       form.GetSendInfo(getter_AddRefs(in),
                        &len,
                        mimeType,
                        charset);
     } else {
       MOZ_ASSERT(false, "switch statements not in sync");
       aRv.Throw(NS_ERROR_FAILURE);
       return false;
     }
-  
+
     nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
     if (!uploadChannel) {
       aRv.Throw(NS_ERROR_FAILURE);
       return false;
     }
     uploadChannel->ExplicitSetUploadStream(in, mimeType, -1,
                                            NS_LITERAL_CSTRING("POST"),
                                            false);
@@ -1263,17 +1263,17 @@ Navigator::SendBeacon(const nsAString& a
                                                                principal,
                                                                true);
 
   // Start a preflight if cross-origin and content type is not whitelisted
   rv = secMan->CheckSameOriginURI(documentURI, uri, false);
   bool crossOrigin = NS_FAILED(rv);
   nsAutoCString contentType, parsedCharset;
   rv = NS_ParseContentType(mimeType, contentType, parsedCharset);
-  if (crossOrigin && 
+  if (crossOrigin &&
       contentType.Length() > 0 &&
       !contentType.Equals(APPLICATION_WWW_FORM_URLENCODED) &&
       !contentType.Equals(MULTIPART_FORM_DATA) &&
       !contentType.Equals(TEXT_PLAIN)) {
     nsCOMPtr<nsIChannel> preflightChannel;
     nsTArray<nsCString> unsafeHeaders;
     unsafeHeaders.AppendElement(NS_LITERAL_CSTRING("Content-Type"));
     rv = NS_StartCORSPreflight(channel,
@@ -1543,17 +1543,17 @@ Navigator::GetMozVoicemail(ErrorResult& 
     if (aRv.Failed()) {
       return nullptr;
     }
   }
 
   return mVoicemail;
 }
 
-nsIDOMMozIccManager*
+IccManager*
 Navigator::GetMozIccManager(ErrorResult& aRv)
 {
   if (!mIccManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -203,17 +203,17 @@ public:
   void MozSetMessageHandler(const nsAString& aType,
                             systemMessageCallback* aCallback,
                             ErrorResult& aRv);
   bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
 #ifdef MOZ_B2G_RIL
   MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
   CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
   Voicemail* GetMozVoicemail(ErrorResult& aRv);
-  nsIDOMMozIccManager* GetMozIccManager(ErrorResult& aRv);
+  IccManager* GetMozIccManager(ErrorResult& aRv);
 #endif // MOZ_B2G_RIL
 #ifdef MOZ_GAMEPAD
   void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
 #endif // MOZ_GAMEPAD
 #ifdef MOZ_B2G_FM
   FMRadio* GetMozFMRadio(ErrorResult& aRv);
 #endif
 #ifdef MOZ_B2G_BT
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -142,17 +142,16 @@
 #include "nsIDOMMobileMessageManager.h"
 #include "nsIDOMMozSmsMessage.h"
 #include "nsIDOMMozMmsMessage.h"
 #include "nsIDOMSmsFilter.h"
 #include "nsIDOMSmsSegmentInfo.h"
 #include "nsIDOMMozMobileMessageThread.h"
 
 #ifdef MOZ_B2G_RIL
-#include "nsIDOMIccManager.h"
 #include "nsIDOMMobileConnection.h"
 #endif // MOZ_B2G_RIL
 
 #ifdef MOZ_B2G_FM
 #include "FMRadio.h"
 #endif
 
 #include "nsIDOMGlobalObjectConstructor.h"
@@ -439,21 +438,16 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(CSSPageRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
-#ifdef MOZ_B2G_RIL
-  NS_DEFINE_CLASSINFO_DATA(MozIccManager, nsDOMGenericSH,
-                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
-#endif
-
   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,
@@ -1114,24 +1108,16 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(MozCSSKeyframesRule, nsIDOMMozCSSKeyframesRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozCSSKeyframesRule)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CSSPageRule, nsIDOMCSSPageRule)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCSSPageRule)
   DOM_CLASSINFO_MAP_END
 
-#ifdef MOZ_B2G_RIL
-  DOM_CLASSINFO_MAP_BEGIN(MozIccManager, nsIDOMMozIccManager)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozIccManager)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
-  DOM_CLASSINFO_MAP_END
-
-#endif
-
   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
 
@@ -2042,36 +2028,37 @@ DefineInterfaceConstants(JSContext *cx, 
   nsCOMPtr<nsIInterfaceInfo> parent_if_info;
 
   rv = if_info->GetParent(getter_AddRefs(parent_if_info));
   NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && parent_if_info, rv);
 
   uint16_t parent_constant_count, i;
   parent_if_info->GetConstantCount(&parent_constant_count);
 
+  JS::Rooted<JS::Value> v(cx);
   for (i = parent_constant_count; i < constant_count; i++) {
     const nsXPTConstant *c = nullptr;
 
     rv = if_info->GetConstant(i, &c);
     NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && c, rv);
 
     uint16_t type = c->GetType().TagPart();
 
-    jsval v;
+    v.setUndefined();
     switch (type) {
       case nsXPTType::T_I8:
       case nsXPTType::T_U8:
       {
-        v = INT_TO_JSVAL(c->GetValue()->val.u8);
+        v.setInt32(c->GetValue()->val.u8);
         break;
       }
       case nsXPTType::T_I16:
       case nsXPTType::T_U16:
       {
-        v = INT_TO_JSVAL(c->GetValue()->val.u16);
+        v.setInt32(c->GetValue()->val.u16);
         break;
       }
       case nsXPTType::T_I32:
       {
         v = JS_NumberValue(c->GetValue()->val.i32);
         break;
       }
       case nsXPTType::T_U32:
@@ -2084,19 +2071,19 @@ DefineInterfaceConstants(JSContext *cx, 
 #ifdef DEBUG
         NS_ERROR("Non-numeric constant found in interface.");
 #endif
         continue;
       }
     }
 
     if (!::JS_DefineProperty(cx, obj, c->GetName(), v,
-                             JS_PropertyStub, JS_StrictPropertyStub,
                              JSPROP_ENUMERATE | JSPROP_READONLY |
-                             JSPROP_PERMANENT)) {
+                             JSPROP_PERMANENT,
+                             JS_PropertyStub, JS_StrictPropertyStub)) {
       return NS_ERROR_UNEXPECTED;
     }
   }
 
   return NS_OK;
 }
 
 class nsDOMConstructor MOZ_FINAL : public nsIDOMDOMConstructor
@@ -2698,18 +2685,18 @@ ResolvePrototype(nsIXPConnect *aXPConnec
 
   v = OBJECT_TO_JSVAL(dot_prototype);
 
   JSAutoCompartment ac(cx, class_obj);
 
   // Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly}
   if (!JS_WrapValue(cx, &v) ||
       !JS_DefineProperty(cx, class_obj, "prototype", v,
-                         JS_PropertyStub, JS_StrictPropertyStub,
-                         JSPROP_PERMANENT | JSPROP_READONLY)) {
+                         JSPROP_PERMANENT | JSPROP_READONLY,
+                         JS_PropertyStub, JS_StrictPropertyStub)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
 static bool
 OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
@@ -3199,19 +3186,19 @@ LookupComponentsShim(JSContext *cx, JS::
   // Create a fake Components object.
   JS::Rooted<JSObject*> components(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), global));
   NS_ENSURE_TRUE(components, NS_ERROR_OUT_OF_MEMORY);
 
   // Create a fake interfaces object.
   JS::Rooted<JSObject*> interfaces(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), global));
   NS_ENSURE_TRUE(interfaces, NS_ERROR_OUT_OF_MEMORY);
   bool ok =
-    JS_DefineProperty(cx, components, "interfaces", JS::ObjectValue(*interfaces),
-                      JS_PropertyStub, JS_StrictPropertyStub,
-                      JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
+    JS_DefineProperty(cx, components, "interfaces", interfaces,
+                      JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
+                      JS_PropertyStub, JS_StrictPropertyStub);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
 
   // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
   // interfaces with constants.
   for (uint32_t i = 0; i < ArrayLength(kInterfaceShimMap); ++i) {
 
     // Grab the names from the table.
     const char *geckoName = kInterfaceShimMap[i].geckoName;
@@ -3223,18 +3210,18 @@ LookupComponentsShim(JSContext *cx, JS::
     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
     if (!v.isObject()) {
       NS_WARNING("Unable to find interface object on global");
       continue;
     }
 
     // Define the shim on the interfaces object.
     ok = JS_DefineProperty(cx, interfaces, geckoName, v,
-                           JS_PropertyStub, JS_StrictPropertyStub,
-                           JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
+                           JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY,
+                           JS_PropertyStub, JS_StrictPropertyStub);
     NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   }
 
   FillPropertyDescriptor(desc, global, JS::ObjectValue(*components), false);
 
   return NS_OK;
 }
 
@@ -3385,18 +3372,18 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
 
     // nsIDocument::WrapObject will handle defining the property.
     *objp = obj;
 
     // NB: We need to do this for any Xray wrapper.
     if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
       *_retval = JS_WrapValue(cx, &v) &&
                  JS_DefineProperty(cx, obj, "document", v,
-                                   JS_PropertyStub, JS_StrictPropertyStub,
-                                   JSPROP_READONLY | JSPROP_ENUMERATE);
+                                   JSPROP_READONLY | JSPROP_ENUMERATE,
+                                   JS_PropertyStub, JS_StrictPropertyStub);
       if (!*_retval) {
         return NS_ERROR_UNEXPECTED;
       }
     }
 
     return NS_OK;
   }
 
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -85,20 +85,16 @@ DOMCI_CLASS(ContentFrameMessageManager)
 DOMCI_CLASS(ChromeMessageBroadcaster)
 DOMCI_CLASS(ChromeMessageSender)
 
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
 
 DOMCI_CLASS(CSSPageRule)
 
-#ifdef MOZ_B2G_RIL
-DOMCI_CLASS(MozIccManager)
-#endif
-
 DOMCI_CLASS(CSSFontFeatureValuesRule)
 
 DOMCI_CLASS(UserDataHandler)
 DOMCI_CLASS(XPathNamespace)
 DOMCI_CLASS(XULControlElement)
 DOMCI_CLASS(XULLabeledControlElement)
 DOMCI_CLASS(XULButtonElement)
 DOMCI_CLASS(XULCheckboxElement)
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2009,28 +2009,25 @@ nsGlobalWindow::WouldReuseInnerWindow(ns
   return false;
 }
 
 void
 nsGlobalWindow::SetInitialPrincipalToSubject()
 {
   FORWARD_TO_OUTER_VOID(SetInitialPrincipalToSubject, ());
 
-  // First, grab the subject principal. These methods never fail.
-  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
-  nsCOMPtr<nsIPrincipal> newWindowPrincipal, systemPrincipal;
-  ssm->GetSubjectPrincipal(getter_AddRefs(newWindowPrincipal));
-  ssm->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
+  // First, grab the subject principal.
+  nsCOMPtr<nsIPrincipal> newWindowPrincipal = nsContentUtils::GetSubjectPrincipal();
   if (!newWindowPrincipal) {
-    newWindowPrincipal = systemPrincipal;
-  }
-
-  // Now, if we're about to use the system principal, make sure we're not using
-  // it for a content docshell.
-  if (newWindowPrincipal == systemPrincipal &&
+    newWindowPrincipal = nsContentUtils::GetSystemPrincipal();
+  }
+
+  // Now, if we're about to use the system principal or an nsExpandedPrincipal,
+  // make sure we're not using it for a content docshell.
+  if (nsContentUtils::IsSystemOrExpandedPrincipal(newWindowPrincipal) &&
       GetDocShell()->ItemType() != nsIDocShellTreeItem::typeChrome) {
     newWindowPrincipal = nullptr;
   }
 
   // If there's an existing document, bail if it either:
   if (mDoc) {
     // (a) is not an initial about:blank document, or
     if (!mDoc->IsInitialDocument())
@@ -2538,20 +2535,20 @@ nsGlobalWindow::SetNewDocument(nsIDocume
                                                     getter_AddRefs(wrapper));
       NS_ENSURE_SUCCESS(rv, rv);
       NS_ABORT_IF_FALSE(wrapper, "bad wrapper");
       rv = wrapper->FinishInitForWrappedGlobal();
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if (!aState) {
-      if (!JS_DefineProperty(cx, newInnerGlobal, "window",
-                             OBJECT_TO_JSVAL(GetWrapperPreserveColor()),
-                             JS_PropertyStub, JS_StrictPropertyStub,
-                             JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+      JS::Rooted<JSObject*> rootedWrapper(cx, GetWrapperPreserveColor());
+      if (!JS_DefineProperty(cx, newInnerGlobal, "window", rootedWrapper,
+                             JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT,
+                             JS_PropertyStub, JS_StrictPropertyStub)) {
         NS_ERROR("can't create the 'window' property");
         return NS_ERROR_FAILURE;
       }
     }
   }
 
   JSAutoCompartment ac(cx, GetWrapperPreserveColor());
 
@@ -4455,19 +4452,18 @@ nsGlobalWindow::SetOpener(nsIDOMWindow* 
     JS::Rooted<JSObject*> thisObj(cx, GetWrapperPreserveColor());
     if (!thisObj) {
       aError.Throw(NS_ERROR_UNEXPECTED);
       return;
     }
 
     if (!JS_WrapObject(cx, &otherObj) ||
         !JS_WrapObject(cx, &thisObj) ||
-        !JS_DefineProperty(cx, thisObj, "opener", JS::ObjectValue(*otherObj),
-                           JS_PropertyStub, JS_StrictPropertyStub,
-                           JSPROP_ENUMERATE)) {
+        !JS_DefineProperty(cx, thisObj, "opener", otherObj, JSPROP_ENUMERATE,
+                           JS_PropertyStub, JS_StrictPropertyStub)) {
       aError.Throw(NS_ERROR_FAILURE);
     }
 
     return;
   }
 
   SetOpenerWindow(aOpener, false);
 }
@@ -13596,18 +13592,18 @@ nsGlobalWindow::SetConsole(JSContext* aC
 {
   JS::Rooted<JSObject*> thisObj(aCx, GetWrapper());
   if (!thisObj) {
     return NS_ERROR_UNEXPECTED;
   }
 
   if (!JS_WrapObject(aCx, &thisObj) ||
       !JS_DefineProperty(aCx, thisObj, "console", aValue,
-                         JS_PropertyStub, JS_StrictPropertyStub,
-                         JSPROP_ENUMERATE)) {
+                         JSPROP_ENUMERATE, JS_PropertyStub,
+                         JS_StrictPropertyStub)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 Console*
 nsGlobalWindow::GetConsole(ErrorResult& aRv)
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -996,24 +996,22 @@ nsJSContext::SetProperty(JS::Handle<JSOb
   // got the arguments, now attach them.
 
   for (uint32_t i = 0; i < args.length(); ++i) {
     if (!JS_WrapValue(mContext, args.handleAt(i))) {
       return NS_ERROR_FAILURE;
     }
   }
 
-  JSObject* array = ::JS_NewArrayObject(mContext, args);
+  JS::Rooted<JSObject*> array(mContext, ::JS_NewArrayObject(mContext, args));
   if (!array) {
     return NS_ERROR_FAILURE;
   }
-  JS::Rooted<JS::Value> arrayVal(mContext, JS::ObjectValue(*array));
-
-  return JS_DefineProperty(mContext, aTarget, aPropName, arrayVal,
-                           nullptr, nullptr, 0) ? NS_OK : NS_ERROR_FAILURE;
+
+  return JS_DefineProperty(mContext, aTarget, aPropName, array, 0) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 nsresult
 nsJSContext::ConvertSupportsTojsvals(nsISupports* aArgs,
                                      JS::Handle<JSObject*> aScope,
                                      JS::AutoValueVector& aArgsOut)
 {
   nsresult rv = NS_OK;
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -182,17 +182,17 @@ ErrorResult::ThrowJSException(JSContext*
   if (IsTypeError()) {
     delete mMessage;
   }
 
   // Make sure mJSException is initialized _before_ we try to root it.  But
   // don't set it to exn yet, because we don't want to do that until after we
   // root.
   mJSException = JS::UndefinedValue();
-  if (!JS_AddNamedValueRoot(cx, &mJSException, "ErrorResult::mJSException")) {
+  if (!js::AddRawValueRoot(cx, &mJSException, "ErrorResult::mJSException")) {
     // Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have
     // in fact rooted mJSException.
     mResult = NS_ERROR_OUT_OF_MEMORY;
   } else {
     mJSException = exn;
     mResult = NS_ERROR_DOM_JS_EXCEPTION;
   }
 }
@@ -205,17 +205,17 @@ ErrorResult::ReportJSException(JSContext
 
   JS::Rooted<JS::Value> exception(cx, mJSException);
   if (JS_WrapValue(cx, &exception)) {
     JS_SetPendingException(cx, exception);
   }
   mJSException = exception;
   // If JS_WrapValue failed, not much we can do about it...  No matter
   // what, go ahead and unroot mJSException.
-  JS_RemoveValueRoot(cx, &mJSException);
+  js::RemoveRawValueRoot(cx, &mJSException);
 }
 
 void
 ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx)
 {
   MOZ_ASSERT(!mMightHaveUnreportedJSException,
              "Why didn't you tell us you planned to handle JS exceptions?");
 
@@ -230,33 +230,33 @@ ErrorResult::ReportJSExceptionFromJSImpl
     // went really wrong.
     NS_RUNTIMEABORT("We stored a non-DOMError exception!");
   }
 
   nsString message;
   domError->GetMessage(message);
 
   JS_ReportError(aCx, "%hs", message.get());
-  JS_RemoveValueRoot(aCx, &mJSException);
+  js::RemoveRawValueRoot(aCx, &mJSException);
 
   // We no longer have a useful exception but we do want to signal that an error
   // occured.
   mResult = NS_ERROR_FAILURE;
 }
 
 void
 ErrorResult::StealJSException(JSContext* cx,
                               JS::MutableHandle<JS::Value> value)
 {
   MOZ_ASSERT(!mMightHaveUnreportedJSException,
              "Must call WouldReportJSException unconditionally in all codepaths that might call StealJSException");
   MOZ_ASSERT(IsJSException(), "No exception to steal");
 
   value.set(mJSException);
-  JS_RemoveValueRoot(cx, &mJSException);
+  js::RemoveRawValueRoot(cx, &mJSException);
   mResult = NS_OK;
 }
 
 void
 ErrorResult::ReportNotEnoughArgsError(JSContext* cx,
                                       const char* ifaceName,
                                       const char* memberName)
 {
@@ -267,19 +267,21 @@ ErrorResult::ReportNotEnoughArgsError(JS
 }
 
 namespace dom {
 
 bool
 DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
                 const ConstantSpec* cs)
 {
+  JS::Rooted<JS::Value> value(cx);
   for (; cs->name; ++cs) {
+    value = cs->value;
     bool ok =
-      JS_DefineProperty(cx, obj, cs->name, cs->value, nullptr, nullptr,
+      JS_DefineProperty(cx, obj, cs->name, value,
                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
     if (!ok) {
       return false;
     }
   }
   return true;
 }
 
@@ -410,18 +412,17 @@ DefineConstructor(JSContext* cx, JS::Han
 {
   bool alreadyDefined;
   if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) {
     return false;
   }
 
   // This is Enumerable: False per spec.
   return alreadyDefined ||
-         JS_DefineProperty(cx, global, name, OBJECT_TO_JSVAL(constructor),
-                           nullptr, nullptr, 0);
+         JS_DefineProperty(cx, global, name, constructor, 0);
 }
 
 static JSObject*
 CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
                       JS::Handle<JSObject*> constructorProto,
                       const JSClass* constructorClass,
                       const JSNativeHolder* constructorNative,
                       unsigned ctorNargs, const NamedConstructor* namedConstructors,
@@ -462,18 +463,18 @@ CreateInterfaceObject(JSContext* cx, JS:
     }
     JSObject* toStringObj = JS_GetFunctionObject(toString);
     js::SetFunctionNativeReserved(toStringObj, TOSTRING_CLASS_RESERVED_SLOT,
                                   PRIVATE_TO_JSVAL(const_cast<JSClass *>(constructorClass)));
 
     js::SetFunctionNativeReserved(toStringObj, TOSTRING_NAME_RESERVED_SLOT,
                                   STRING_TO_JSVAL(str));
 
-    if (!JS_DefineProperty(cx, constructor, "length", JS::Int32Value(ctorNargs),
-                           nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT)) {
+    if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
+                           JSPROP_READONLY | JSPROP_PERMANENT)) {
       return nullptr;
     }
   }
 
   if (properties) {
     if (properties->staticMethods &&
         !DefinePrefable(cx, constructor, properties->staticMethods)) {
       return nullptr;
@@ -520,19 +521,18 @@ CreateInterfaceObject(JSContext* cx, JS:
     int namedConstructorSlot = DOM_INTERFACE_SLOTS_BASE;
     while (namedConstructors->mName) {
       JS::Rooted<JSObject*> namedConstructor(cx,
         CreateConstructor(cx, global, namedConstructors->mName,
                           &namedConstructors->mHolder,
                           namedConstructors->mNargs));
       if (!namedConstructor ||
           !JS_DefineProperty(cx, namedConstructor, "prototype",
-                             JS::ObjectValue(*proto), JS_PropertyStub,
-                             JS_StrictPropertyStub,
-                             JSPROP_PERMANENT | JSPROP_READONLY) ||
+                             proto, JSPROP_PERMANENT | JSPROP_READONLY,
+                             JS_PropertyStub, JS_StrictPropertyStub) ||
           (defineOnGlobal &&
            !DefineConstructor(cx, global, namedConstructors->mName,
                               namedConstructor))) {
         return nullptr;
       }
       js::SetReservedSlot(constructor, namedConstructorSlot++,
                           JS::ObjectValue(*namedConstructor));
       ++namedConstructors;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -790,16 +790,20 @@ DOMInterfaces = {
 'MozCellBroadcast': {
     'nativeType': 'mozilla::dom::CellBroadcast',
 },
 
 'MozIcc': {
     'nativeType': 'mozilla::dom::Icc',
 },
 
+'MozIccManager': {
+    'nativeType': 'mozilla::dom::IccManager',
+},
+
 'MozMobileConnectionArray': {
     'nativeType': 'mozilla::dom::MobileConnectionArray',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'MozNamedAttrMap': {
     'nativeType': 'nsDOMAttributeMap',
 },
@@ -1880,17 +1884,16 @@ addExternalIface('imgINotificationObserv
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback',
                  notflattened=True)
 addExternalIface('MozIccInfo', headerFile='nsIDOMIccInfo.h')
-addExternalIface('MozIccManager', headerFile='nsIDOMIccManager.h')
 addExternalIface('MozMobileConnection', headerFile='nsIDOMMobileConnection.h')
 addExternalIface('MozMobileMessageManager', headerFile='nsIDOMMobileMessageManager.h')
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozTreeBoxObject', nativeType='nsITreeBoxObject',
                  notflattened=True)
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6477,17 +6477,17 @@ class CGJsonifierMethod(CGSpecializedMet
                '}\n')
         for m in self.descriptor.interface.members:
             if m.isAttr() and not m.isStatic() and m.type.isSerializable():
                 ret += ('{ // scope for "temp"\n'
                         '  JS::Rooted<JS::Value> temp(cx);\n'
                         '  if (!get_%s(cx, obj, self, JSJitGetterCallArgs(&temp))) {\n'
                         '    return false;\n'
                         '  }\n'
-                        '  if (!JS_DefineProperty(cx, result, "%s", temp, nullptr, nullptr, JSPROP_ENUMERATE)) {\n'
+                        '  if (!JS_DefineProperty(cx, result, "%s", temp, JSPROP_ENUMERATE)) {\n'
                         '    return false;\n'
                         '  }\n'
                         '}\n' % (m.identifier.name, m.identifier.name))
 
         ret += ('args.rval().setObject(*result);\n'
                 'return true;')
         return CGIndenter(CGGeneric(ret)).define()
 
@@ -6895,17 +6895,17 @@ class CGSpecializedReplaceableSetter(CGS
     """
     def __init__(self, descriptor, attr):
         CGSpecializedSetter.__init__(self, descriptor, attr)
 
     def definition_body(self):
         attrName = self.attr.identifier.name
         # JS_DefineProperty can only deal with ASCII
         assert all(ord(c) < 128 for c in attrName)
-        return CGIndenter(CGGeneric("""return JS_DefineProperty(cx, obj, "%s", args[0], nullptr, nullptr, JSPROP_ENUMERATE);""" % attrName)).define()
+        return CGIndenter(CGGeneric("""return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);""" % attrName)).define()
 
 
 def memberReturnsNewObject(member):
     return member.getExtendedAttribute("NewObject") is not None
 
 
 class CGMemberJITInfo(CGThing):
     """
@@ -11655,17 +11655,17 @@ class CGJSImplClass(CGBindingImplClass):
                 "  return nullptr;\n"
                 "}\n"
                 "\n"
                 "// Now define it on our chrome object\n"
                 "JSAutoCompartment ac(aCx, mImpl->Callback());\n"
                 "if (!JS_WrapObject(aCx, &obj)) {\n"
                 "  return nullptr;\n"
                 "}\n"
-                'if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", JS::ObjectValue(*obj), nullptr, nullptr, 0)) {\n'
+                'if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", obj, 0)) {\n'
                 "  return nullptr;\n"
                 "}\n"
                 "return obj;" % self.descriptor.name)
 
     def getGetParentObjectReturnType(self):
         return "nsISupports*"
 
     def getGetParentObjectBody(self):
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -201,18 +201,17 @@ class TypedArrayCreator
 
   public:
     TypedArrayCreator(const ArrayType& aArray)
       : mArray(aArray)
     {}
 
     JSObject* Create(JSContext* aCx) const
     {
-      return TypedArrayType::Create(aCx, JS::NullPtr(), mArray.Length(),
-                                    mArray.Elements());
+      return TypedArrayType::Create(aCx, mArray.Length(), mArray.Elements());
     }
 
   private:
     const ArrayType& mArray;
 };
 
 // A class for rooting an existing TypedArray struct
 template<typename ArrayType>
--- a/dom/file/MetadataHelper.cpp
+++ b/dom/file/MetadataHelper.cpp
@@ -28,31 +28,31 @@ nsresult
 MetadataHelper::GetSuccessResult(JSContext* aCx,
                                  JS::MutableHandle<JS::Value> aVal)
 {
   JS::Rooted<JSObject*> obj(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(),
                                               JS::NullPtr()));
   NS_ENSURE_TRUE(obj, NS_ERROR_OUT_OF_MEMORY);
 
   if (mParams->SizeRequested()) {
-    JS::Value val = JS_NumberValue(mParams->Size());
+    JS::Rooted<JS::Value> val(aCx, JS_NumberValue(mParams->Size()));
 
-    if (!JS_DefineProperty(aCx, obj, "size", val, nullptr, nullptr,
-                           JSPROP_ENUMERATE)) {
+    if (!JS_DefineProperty(aCx, obj, "size", val, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   if (mParams->LastModifiedRequested()) {
     double msec = mParams->LastModified();
     JSObject *date = JS_NewDateObjectMsec(aCx, msec);
     NS_ENSURE_TRUE(date, NS_ERROR_OUT_OF_MEMORY);
 
-    if (!JS_DefineProperty(aCx, obj, "lastModified", OBJECT_TO_JSVAL(date),
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
+    JS::Rooted<JS::Value> dateRoot(aCx, JS::ObjectValue(*date));
+    if (!JS_DefineProperty(aCx, obj, "lastModified", dateRoot,
+                           JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
   }
 
   aVal.setObject(*obj);
   return NS_OK;
 }
 
--- a/dom/icc/interfaces/moz.build
+++ b/dom/icc/interfaces/moz.build
@@ -1,13 +1,12 @@
 # -*- 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 += [
     'nsIDOMIccInfo.idl',
-    'nsIDOMIccManager.idl',
     'nsIIccProvider.idl',
 ]
 
 XPIDL_MODULE = 'dom_icc'
--- a/dom/icc/src/IccManager.cpp
+++ b/dom/icc/src/IccManager.cpp
@@ -1,178 +1,123 @@
 /* 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 "IccManager.h"
-
+#include "mozilla/dom/MozIccManagerBinding.h"
 #include "GeneratedEvents.h"
 #include "Icc.h"
 #include "IccListener.h"
 #include "mozilla/dom/IccChangeEvent.h"
 #include "mozilla/Preferences.h"
-#include "mozilla/Services.h"
-#include "nsIDOMClassInfo.h"
 #include "nsIDOMIccInfo.h"
 
 using namespace mozilla::dom;
 
-DOMCI_DATA(MozIccManager, IccManager)
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(IccManager)
 
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IccManager,
-                                               DOMEventTargetHelper)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsIccIds)
-  // We did not setup 'mIccListeners' being a participant of cycle collection is
-  // because in Navigator->Invalidate() it will call mIccManager->Shutdown(),
-  // then IccManager will call Shutdown() of each IccListener, this will release
-  // the reference that held by each mIccListener and break the cycle.
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IccManager,
                                                   DOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IccManager,
                                                 DOMEventTargetHelper)
-  tmp->Unroot();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
+// QueryInterface implementation for IccManager
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IccManager)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMMozIccManager)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozIccManager)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(IccManager, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(IccManager, DOMEventTargetHelper)
 
 IccManager::IccManager(nsPIDOMWindow* aWindow)
-  : mJsIccIds(nullptr)
-  , mRooted(false)
+  : DOMEventTargetHelper(aWindow)
 {
-  BindToOwner(aWindow);
-
   uint32_t numberOfServices =
     mozilla::Preferences::GetUint("ril.numRadioInterfaces", 1);
 
   for (uint32_t i = 0; i < numberOfServices; i++) {
     nsRefPtr<IccListener> iccListener = new IccListener(this, i);
     mIccListeners.AppendElement(iccListener);
   }
 }
 
 IccManager::~IccManager()
 {
   Shutdown();
-  Unroot();
+}
+
+JSObject*
+IccManager::WrapObject(JSContext* aCx)
+{
+  return MozIccManagerBinding::Wrap(aCx, this);
 }
 
 void
 IccManager::Shutdown()
 {
   for (uint32_t i = 0; i < mIccListeners.Length(); i++) {
     mIccListeners[i]->Shutdown();
     mIccListeners[i] = nullptr;
   }
   mIccListeners.Clear();
 }
 
 nsresult
 IccManager::NotifyIccAdd(const nsAString& aIccId)
 {
-  mJsIccIds = nullptr;
+  MozIccManagerBinding::ClearCachedIccIdsValue(this);
 
   IccChangeEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mIccId = aIccId;
 
   nsRefPtr<IccChangeEvent> event =
     IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccdetected"), init);
 
   return DispatchTrustedEvent(event);
 }
 
 nsresult
 IccManager::NotifyIccRemove(const nsAString& aIccId)
 {
-  mJsIccIds = nullptr;
+  MozIccManagerBinding::ClearCachedIccIdsValue(this);
 
   IccChangeEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mIccId = aIccId;
 
   nsRefPtr<IccChangeEvent> event =
     IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccundetected"), init);
 
   return DispatchTrustedEvent(event);
 }
 
-void
-IccManager::Root()
-{
-  if (!mRooted) {
-    mozilla::HoldJSObjects(this);
-    mRooted = true;
-  }
-}
+// MozIccManager
 
 void
-IccManager::Unroot()
+IccManager::GetIccIds(nsTArray<nsString>& aIccIds)
 {
-  if (mRooted) {
-    mJsIccIds = nullptr;
-    mozilla::DropJSObjects(this);
-    mRooted = false;
+  nsTArray<nsRefPtr<IccListener>>::size_type i;
+  for (i = 0; i < mIccListeners.Length(); ++i) {
+    nsRefPtr<Icc> icc = mIccListeners[i]->GetIcc();
+    if (icc) {
+      aIccIds.AppendElement(icc->GetIccId());
+    }
   }
 }
 
-// nsIDOMMozIccManager
-
-NS_IMETHODIMP
-IccManager::GetIccIds(JS::MutableHandle<JS::Value> aIccIds)
+already_AddRefed<nsISupports>
+IccManager::GetIccById(const nsAString& aIccId) const
 {
-  if (!mJsIccIds) {
-    nsTArray<nsString> iccIds;
-    for (uint32_t i = 0; i < mIccListeners.Length(); i++) {
-      nsRefPtr<Icc> icc = mIccListeners[i]->GetIcc();
-      if (icc) {
-        iccIds.AppendElement(icc->GetIccId());
-      }
-    }
-
-    nsresult rv;
-    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    AutoPushJSContext cx(sc->GetNativeContext());
-    JS::Rooted<JSObject*> jsIccIds(cx);
-    rv = nsTArrayToJSArray(cx, iccIds, jsIccIds.address());
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    mJsIccIds = jsIccIds;
-    Root();
-  }
-
-  aIccIds.setObject(*mJsIccIds);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-IccManager::GetIccById(const nsAString& aIccId, nsISupports** aIcc)
-{
-  *aIcc = nullptr;
-
-  for (uint32_t i = 0; i < mIccListeners.Length(); i++) {
+  nsTArray<nsRefPtr<IccListener>>::size_type i;
+  for (i = 0; i < mIccListeners.Length(); ++i) {
     nsRefPtr<Icc> icc = mIccListeners[i]->GetIcc();
     if (icc && aIccId == icc->GetIccId()) {
-      icc.forget(aIcc);
-      return NS_OK;
+      return icc.forget();
     }
   }
-
-  return NS_OK;
+  return nullptr;
 }
-
-NS_IMPL_EVENT_HANDLER(IccManager, iccdetected)
-NS_IMPL_EVENT_HANDLER(IccManager, iccundetected)
--- a/dom/icc/src/IccManager.h
+++ b/dom/icc/src/IccManager.h
@@ -2,58 +2,60 @@
  * 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 mozilla_dom_IccManager_h
 #define mozilla_dom_IccManager_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIDOMIccManager.h"
 #include "nsIIccProvider.h"
 #include "nsTArrayHelpers.h"
 
 namespace mozilla {
 namespace dom {
 
 class IccListener;
 
 class IccManager MOZ_FINAL : public DOMEventTargetHelper
-                           , public nsIDOMMozIccManager
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMMOZICCMANAGER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IccManager,
-                                                         DOMEventTargetHelper)
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IccManager, DOMEventTargetHelper)
 
   IccManager(nsPIDOMWindow* aWindow);
   ~IccManager();
 
   void
   Shutdown();
 
   nsresult
   NotifyIccAdd(const nsAString& aIccId);
 
   nsresult
   NotifyIccRemove(const nsAString& aIccId);
 
+  IMPL_EVENT_HANDLER(iccdetected)
+  IMPL_EVENT_HANDLER(iccundetected)
+
+  void
+  GetIccIds(nsTArray<nsString>& aIccIds);
+
+  already_AddRefed<nsISupports>
+  GetIccById(const nsAString& aIccId) const;
+
+  nsPIDOMWindow*
+  GetParentObject() const { return GetOwner(); }
+
+  virtual JSObject*
+  WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
 private:
   nsTArray<nsRefPtr<IccListener>> mIccListeners;
-
-  // Cached iccIds js array object. Cleared whenever the NotifyIccAdd() or
-  // NotifyIccRemove() is called, and then rebuilt once a page looks for the
-  // iccIds attribute.
-  JS::Heap<JSObject*> mJsIccIds;
-  bool mRooted;
-
-  void Root();
-  void Unroot();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_IccManager_h
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -902,37 +902,32 @@ public:
     }
 
     // Technically these props go on the proto, but this detail won't change
     // the results of index creation.
 
     JS::Rooted<JSString*> type(aCx,
       JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length()));
     if (!type ||
-        !JS_DefineProperty(aCx, obj, "size",
-                           JS_NumberValue((double)aData.size),
-                           nullptr, nullptr, 0) ||
-        !JS_DefineProperty(aCx, obj, "type", STRING_TO_JSVAL(type),
-                           nullptr, nullptr, 0)) {
+        !JS_DefineProperty(aCx, obj, "size", double(aData.size), 0) ||
+        !JS_DefineProperty(aCx, obj, "type", type, 0)) {
       return nullptr;
     }
 
     if (aData.tag == SCTAG_DOM_BLOB) {
       return obj;
     }
 
     JS::Rooted<JSString*> name(aCx,
       JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length()));
     JS::Rooted<JSObject*> date(aCx,
       JS_NewDateObjectMsec(aCx, aData.lastModifiedDate));
     if (!name || !date ||
-        !JS_DefineProperty(aCx, obj, "name", STRING_TO_JSVAL(name),
-                           nullptr, nullptr, 0) ||
-        !JS_DefineProperty(aCx, obj, "lastModifiedDate", OBJECT_TO_JSVAL(date),
-                           nullptr, nullptr, 0)) {
+        !JS_DefineProperty(aCx, obj, "name", name, 0) ||
+        !JS_DefineProperty(aCx, obj, "lastModifiedDate", date, 0)) {
       return nullptr;
     }
 
     return obj;
   }
 };
 
 } // anonymous namespace
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -441,18 +441,17 @@ IndexedDatabaseManager::DefineIndexedDB(
   MOZ_ASSERT(factory, "This should never fail for chrome!");
 
   JS::Rooted<JS::Value> indexedDB(aCx);
   js::AssertSameCompartment(aCx, aGlobal);
   if (!WrapNewBindingObject(aCx, factory, &indexedDB)) {
     return false;
   }
 
-  return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, nullptr, nullptr,
-                           JSPROP_ENUMERATE);
+  return JS_DefineProperty(aCx, aGlobal, IDB_STR, indexedDB, JSPROP_ENUMERATE);
 }
 
 // static
 bool
 IndexedDatabaseManager::IsClosed()
 {
   return gClosed;
 }
--- a/dom/interfaces/xul/nsIDOMXULContainerElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULContainerElement.idl
@@ -1,18 +1,18 @@
 /* -*- 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 "nsIDOMXULElement.idl"
 interface nsIDOMXULContainerElement;
 
-[scriptable, uuid(6f59f65f-afc9-4076-a80f-7b25d5a42fe4)]
-interface nsIDOMXULContainerItemElement : nsIDOMXULElement
+[scriptable, uuid(800a68c7-b854-4597-a436-3055ce5c5c96)]
+interface nsIDOMXULContainerItemElement : nsISupports
 {
   /**
    * Returns the parent container if any.
    */
   readonly attribute nsIDOMXULContainerElement parentContainer;
 };
 
 [scriptable, uuid(b2bc96b8-31fc-42f4-937a-bd27291af40b)]
--- a/dom/interfaces/xul/nsIDOMXULControlElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULControlElement.idl
@@ -3,18 +3,18 @@
  * 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 "nsIDOMElement.idl"
 #include "nsIDOMXULElement.idl"
 
 interface nsIControllers;
 
-[scriptable, uuid(e184acec-1890-4c17-9402-6481d9309a61)]
-interface nsIDOMXULControlElement : nsIDOMXULElement {
+[scriptable, uuid(ea7f92d0-b379-4107-91b4-1e69bdd771e3)]
+interface nsIDOMXULControlElement : nsISupports {
   attribute boolean disabled;
   attribute long tabIndex;
   
 // XXX defined in XULElement, but should be defined here
 //  readonly attribute nsIControllers controllers;
   
 //  void focus();
 //  void blur();
--- a/dom/interfaces/xul/nsIDOMXULDescriptionElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULDescriptionElement.idl
@@ -1,15 +1,15 @@
 
 /* -*- 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 "nsIDOMXULElement.idl"
 
-[scriptable, uuid(7a3be943-dfc0-4b7f-8b5e-692bbce0ce47)]
-interface nsIDOMXULDescriptionElement : nsIDOMXULElement {
+[scriptable, uuid(64c3500e-e258-4d49-b7ca-c93ab0931ce4)]
+interface nsIDOMXULDescriptionElement : nsISupports {
   attribute boolean disabled;
   attribute boolean crop;
   attribute DOMString value;
 };
 
--- a/dom/interfaces/xul/nsIDOMXULImageElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULImageElement.idl
@@ -1,12 +1,12 @@
 /* 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 "nsIDOMElement.idl"
 #include "nsIDOMXULElement.idl"
 
-[scriptable, uuid(d6f60061-263a-4e57-8986-6b0036ea488b)]
-interface nsIDOMXULImageElement : nsIDOMXULElement {
+[scriptable, uuid(0a391077-c509-49d2-af73-72e2114edd65)]
+interface nsIDOMXULImageElement : nsISupports {
   attribute DOMString src;
 };
 
--- a/dom/interfaces/xul/nsIDOMXULPopupElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULPopupElement.idl
@@ -1,18 +1,18 @@
 /* -*- 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 "nsIDOMElement.idl"
 #include "nsIDOMXULElement.idl"
 
-[scriptable, uuid(84fcce86-79de-4e22-8b9a-2c014ebde3e5)]
-interface nsIDOMXULPopupElement : nsIDOMXULElement {
+[scriptable, uuid(cb7eaa79-45d5-4ea3-ae17-b65fdcfe5e30)]
+interface nsIDOMXULPopupElement : nsISupports {
   const unsigned short      BEFORE_START                   = 1;
   const unsigned short      BEFORE_END                     = 2;
   const unsigned short      AFTER_START                    = 3;
   const unsigned short      AFTER_END                      = 4;
   const unsigned short      START_BEFORE                   = 5;
   const unsigned short      START_AFTER                    = 6;
   const unsigned short      END_BEFORE                     = 7;
   const unsigned short      END_AFTER                      = 8;
--- a/dom/interfaces/xul/nsIDOMXULSelectCntrlItemEl.idl
+++ b/dom/interfaces/xul/nsIDOMXULSelectCntrlItemEl.idl
@@ -1,18 +1,18 @@
 /* -*- 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 "nsIDOMXULElement.idl"
 interface nsIDOMXULSelectControlElement;
 
-[scriptable, uuid(5cf0f3e0-43aa-4c2b-a599-3adf5025cda5)]
-interface nsIDOMXULSelectControlItemElement : nsIDOMXULElement {
+[scriptable, uuid(5c6be58f-17df-4750-88a5-4a59ac28adc9)]
+interface nsIDOMXULSelectControlItemElement : nsISupports {
   attribute boolean disabled;
   attribute DOMString crop;
   attribute DOMString image;
   attribute DOMString label;
   attribute DOMString accessKey;
   attribute DOMString command;
   
   attribute DOMString value;
--- a/dom/interfaces/xul/nsIDOMXULTreeElement.idl
+++ b/dom/interfaces/xul/nsIDOMXULTreeElement.idl
@@ -9,18 +9,18 @@
 interface nsITreeColumns;
 interface nsITreeView;
 interface nsIDOMXULTextBoxElement;
 
 /**
  * @status UNDER_DEVELOPMENT
  */
 
-[scriptable, uuid(660b5fd1-fa8f-4c9f-901e-cf10ca69b5fd)]
-interface nsIDOMXULTreeElement : nsIDOMXULElement
+[scriptable, uuid(013b62af-1e2f-4b07-9091-d7c0fc4687e2)]
+interface nsIDOMXULTreeElement : nsISupports
 {
 
   readonly attribute nsITreeColumns columns;
 
   attribute nsITreeView view;
 
   readonly attribute nsIDOMElement body;
 
--- a/dom/mobilemessage/src/MmsMessage.cpp
+++ b/dom/mobilemessage/src/MmsMessage.cpp
@@ -539,52 +539,47 @@ MmsMessage::GetAttachments(JSContext* aC
 
   for (uint32_t i = 0; i < length; ++i) {
     const Attachment &attachment = mAttachments[i];
 
     JS::Rooted<JSObject*> attachmentObj(
       aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
     NS_ENSURE_TRUE(attachmentObj, NS_ERROR_OUT_OF_MEMORY);
 
-    JS::Rooted<JS::Value> tmpJsVal(aCx);
-    JSString* tmpJsStr;
+    JS::Rooted<JSString*> tmpJsStr(aCx);
 
     // Get |attachment.mId|.
     tmpJsStr = JS_NewUCStringCopyN(aCx,
                                    attachment.id.get(),
                                    attachment.id.Length());
     NS_ENSURE_TRUE(tmpJsStr, NS_ERROR_OUT_OF_MEMORY);
 
-    tmpJsVal.setString(tmpJsStr);
-    if (!JS_DefineProperty(aCx, attachmentObj, "id", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
+    if (!JS_DefineProperty(aCx, attachmentObj, "id", tmpJsStr, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     // Get |attachment.mLocation|.
     tmpJsStr = JS_NewUCStringCopyN(aCx,
                                    attachment.location.get(),
                                    attachment.location.Length());
     NS_ENSURE_TRUE(tmpJsStr, NS_ERROR_OUT_OF_MEMORY);
 
-    tmpJsVal.setString(tmpJsStr);
-    if (!JS_DefineProperty(aCx, attachmentObj, "location", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
+    if (!JS_DefineProperty(aCx, attachmentObj, "location", tmpJsStr, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     // Get |attachment.mContent|.
+    JS::Rooted<JS::Value> tmpJsVal(aCx);
     nsresult rv = nsContentUtils::WrapNative(aCx,
                                              attachment.content,
                                              &NS_GET_IID(nsIDOMBlob),
                                              &tmpJsVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (!JS_DefineProperty(aCx, attachmentObj, "content", tmpJsVal,
-                           nullptr, nullptr, JSPROP_ENUMERATE)) {
+    if (!JS_DefineProperty(aCx, attachmentObj, "content", tmpJsVal, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
     if (!JS_SetElement(aCx, attachments, i, attachmentObj)) {
       return NS_ERROR_FAILURE;
     }
   }
 
--- a/dom/mobilemessage/src/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/src/ipc/SmsParent.cpp
@@ -34,103 +34,96 @@ namespace mobilemessage {
 static JSObject*
 MmsAttachmentDataToJSObject(JSContext* aContext,
                             const MmsAttachmentData& aAttachment)
 {
   JS::Rooted<JSObject*> obj(aContext, JS_NewObject(aContext, nullptr, JS::NullPtr(),
                                                    JS::NullPtr()));
   NS_ENSURE_TRUE(obj, nullptr);
 
-  JSString* idStr = JS_NewUCStringCopyN(aContext,
-                                        aAttachment.id().get(),
-                                        aAttachment.id().Length());
+  JS::Rooted<JSString*> idStr(aContext, JS_NewUCStringCopyN(aContext,
+                                                            aAttachment.id().get(),
+                                                            aAttachment.id().Length()));
   NS_ENSURE_TRUE(idStr, nullptr);
-  if (!JS_DefineProperty(aContext, obj, "id", JS::StringValue(idStr),
-                         nullptr, nullptr, 0)) {
+  if (!JS_DefineProperty(aContext, obj, "id", idStr, 0)) {
     return nullptr;
   }
 
-  JSString* locStr = JS_NewUCStringCopyN(aContext,
-                                         aAttachment.location().get(),
-                                         aAttachment.location().Length());
+  JS::Rooted<JSString*> locStr(aContext, JS_NewUCStringCopyN(aContext,
+                                                             aAttachment.location().get(),
+                                                             aAttachment.location().Length()));
   NS_ENSURE_TRUE(locStr, nullptr);
-  if (!JS_DefineProperty(aContext, obj, "location", JS::StringValue(locStr),
-                         nullptr, nullptr, 0)) {
+  if (!JS_DefineProperty(aContext, obj, "location", locStr, 0)) {
     return nullptr;
   }
 
   nsCOMPtr<nsIDOMBlob> blob = static_cast<BlobParent*>(aAttachment.contentParent())->GetBlob();
   JS::Rooted<JS::Value> content(aContext);
   nsresult rv = nsContentUtils::WrapNative(aContext,
                                            blob,
                                            &NS_GET_IID(nsIDOMBlob),
                                            &content);
   NS_ENSURE_SUCCESS(rv, nullptr);
-  if (!JS_DefineProperty(aContext, obj, "content", content,
-                         nullptr, nullptr, 0)) {
+  if (!JS_DefineProperty(aContext, obj, "content", content, 0)) {
     return nullptr;
   }
 
   return obj;
 }
 
 static bool
 GetParamsFromSendMmsMessageRequest(JSContext* aCx,
                                    const SendMmsMessageRequest& aRequest,
                                    JS::Value* aParam)
 {
   JS::Rooted<JSObject*> paramsObj(aCx, JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
   NS_ENSURE_TRUE(paramsObj, false);
 
   // smil
-  JSString* smilStr = JS_NewUCStringCopyN(aCx,
-                                          aRequest.smil().get(),
-                                          aRequest.smil().Length());
+  JS::Rooted<JSString*> smilStr(aCx, JS_NewUCStringCopyN(aCx,
+                                                         aRequest.smil().get(),
+                                                         aRequest.smil().Length()));
   NS_ENSURE_TRUE(smilStr, false);
-  if(!JS_DefineProperty(aCx, paramsObj, "smil", JS::StringValue(smilStr),
-                        nullptr, nullptr, 0)) {
+  if(!JS_DefineProperty(aCx, paramsObj, "smil", smilStr, 0)) {
     return false;
   }
 
   // subject
-  JSString* subjectStr = JS_NewUCStringCopyN(aCx,
-                                             aRequest.subject().get(),
-                                             aRequest.subject().Length());
+  JS::Rooted<JSString*> subjectStr(aCx, JS_NewUCStringCopyN(aCx,
+                                                            aRequest.subject().get(),
+                                                            aRequest.subject().Length()));
   NS_ENSURE_TRUE(subjectStr, false);
-  if(!JS_DefineProperty(aCx, paramsObj, "subject",
-                        JS::StringValue(subjectStr), nullptr, nullptr, 0)) {
+  if(!JS_DefineProperty(aCx, paramsObj, "subject", subjectStr, 0)) {
     return false;
   }
 
   // receivers
   JS::Rooted<JSObject*> receiverArray(aCx);
   if (NS_FAILED(nsTArrayToJSArray(aCx,
                                   aRequest.receivers(),
                                   receiverArray.address()))) {
     return false;
   }
-  if (!JS_DefineProperty(aCx, paramsObj, "receivers",
-                         JS::ObjectValue(*receiverArray), nullptr, nullptr, 0)) {
+  if (!JS_DefineProperty(aCx, paramsObj, "receivers", receiverArray, 0)) {
     return false;
   }
 
   // attachments
   JS::Rooted<JSObject*> attachmentArray(aCx, JS_NewArrayObject(aCx,
                                                                aRequest.attachments().Length()));
   for (uint32_t i = 0; i < aRequest.attachments().Length(); i++) {
     JS::Rooted<JSObject*> obj(aCx,
       MmsAttachmentDataToJSObject(aCx, aRequest.attachments().ElementAt(i)));
     NS_ENSURE_TRUE(obj, false);
     if (!JS_SetElement(aCx, attachmentArray, i, obj)) {
       return false;
     }
   }
 
-  if (!JS_DefineProperty(aCx, paramsObj, "attachments",
-                         JS::ObjectValue(*attachmentArray), nullptr, nullptr, 0)) {
+  if (!JS_DefineProperty(aCx, paramsObj, "attachments", attachmentArray, 0)) {
     return false;
   }
 
   aParam->setObject(*paramsObj);
   return true;
 }
 
 NS_IMPL_ISUPPORTS1(SmsParent, nsIObserver)
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -156,18 +156,19 @@ NPObjWrapper_Finalize(JSFreeOp *fop, JSO
 
 static bool
 NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static bool
 NPObjWrapper_Construct(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static bool
-CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject *npobj,
-                     JS::Handle<jsid> id, NPVariant* getPropertyResult, JS::Value *vp);
+CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj,
+                     JS::Handle<jsid> id,  NPVariant* getPropertyResult,
+                     JS::MutableHandle<JS::Value> vp);
 
 const JSClass sNPObjectJSWrapperClass =
   {
     NPRUNTIME_JSCLASS_NAME,
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE,
     NPObjWrapper_AddProperty,
     NPObjWrapper_DelProperty,
     NPObjWrapper_GetProperty,
@@ -491,17 +492,17 @@ ReportExceptionIfPending(JSContext *cx)
   }
 
   ThrowJSException(cx, nullptr);
 
   return false;
 }
 
 nsJSObjWrapper::nsJSObjWrapper(NPP npp)
-  : mNpp(npp)
+  : mJSObj(GetJSContext(npp), nullptr), mNpp(npp)
 {
   MOZ_COUNT_CTOR(nsJSObjWrapper);
   OnWrapperCreated();
 }
 
 nsJSObjWrapper::~nsJSObjWrapper()
 {
   MOZ_COUNT_DTOR(nsJSObjWrapper);
@@ -509,19 +510,16 @@ nsJSObjWrapper::~nsJSObjWrapper()
   // Invalidate first, since it relies on sJSRuntime and sJSObjWrappers.
   NP_Invalidate(this);
 
   OnWrapperDestroyed();
 }
 
 void
 nsJSObjWrapper::ClearJSObject() {
-  // Unroot the object's JSObject
-  JS_RemoveObjectRootRT(sJSRuntime, &mJSObj);
-
   // Forget our reference to the JSObject.
   mJSObj = nullptr;
 }
 
 // static
 NPObject *
 nsJSObjWrapper::NP_Allocate(NPP npp, NPClass *aClass)
 {
@@ -1017,38 +1015,27 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
   nsJSObjWrapper *wrapper =
     (nsJSObjWrapper *)_createobject(npp, &sJSObjWrapperNPClass);
 
   if (!wrapper) {
     // Out of memory, entry not yet added to table.
     return nullptr;
   }
 
+  // Assign mJSObj, rooting the JSObject. Its lifetime is now tied to that of
+  // the NPObject.
   wrapper->mJSObj = obj;
 
   nsJSObjWrapperKey key(obj, npp);
   if (!sJSObjWrappers.putNew(key, wrapper)) {
     // Out of memory, free the wrapper we created.
     _releaseobject(wrapper);
     return nullptr;
   }
 
-  NS_ASSERTION(wrapper->mNpp == npp, "nsJSObjWrapper::mNpp not initialized!");
-
-  // Root the JSObject, its lifetime is now tied to that of the
-  // NPObject.
-  if (!::JS_AddNamedObjectRoot(cx, &wrapper->mJSObj, "nsJSObjWrapper::mJSObject")) {
-    NS_ERROR("Failed to root JSObject!");
-
-    sJSObjWrappers.remove(key);
-    _releaseobject(wrapper);
-
-    return nullptr;
-  }
-
   // Add postbarrier for the hashtable key
   JS_StoreObjectPostBarrierCallback(cx, JSObjWrapperKeyMarkCallback, obj, wrapper->mNpp);
 
   return wrapper;
 }
 
 // Climb the prototype chain, unwrapping as necessary until we find an NP object
 // wrapper.
@@ -1266,17 +1253,17 @@ NPObjWrapper_GetProperty(JSContext *cx, 
       if (success)
         _releasevariantvalue(&npv);
       return false;
     }
 
     if (success) {
       // We return NPObject Member class here to support ambiguous members.
       if (hasProperty && hasMethod)
-        return CreateNPObjectMember(npp, cx, obj, npobj, id, &npv, vp.address());
+        return CreateNPObjectMember(npp, cx, obj, npobj, id, &npv, vp);
 
       if (hasProperty) {
         vp.set(NPVariantToJSVal(npp, cx, &npv));
         _releasevariantvalue(&npv);
 
         if (!ReportExceptionIfPending(cx))
           return false;
       }
@@ -1289,17 +1276,17 @@ NPObjWrapper_GetProperty(JSContext *cx, 
     return false;
 
   hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return false;
 
   // We return NPObject Member class here to support ambiguous members.
   if (hasProperty && hasMethod)
-    return CreateNPObjectMember(npp, cx, obj, npobj, id, nullptr, vp.address());
+    return CreateNPObjectMember(npp, cx, obj, npobj, id, nullptr, vp);
 
   if (hasProperty) {
     if (npobj->_class->getProperty(npobj, identifier, &npv))
       vp.set(NPVariantToJSVal(npp, cx, &npv));
 
     _releasevariantvalue(&npv);
 
     if (!ReportExceptionIfPending(cx))
@@ -1901,22 +1888,21 @@ LookupNPP(NPObject *npobj)
     return nullptr;
   }
 
   NS_ASSERTION(entry->mNpp, "Live NPObject entry w/o an NPP!");
 
   return entry->mNpp;
 }
 
-bool
+static bool
 CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj,
-                     JS::Handle<jsid> id,  NPVariant* getPropertyResult, JS::Value *vp)
+                     JS::Handle<jsid> id,  NPVariant* getPropertyResult,
+                     JS::MutableHandle<JS::Value> vp)
 {
-  NS_ENSURE_TRUE(vp, false);
-
   if (!npobj || !npobj->_class || !npobj->_class->getProperty ||
       !npobj->_class->invoke) {
     ThrowJSException(cx, "Bad NPObject");
 
     return false;
   }
 
   NPObjectMemberPrivate *memberPrivate =
@@ -1929,18 +1915,17 @@ CreateNPObjectMember(NPP npp, JSContext 
   memset(memberPrivate, 0, sizeof(NPObjectMemberPrivate));
 
   JSObject *memobj = ::JS_NewObject(cx, &sNPObjectMemberClass, JS::NullPtr(), JS::NullPtr());
   if (!memobj) {
     PR_Free(memberPrivate);
     return false;
   }
 
-  *vp = OBJECT_TO_JSVAL(memobj);
-  ::JS_AddValueRoot(cx, vp);
+  vp.setObject(*memobj);
 
   ::JS_SetPrivate(memobj, (void *)memberPrivate);
 
   NPIdentifier identifier = JSIdToNPIdentifier(id);
 
   JS::Rooted<JS::Value> fieldValue(cx);
   NPVariant npv;
 
@@ -1948,23 +1933,17 @@ CreateNPObjectMember(NPP npp, JSContext 
     // Plugin has already handed us the value we want here.
     npv = *getPropertyResult;
   }
   else {
     VOID_TO_NPVARIANT(npv);
 
     NPBool hasProperty = npobj->_class->getProperty(npobj, identifier,
                                                     &npv);
-    if (!ReportExceptionIfPending(cx)) {
-      ::JS_RemoveValueRoot(cx, vp);
-      return false;
-    }
-
-    if (!hasProperty) {
-      ::JS_RemoveValueRoot(cx, vp);
+    if (!ReportExceptionIfPending(cx) || !hasProperty) {
       return false;
     }
   }
 
   fieldValue = NPVariantToJSVal(npp, cx, &npv);
 
   // npobjWrapper is the JSObject through which we make sure we don't
   // outlive the underlying NPObject, so make sure it points to the
@@ -1972,18 +1951,16 @@ CreateNPObjectMember(NPP npp, JSContext 
   obj = GetNPObjectWrapper(cx, obj);
 
   memberPrivate->npobjWrapper = obj;
 
   memberPrivate->fieldValue = fieldValue;
   memberPrivate->methodName = id;
   memberPrivate->npp = npp;
 
-  ::JS_RemoveValueRoot(cx, vp);
-
   return true;
 }
 
 static bool
 NPObjectMember_Convert(JSContext *cx, JS::Handle<JSObject*> obj, JSType type, JS::MutableHandle<JS::Value> vp)
 {
   NPObjectMemberPrivate *memberPrivate =
     (NPObjectMemberPrivate *)::JS_GetInstancePrivate(cx, obj,
--- a/dom/plugins/base/nsJSNPRuntime.h
+++ b/dom/plugins/base/nsJSNPRuntime.h
@@ -36,17 +36,17 @@ public:
   const NPP mNpp;
 };
 
 extern const JSClass sNPObjectJSWrapperClass;
 
 class nsJSObjWrapper : public NPObject
 {
 public:
-  JSObject *mJSObj;  /* Added as a GC root. */
+  JS::PersistentRooted<JSObject *> mJSObj;
   const NPP mNpp;
 
   static NPObject *GetNewOrUsed(NPP npp, JSContext *cx,
                                 JS::Handle<JSObject*> obj);
 
   void ClearJSObject();
 
 protected:
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -87,56 +87,43 @@ private:
 
 class PromiseResolverMixin
 {
 public:
   PromiseResolverMixin(Promise* aPromise,
                        JS::Handle<JS::Value> aValue,
                        Promise::PromiseState aState)
     : mPromise(aPromise)
-    , mValue(aValue)
+    , mValue(CycleCollectedJSRuntime::Get()->Runtime(), aValue)
     , mState(aState)
   {
     MOZ_ASSERT(aPromise);
     MOZ_ASSERT(mState != Promise::Pending);
     MOZ_COUNT_CTOR(PromiseResolverMixin);
-
-    /* It's safe to use unsafeGet() here: the unsafeness comes from the
-     * possibility of updating the value of mJSObject without triggering the
-     * barriers.  However if the value will always be marked, post barriers
-     * unnecessary. */
-    JS_AddNamedValueRootRT(CycleCollectedJSRuntime::Get()->Runtime(), mValue.unsafeGet(),
-                           "PromiseResolverMixin.mValue");
   }
 
   virtual ~PromiseResolverMixin()
   {
     NS_ASSERT_OWNINGTHREAD(PromiseResolverMixin);
     MOZ_COUNT_DTOR(PromiseResolverMixin);
-
-    /* It's safe to use unsafeGet() here: the unsafeness comes from the
-     * possibility of updating the value of mJSObject without triggering the
-     * barriers.  However if the value will always be marked, post barriers
-     * unnecessary. */
-    JS_RemoveValueRootRT(CycleCollectedJSRuntime::Get()->Runtime(), mValue.unsafeGet());
   }
 
 protected:
   void
   RunInternal()
   {
     NS_ASSERT_OWNINGTHREAD(PromiseResolverMixin);
     mPromise->RunResolveTask(
       JS::Handle<JS::Value>::fromMarkedLocation(mValue.address()),
       mState, Promise::SyncTask);
   }
 
 private:
   nsRefPtr<Promise> mPromise;
-  JS::Heap<JS::Value> mValue;
+  JS::PersistentRooted<JS::Value> mValue;
   Promise::PromiseState mState;
   NS_DECL_OWNINGTHREAD;
 };
 
 // This class processes the promise's callbacks with promise's result.
 class PromiseResolverTask MOZ_FINAL : public nsRunnable,
                                       public PromiseResolverMixin
 {
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -364,16 +364,21 @@ this.PushService = {
         debug("webapps-clear-data");
 
         let data = aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
         if (!data) {
           debug("webapps-clear-data: Failed to get information about application");
           return;
         }
 
+        // Only remove push registrations for apps.
+        if (data.browserOnly) {
+          return;
+        }
+
         let appsService = Cc["@mozilla.org/AppsService;1"]
                             .getService(Ci.nsIAppsService);
         let manifestURL = appsService.getManifestURLByLocalId(data.appId);
         if (!manifestURL) {
           debug("webapps-clear-data: No manifest URL found for " + data.appId);
           return;
         }
 
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -639,19 +639,20 @@ NetworkManager.prototype = {
       if (this.isNetworkTypeSecondaryMobile(this.active.type)) {
         gNetworkService.setDNS(this.active);
       } else {
 #endif // MOZ_B2G_RIL
         gNetworkService.setDefaultRouteAndDNS(this.active, oldActive);
 #ifdef MOZ_B2G_RIL
       }
 #endif
-      if (this.active != oldActive) {
-        Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
-      }
+    }
+
+    if (this.active != oldActive) {
+      Services.obs.notifyObservers(this.active, TOPIC_ACTIVE_CHANGED, null);
     }
 
     if (this._manageOfflineStatus) {
       Services.io.offline = !this.active;
     }
   },
 
 #ifdef MOZ_B2G_RIL
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/marionette/head.js
@@ -0,0 +1,134 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_CONTEXT = "chrome";
+
+let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+
+/**
+ * Wrap DOMRequest onsuccess/onerror events to Promise resolve/reject.
+ *
+ * Fulfill params: A DOMEvent.
+ * Reject params: A DOMEvent.
+ *
+ * @param aRequest
+ *        A DOMRequest instance.
+ *
+ * @return A deferred promise.
+ */
+function wrapDomRequestAsPromise(aRequest) {
+  let deferred = Promise.defer();
+
+  ok(aRequest instanceof DOMRequest,
+     "aRequest is instanceof " + aRequest.constructor);
+
+  aRequest.addEventListener("success", function(aEvent) {
+    deferred.resolve(aEvent);
+  });
+  aRequest.addEventListener("error", function(aEvent) {
+    deferred.reject(aEvent);
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Get mozSettings value specified by @aKey.
+ *
+ * Resolve if that mozSettings value is retrieved successfully, reject
+ * otherwise.
+ *
+ * Fulfill params: The corresponding mozSettings value of the key.
+ * Reject params: (none)
+ *
+ * @param aKey
+ *        A string.
+ * @param aAllowError [optional]
+ *        A boolean value.  If set to true, an error response won't be treated
+ *        as test failure.  Default: false.
+ *
+ * @return A deferred promise.
+ */
+function getSettings(aKey, aAllowError) {
+  let request = window.navigator.mozSettings.createLock().get(aKey);
+  return wrapDomRequestAsPromise(request)
+    .then(function resolve(aEvent) {
+      log("getSettings(" + aKey + ") - success");
+      return aEvent.target.result[aKey];
+    }, function reject(aEvent) {
+      ok(aAllowError, "getSettings(" + aKey + ") - error");
+    });
+}
+
+/**
+ * Set mozSettings values.
+ *
+ * Resolve if that mozSettings value is set successfully, reject otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aKey
+ *        A string key.
+ * @param aValue
+ *        An object value.
+ * @param aAllowError [optional]
+ *        A boolean value.  If set to true, an error response won't be treated
+ *        as test failure.  Default: false.
+ *
+ * @return A deferred promise.
+ */
+function setSettings(aKey, aValue, aAllowError) {
+  let settings = {};
+  settings[aKey] = aValue;
+  let request = window.navigator.mozSettings.createLock().set(settings);
+  return wrapDomRequestAsPromise(request)
+    .then(function resolve() {
+      log("setSettings(" + JSON.stringify(settings) + ") - success");
+    }, function reject() {
+      ok(aAllowError, "setSettings(" + JSON.stringify(settings) + ") - error");
+    });
+}
+
+/**
+ * Wait for observer event.
+ *
+ * Resolve if that topic event occurs.  Never reject.
+ *
+ * Fulfill params: the subject passed.
+ *
+ * @param aTopic
+ *        A string topic name.
+ *
+ * @return A deferred promise.
+ */
+function waitForObserverEvent(aTopic) {
+  let obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
+  let deferred = Promise.defer();
+
+  obs.addObserver(function observer(subject, topic, data) {
+    if (topic === aTopic) {
+      obs.removeObserver(observer, aTopic);
+      deferred.resolve(subject);
+    }
+  }, aTopic, false);
+
+  return deferred.promise;
+}
+
+/**
+ * Basic test routine helper.
+ *
+ * This helper does nothing but clean-ups.
+ *
+ * @param aTestCaseMain
+ *        A function that takes no parameter.
+ */
+function startTestBase(aTestCaseMain) {
+  Promise.resolve()
+    .then(aTestCaseMain)
+    .then(finish, function() {
+      ok(false, 'promise rejects during test.');
+      finish();
+    });
+}
--- a/dom/system/gonk/tests/marionette/manifest.ini
+++ b/dom/system/gonk/tests/marionette/manifest.ini
@@ -5,8 +5,9 @@ qemu = true
 
 [test_geolocation.js]
 disabled = Bug 808783
 [test_fakevolume.js]
 [test_ril_code_quality.py]
 [test_screen_state.js]
 [test_dsds_numRadioInterfaces.js]
 [test_data_connection.js]
+[test_network_active_changed.js]
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/marionette/test_network_active_changed.js
@@ -0,0 +1,54 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled";
+const TOPIC_NETWORK_ACTIVE_CHANGED = "network-active-changed";
+
+let networkManager =
+  Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
+ok(networkManager,
+   "networkManager.constructor is " + networkManager.constructor);
+
+function testInitialState() {
+  return Promise.resolve()
+    .then(() => getSettings(SETTINGS_KEY_DATA_ENABLED))
+    .then((enabled) => {
+      is(enabled, false, "data should be off by default");
+      is(networkManager.active, null,
+         "networkManager.active should be null by default");
+    });
+}
+
+function testActiveNetworkChangedBySwitchingDataCall(aDataCallEnabled) {
+  log("Test active network by switching dataCallEnabled to " + aDataCallEnabled);
+
+  return Promise.resolve()
+    .then(() => setSettings(SETTINGS_KEY_DATA_ENABLED, aDataCallEnabled))
+    .then(() => waitForObserverEvent(TOPIC_NETWORK_ACTIVE_CHANGED))
+    .then((subject) => {
+      if (aDataCallEnabled) {
+        ok(subject instanceof Ci.nsINetworkInterface,
+           "subject should be an instance of nsINetworkInterface");
+        ok(subject instanceof Ci.nsIRilNetworkInterface,
+           "subject should be an instance of nsIRILNetworkInterface");
+        is(subject.type, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE,
+           "subject.type should be NETWORK_TYPE_MOBILE");
+      }
+
+      is(subject, networkManager.active,
+         "subject should be equal with networkManager.active");
+    });
+}
+
+// Start test
+startTestBase(function() {
+  return Promise.resolve()
+    .then(() => testInitialState())
+    // Test active network changed by enabling data call.
+    .then(() => testActiveNetworkChangedBySwitchingDataCall(true))
+    // Test active network changed by disabling data call.
+    .then(() => testActiveNetworkChangedBySwitchingDataCall(false));
+});
--- a/dom/telephony/gonk/TelephonyProvider.js
+++ b/dom/telephony/gonk/TelephonyProvider.js
@@ -425,34 +425,59 @@ TelephonyProvider.prototype = {
     if (DEBUG) debug("Dialing " + (aIsEmergency ? "emergency " : "") + aNumber);
 
     if (this.isDialing) {
       if (DEBUG) debug("Already has a dialing call. Drop.");
       aTelephonyCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
       return;
     }
 
-    // For DSDS, if there is aleady a call on SIM X, we cannot place any new
-    // call on other SIM.
-    let callOnOtherSim = false;
-    for (let cid = 0; cid < this._numClients; ++cid) {
-      if (cid === aClientId) {
-        continue;
+    function hasCallsOnOtherClient(aClientId) {
+      for (let cid = 0; cid < this._numClients; ++cid) {
+        if (cid === aClientId) {
+          continue;
+        }
+        if (Object.keys(this._currentCalls[cid]).length !== 0) {
+          return true;
+        }
       }
-      if (Object.keys(this._currentCalls[cid]).length !== 0) {
-        callOnOtherSim = true;
-        break;
-      }
+      return false;
     }
-    if (callOnOtherSim) {
+
+    // For DSDS, if there is aleady a call on SIM 'aClientId', we cannot place
+    // any new call on other SIM.
+    if (hasCallsOnOtherClient.call(this, aClientId)) {
       if (DEBUG) debug("Already has a call on other sim. Drop.");
       aTelephonyCallback.notifyDialError(DIAL_ERROR_OTHER_CONNECTION_IN_USE);
       return;
     }
 
+    // All calls in the conference is regarded as one conference call.
+    function numCallsOnLine(aClientId) {
+      let numCalls = 0;
+      let hasConference = false;
+
+      for (let cid in this._currentCalls[aClientId]) {
+        let call = this._currentCalls[aClientId][cid];
+        if (call.isConference) {
+          hasConference = true;
+        } else {
+          numCalls++;
+        }
+      }
+
+      return hasConference ? numCalls + 1 : numCalls;
+    }
+
+    if (numCallsOnLine.call(this, aClientId) >= 2) {
+      if (DEBUG) debug("Has more than 2 calls on line. Drop.");
+      aTelephonyCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
+      return;
+    }
+
     // we don't try to be too clever here, as the phone is probably in the
     // locked state. Let's just check if it's a number without normalizing
     if (!aIsEmergency) {
       aNumber = gPhoneNumberUtils.normalize(aNumber);
     }
 
     // Validate the number.
     if (!gPhoneNumberUtils.isPlainPhoneNumber(aNumber)) {
--- a/dom/telephony/test/marionette/head.js
+++ b/dom/telephony/test/marionette/head.js
@@ -379,16 +379,18 @@ let emulator = (function() {
       is(call.serviceId, serviceId);
 
       call.onalerting = function onalerting(event) {
         call.onalerting = null;
         log("Received 'onalerting' call event.");
         checkEventCallState(event, call, "alerting");
         deferred.resolve(call);
       };
+    }, cause => {
+      deferred.reject(cause);
     });
 
     return deferred.promise;
   }
 
   /**
    * Answer an incoming call.
    *
@@ -439,16 +441,48 @@ let emulator = (function() {
       receive("call.onconnected");
     };
     call.answer();
 
     return deferred.promise;
   }
 
   /**
+   * Hold a call.
+   *
+   * @param call
+   *        A TelephonyCall object.
+   * @return A deferred promise.
+   */
+  function hold(call) {
+    log("Putting the call on hold.");
+
+    let deferred = Promise.defer();
+
+    let gotHolding = false;
+    call.onholding = function onholding(event) {
+      log("Received 'holding' call event");
+      call.onholding = null;
+      checkEventCallState(event, call, "holding");
+      gotHolding = true;
+    };
+
+    call.onheld = function onheld(event) {
+      log("Received 'held' call event");
+      call.onheld = null;
+      checkEventCallState(event, call, "held");
+      ok(gotHolding);
+      deferred.resolve(call);
+    };
+    call.hold();
+
+    return deferred.promise;
+  }
+
+  /**
    * Simulate an incoming call.
    *
    * @param number
    *        A string.
    * @return A deferred promise.
    */
   function remoteDial(number) {
     log("Simulating an incoming call.");
@@ -1033,16 +1067,17 @@ let emulator = (function() {
   this.gCheckInitialState = checkInitialState;
   this.gClearCalls = clearCalls;
   this.gOutCallStrPool = outCallStrPool;
   this.gInCallStrPool = inCallStrPool;
   this.gCheckState = checkState;
   this.gCheckAll = checkAll;
   this.gDial = dial;
   this.gAnswer = answer;
+  this.gHold = hold;
   this.gRemoteDial = remoteDial;
   this.gRemoteAnswer = remoteAnswer;
   this.gRemoteHangUp = remoteHangUp;
   this.gRemoteHangUpCalls = remoteHangUpCalls;
   this.gAddCallsToConference = addCallsToConference;
   this.gHoldConference = holdConference;
   this.gResumeConference = resumeConference;
   this.gRemoveCallInConference = removeCallInConference;
--- a/dom/telephony/test/marionette/manifest.ini
+++ b/dom/telephony/test/marionette/manifest.ini
@@ -51,8 +51,9 @@ disabled = Bug 821958
 [test_conference_two_calls.js]
 [test_conference_add_error.js]
 [test_conference_remove_error.js]
 [test_conference_two_hangup_one.js]
 [test_conference_two_hold_resume.js]
 [test_conference_two_remove_one.js]
 [test_conference_three_hangup_one.js]
 [test_conference_three_remove_one.js]
+[test_outgoing_when_two_calls_on_line.js]
new file mode 100644
--- /dev/null
+++ b/dom/telephony/test/marionette/test_outgoing_when_two_calls_on_line.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+function testReject3rdCall() {
+  let outCall1;
+  let outCall2;
+
+  return gDial("0912345001")
+    .then(call => { outCall1 = call; })
+    .then(() => gRemoteAnswer(outCall1))
+    .then(() => gHold(outCall1))
+    .then(() => gDial("0912345002"))
+    .then(call => { outCall2 = call; })
+    .then(() => gRemoteAnswer(outCall2))
+    .then(() => gDial("0912345003"))
+    .then(call => {
+      ok(false, "The dial request should be rejected");
+    }, cause => {
+      log("Reject 3rd call, cuase: " + cause);
+      is(cause, "InvalidStateError");
+    })
+    .then(() => gRemoteHangUpCalls([outCall1, outCall2]));
+}
+
+startTest(function() {
+  testReject3rdCall()
+    .then(null, () => {
+      ok(false, 'promise rejects during test.');
+    })
+    .then(finish);
+});
rename from dom/icc/interfaces/nsIDOMIccManager.idl
rename to dom/webidl/MozIccManager.webidl
--- a/dom/icc/interfaces/nsIDOMIccManager.idl
+++ b/dom/webidl/MozIccManager.webidl
@@ -1,18 +1,15 @@
+/* -*- 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/. */
+ * 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 "nsIDOMEventTarget.idl"
-
-interface nsIDOMMozIcc;
-
-[scriptable, builtinclass, uuid(67e40e8e-35ee-40a4-a5b8-414588675133)]
-interface nsIDOMMozIccManager : nsIDOMEventTarget
+[Pref="dom.icc.enabled"]
+interface MozIccManager : EventTarget
 {
   /**
    * STK menu presentation types.
    */
   const unsigned short STK_MENU_TYPE_NOT_SPECIFIED      = 0x00;
   const unsigned short STK_MENU_TYPE_DATA_VALUES        = 0x01;
   const unsigned short STK_MENU_TYPE_NAVIGATION_OPTIONS = 0x03;
 
@@ -226,30 +223,31 @@ interface nsIDOMMozIccManager : nsIDOMEv
    * Next Action Indicator.
    */
   const unsigned short STK_NEXT_ACTION_NULL                  = 0x00;
   const unsigned short STK_NEXT_ACTION_END_PROACTIVE_SESSION = 0x81;
 
   /**
    * Array of iccIds that are currently detected.
    */
-  readonly attribute jsval iccIds;  // DOMString[]
+  [Cached, Pure]
+  readonly attribute sequence<DOMString> iccIds;
 
   /**
    * Get ICC object by iccId.
    *
    * @param iccId
    *        The identifier of the ICC.
    *
    * @return see MozIcc.webidl for the detail.
    */
-  nsISupports getIccById(in DOMString iccId);
+  nsISupports getIccById(DOMString iccId);
 
   /**
    * 'oniccdetected' event is notified whenever a new ICC is detected.
    */
-  [implicit_jscontext] attribute jsval oniccdetected;
+  attribute EventHandler oniccdetected;
 
   /**
    * 'oniccundetected' event is notified whenever an ICC becomes undetected.
    */
-  [implicit_jscontext] attribute jsval oniccundetected;
+  attribute EventHandler oniccundetected;
 };
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -268,18 +268,16 @@ partial interface Navigator {
   readonly attribute MozCellBroadcast mozCellBroadcast;
 };
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasVoicemailSupport"]
   readonly attribute MozVoicemail mozVoicemail;
 };
 
-// nsIMozNavigatorIccManager
-interface MozIccManager;
 partial interface Navigator {
   [Throws, Func="Navigator::HasIccManagerSupport"]
   readonly attribute MozIccManager? mozIccManager;
 };
 #endif // MOZ_B2G_RIL
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasTelephonySupport"]
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -538,16 +538,17 @@ if CONFIG['MOZ_B2G_BT']:
     ]
 
 if CONFIG['MOZ_B2G_RIL']:
     WEBIDL_FILES += [
         'IccCardLockError.webidl',
         'MozCellBroadcast.webidl',
         'MozCellBroadcastEvent.webidl',
         'MozIcc.webidl',
+        'MozIccManager.webidl',
         'MozMobileConnectionArray.webidl',
         'MozVoicemail.webidl',
         'MozVoicemailEvent.webidl',
     ]
 
 if CONFIG['MOZ_NFC']:
     WEBIDL_FILES += [
          'MozNDEFRecord.webidl',
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -892,20 +892,19 @@ GetOrCreateClassObjectMap(JSContext *cx,
   }
   if (desc.object() && desc.value().isObject() &&
       JS::IsWeakMapObject(&desc.value().toObject())) {
     return &desc.value().toObject();
   }
 
   // It's not there. Create and define it.
   JS::Rooted<JSObject*> map(cx, JS::NewWeakMapObject(cx));
-  if (!map || !JS_DefineProperty(cx, scope, mapName,
-                                 JS::ObjectValue(*map),
-                                 JS_PropertyStub, JS_StrictPropertyStub,
-                                 JSPROP_PERMANENT | JSPROP_READONLY))
+  if (!map || !JS_DefineProperty(cx, scope, mapName, map,
+                                 JSPROP_PERMANENT | JSPROP_READONLY,
+                                 JS_PropertyStub, JS_StrictPropertyStub))
   {
     return nullptr;
   }
   return map;
 }
 
 static JSObject*
 GetOrCreateMapEntryForPrototype(JSContext *cx, JS::Handle<JSObject*> proto)
@@ -1037,19 +1036,19 @@ nsXBLBinding::DoInitJSClass(JSContext *c
     ::JS_SetPrivate(proto, docInfo);
     NS_ADDREF(docInfo);
     JS_SetReservedSlot(proto, 0, PRIVATE_TO_JSVAL(aProtoBinding));
 
     // Next, enter the compartment of the property holder, wrap the proto, and
     // stick it on.
     JSAutoCompartment ac3(cx, holder);
     if (!JS_WrapObject(cx, &proto) ||
-        !JS_DefineProperty(cx, holder, aClassName.get(), JS::ObjectValue(*proto),
-                           JS_PropertyStub, JS_StrictPropertyStub,
-                           JSPROP_READONLY | JSPROP_PERMANENT))
+        !JS_DefineProperty(cx, holder, aClassName.get(), proto,
+                           JSPROP_READONLY | JSPROP_PERMANENT,
+                           JS_PropertyStub, JS_StrictPropertyStub))
     {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // Whew. We have the proto. Wrap it back into the compartment of |obj|,
   // splice it in, and return it.
   JSAutoCompartment ac4(cx, obj);
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -87,19 +87,18 @@ nsXBLProtoImpl::InstallImplementation(ns
 
     // This is just a property holder, so it doesn't need any special JSClass.
     propertyHolder = JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), scopeObject);
     NS_ENSURE_TRUE(propertyHolder, NS_ERROR_OUT_OF_MEMORY);
 
     // Define it as a property on the scopeObject, using the same name used on
     // the content side.
     bool ok = JS_DefineProperty(cx, scopeObject, aPrototypeBinding->ClassName().get(),
-                                JS::ObjectValue(*propertyHolder), JS_PropertyStub,
-                                JS_StrictPropertyStub,
-                                JSPROP_PERMANENT | JSPROP_READONLY);
+                                propertyHolder, JSPROP_PERMANENT | JSPROP_READONLY,
+                                JS_PropertyStub, JS_StrictPropertyStub);
     NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
   } else {
     propertyHolder = targetClassObject;
   }
 
   // Walk our member list and install each one in turn on the XBL scope object.
   for (nsXBLProtoImplMember* curr = mMembers;
        curr;
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -13,35 +13,36 @@
 #include "nsIJSRuntimeService.h"
 #include "nsCOMPtr.h"
 #include "nsIServiceManager.h"
 #include "nsIComponentManager.h"
 #include "nsString.h"
 #include "nsIPrefService.h"
 #include "nspr.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Maybe.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsJSPrincipals.h"
 #include "jswrapper.h"
 
 extern PRLogModuleInfo *MCD;
 using mozilla::AutoSafeJSContext;
 
 //*****************************************************************************
 
-static JSObject *autoconfigSb = nullptr;
+static mozilla::Maybe<JS::PersistentRooted<JSObject *> > autoconfigSb;
 
 nsresult CentralizedAdminPrefManagerInit()
 {
     nsresult rv;
 
     // If the sandbox is already created, no need to create it again.
-    if (autoconfigSb)
+    if (!autoconfigSb.empty())
         return NS_OK;
 
     // Grab XPConnect.
     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
     if (NS_FAILED(rv)) {
         return rv;
     }
 
@@ -52,47 +53,42 @@ nsresult CentralizedAdminPrefManagerInit
 
     // Create a sandbox.
     AutoSafeJSContext cx;
     nsCOMPtr<nsIXPConnectJSObjectHolder> sandbox;
     rv = xpc->CreateSandbox(cx, principal, getter_AddRefs(sandbox));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Unwrap, store and root the sandbox.
-    autoconfigSb = sandbox->GetJSObject();
-    NS_ENSURE_STATE(autoconfigSb);
-    autoconfigSb = js::UncheckedUnwrap(autoconfigSb);
-    JSAutoCompartment ac(cx, autoconfigSb);
-    if (!JS_AddNamedObjectRoot(cx, &autoconfigSb, "AutoConfig Sandbox"))
-        return NS_ERROR_FAILURE;
+    NS_ENSURE_STATE(sandbox->GetJSObject());
+    autoconfigSb.construct(cx, js::UncheckedUnwrap(sandbox->GetJSObject()));
 
     return NS_OK;
 }
 
 nsresult CentralizedAdminPrefManagerFinish()
 {
-    if (autoconfigSb) {
+    if (!autoconfigSb.empty()) {
         AutoSafeJSContext cx;
-        JSAutoCompartment(cx, autoconfigSb);
-        JS_RemoveObjectRoot(cx, &autoconfigSb);
+        autoconfigSb.destroy();
         JS_MaybeGC(cx);
     }
     return NS_OK;
 }
 
 nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length,
-                                   const char *filename, bool bGlobalContext, 
+                                   const char *filename, bool bGlobalContext,
                                    bool bCallbacks, bool skipFirstLine)
 {
     nsresult rv = NS_OK;
 
     if (skipFirstLine) {
-        /* In order to protect the privacy of the JavaScript preferences file 
+        /* In order to protect the privacy of the JavaScript preferences file
          * from loading by the browser, we make the first line unparseable
-         * by JavaScript. We must skip that line here before executing 
+         * by JavaScript. We must skip that line here before executing
          * the JavaScript code.
          */
         unsigned int i = 0;
         while (i < length) {
             char c = js_buffer[i++];
             if (c == '\r') {
                 if (js_buffer[i] == '\n')
                     i++;
@@ -108,19 +104,19 @@ nsresult EvaluateAdminConfigScript(const
 
     // Grab XPConnect.
     nsCOMPtr<nsIXPConnect> xpc = do_GetService(nsIXPConnect::GetCID(), &rv);
     if (NS_FAILED(rv)) {
         return rv;
     }
 
     AutoSafeJSContext cx;
-    JSAutoCompartment ac(cx, autoconfigSb);
+    JSAutoCompartment ac(cx, autoconfigSb.ref());
 
     nsAutoCString script(js_buffer, length);
     JS::RootedValue v(cx);
-    rv = xpc->EvalInSandboxObject(NS_ConvertASCIItoUTF16(script), filename, cx, autoconfigSb,
+    rv = xpc->EvalInSandboxObject(NS_ConvertASCIItoUTF16(script), filename, cx, autoconfigSb.ref(),
                                   /* returnStringOnly = */ false, &v);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
 }
 
--- a/gfx/2d/DataSurfaceHelpers.h
+++ b/gfx/2d/DataSurfaceHelpers.h
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#pragma once
+#ifndef _MOZILLA_GFX_DATASURFACEHELPERS_H
+#define _MOZILLA_GFX_DATASURFACEHELPERS_H
 
 #include "2D.h"
 
 namespace mozilla {
 namespace gfx {
 
 void
 ConvertBGRXToBGRA(uint8_t* aData, const IntSize &aSize, int32_t aStride);
@@ -41,8 +42,10 @@ SurfaceToPackedBGRA(DataSourceSurface *a
  * are simply dropped (no attempt is made to un-pre-multiply alpha from the
  * color components).
  */
 uint8_t*
 SurfaceToPackedBGR(DataSourceSurface *aSurface);
 
 }
 }
+
+#endif // _MOZILLA_GFX_DATASURFACEHELPERS_H
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#pragma once
+#ifndef _MOZILLA_GFX_SOURCESURFACESKIA_H
+#define _MOZILLA_GFX_SOURCESURFACESKIA_H
 
 #ifdef USE_SKIA_GPU
 #include "skia/GrContext.h"
 #include "skia/GrGLInterface.h"
 #endif
 
 #include "skia/SkCanvas.h"
 
@@ -132,8 +133,10 @@ private:
 
   IntSize mSize;
   SkRefPtr<SkCanvas> mCanvas;
   SourceSurfaceSkia* mSnapshot;
 };
 
 }
 }
+
+#endif // _MOZILLA_GFX_SOURCESURFACESKIA_H
--- a/gfx/2d/SourceSurfaceCG.h
+++ b/gfx/2d/SourceSurfaceCG.h
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#pragma once
+#ifndef _MOZILLA_GFX_SOURCESURFACECG_H
+#define _MOZILLA_GFX_SOURCESURFACECG_H
 
 #include <ApplicationServices/ApplicationServices.h>
 
 #include "2D.h"
 
 class MacIOSurface;
 
 namespace mozilla {
@@ -182,8 +183,10 @@ private:
   int32_t mStride;
 
   IntSize mSize;
 };
 
 
 }
 }
+
+#endif // _MOZILLA_GFX_SOURCESURFACECG_H
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1718,21 +1718,25 @@ public:
   bool HasMultipleChildren();
 
   /**
    * Returns true if this container supports children with component alpha.
    * Should only be called while painting a child of this layer.
    */
   bool SupportsComponentAlphaChildren() { return mSupportsComponentAlphaChildren; }
 
+  /**
+   * Returns true if aLayer or any layer in its parent chain has the opaque
+   * content flag set.
+   */
+  static bool HasOpaqueAncestorLayer(Layer* aLayer);
+
 protected:
   friend class ReadbackProcessor;
 
-  static bool HasOpaqueAncestorLayer(Layer* aLayer);
-
   void DidInsertChild(Layer* aLayer);
   void DidRemoveChild(Layer* aLayer);
 
   ContainerLayer(LayerManager* aManager, void* aImplData);
 
   /**
    * A default implementation of ComputeEffectiveTransforms for use by OpenGL
    * and D3D.
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -31,27 +31,16 @@
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsAutoTArray
 #include "TextRenderer.h"               // for TextRenderer
 #include <vector>
 
 namespace mozilla {
 namespace layers {
 
-// HasOpaqueAncestorLayer and ContainerRender are shared between RefLayer and ContainerLayer
-static bool
-HasOpaqueAncestorLayer(Layer* aLayer)
-{
-  for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
-    if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
-      return true;
-  }
-  return false;
-}
-
 /**
  * Returns a rectangle of content painted opaquely by aLayer. Very consertative;
  * bails by returning an empty rect in any tricky situations.
  */
 static nsIntRect
 GetOpaqueRect(Layer* aLayer)
 {
   nsIntRect result;
@@ -241,16 +230,17 @@ static void DrawVelGraph(const nsIntRect
       gfx::Point(bounds.x + graphRect.width / circularBufferSize * i,
                  graphBounds.y + graphRect.height - vel/yScaleFactor));
   }
 
   compositor->DrawLines(graph, clipRect, gfx::Color(0,1,0,1),
                         opacity, transform);
 }
 
+// ContainerRender is shared between RefLayer and ContainerLayer
 template<class ContainerT> void
 ContainerRender(ContainerT* aContainer,
                 LayerManagerComposite* aManager,
                 const nsIntRect& aClipRect)
 {
   /**
    * Setup our temporary surface for rendering the contents of this container.
    */
@@ -290,17 +280,17 @@ ContainerRender(ContainerT* aContainer,
       mode = INIT_MODE_NONE;
     } else {
       const gfx::Matrix4x4& transform3D = aContainer->GetEffectiveTransform();
       gfx::Matrix transform;
       // If we have an opaque ancestor layer, then we can be sure that
       // all the pixels we draw into are either opaque already or will be
       // covered by something opaque. Otherwise copying up the background is
       // not safe.
-      if (HasOpaqueAncestorLayer(aContainer) &&
+      if (ContainerLayer::HasOpaqueAncestorLayer(aContainer) &&
           transform3D.Is2D(&transform) && !ThebesMatrix(transform).HasNonIntegerTranslation()) {
         surfaceCopyNeeded = gfxPrefs::ComponentAlphaEnabled();
         sourcePoint.x += transform._31;
         sourcePoint.y += transform._32;
         aContainer->mSupportsComponentAlphaChildren
           = gfxPrefs::ComponentAlphaEnabled();
       }
     }
--- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp
+++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp
@@ -112,20 +112,25 @@ CanvasLayerD3D10::UpdateSurface()
   Painted();
 
   if (mDrawTarget) {
     mDrawTarget->Flush();
   } else if (mIsD2DTexture) {
     return;
   }
 
+  if (!mTexture) {
+    return;
+  }
+
   if (mGLContext) {
     SharedSurface_GL* surf = mGLContext->RequestFrame();
-    if (!surf)
-        return;
+    if (!surf) {
+      return;
+    }
 
     switch (surf->Type()) {
       case SharedSurfaceType::EGLSurfaceANGLE: {
         SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
 
         mSRView = shareSurf->GetSRV();
         return;
       }
--- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp
@@ -46,26 +46,16 @@ static inline LayerD3D10*
 GetNextSiblingD3D10(LayerD3D10* aLayer)
 {
    Layer* layer = aLayer->GetLayer()->GetNextSibling();
    return layer ? static_cast<LayerD3D10*>(layer->
                                            ImplData())
                 : nullptr;
 }
 
-static bool
-HasOpaqueAncestorLayer(Layer* aLayer)
-{
-  for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
-    if (l->GetContentFlags() & Layer::CONTENT_OPAQUE)
-      return true;
-  }
-  return false;
-}
-
 void
 ContainerLayerD3D10::RenderLayer()
 {
   float renderTargetOffset[] = { 0, 0 };
 
   nsIntRect visibleRect = mVisibleRegion.GetBounds();
   float opacity = GetEffectiveOpacity();
   bool useIntermediate = UseIntermediateSurface();
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -197,17 +197,17 @@ void ApzcPan(AsyncPanZoomController* apz
     touchStartStatus = nsEventStatus_eConsumeNoDefault;
   }
 
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_START, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   // Make sure the move is large enough to not be handled as a tap
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY+OVERCOME_TOUCH_TOLERANCE), ScreenSize(0, 0), 0, 0));
   status = apzc->ReceiveInputEvent(mti);
-  EXPECT_EQ(status, touchStartStatus);
+  EXPECT_EQ(touchStartStatus, status);
   // APZC should be in TOUCHING state
 
   // Allowed touch behaviours must be set after sending touch-start.
   if (aAllowedTouchBehaviors) {
     apzc->SetAllowedTouchBehavior(*aAllowedTouchBehaviors);
   }
 
   nsEventStatus touchMoveStatus;
@@ -219,23 +219,23 @@ void ApzcPan(AsyncPanZoomController* apz
     // APZC should go into the panning state and therefore consume the event.
     touchMoveStatus = nsEventStatus_eConsumeNoDefault;
   }
 
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchStartY), ScreenSize(0, 0), 0, 0));
   status = apzc->ReceiveInputEvent(mti);
-  EXPECT_EQ(status, touchMoveStatus);
+  EXPECT_EQ(touchMoveStatus, status);
 
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
   status = apzc->ReceiveInputEvent(mti);
-  EXPECT_EQ(status, touchMoveStatus);
+  EXPECT_EQ(touchMoveStatus, status);
 
   mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_END, aTime, 0);
   aTime += TIME_BETWEEN_TOUCH_EVENT;
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(10, aTouchEndY), ScreenSize(0, 0), 0, 0));
   status = apzc->ReceiveInputEvent(mti);
 }
 
 static
@@ -269,29 +269,29 @@ void DoPanTest(bool aShouldTriggerScroll
   nsTArray<uint32_t> allowedTouchBehaviors;
   allowedTouchBehaviors.AppendElement(aBehavior);
 
   // Pan down
   ApzcPan(apzc, tm, time, touchStart, touchEnd, !aShouldTriggerScroll, false, &allowedTouchBehaviors);
   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
 
   if (aShouldTriggerScroll) {
-    EXPECT_EQ(pointOut, ScreenPoint(0, -(touchEnd-touchStart)));
-    EXPECT_NE(viewTransformOut, ViewTransform());
+    EXPECT_EQ(ScreenPoint(0, -(touchEnd-touchStart)), pointOut);
+    EXPECT_NE(ViewTransform(), viewTransformOut);
   } else {
-    EXPECT_EQ(pointOut, ScreenPoint());
-    EXPECT_EQ(viewTransformOut, ViewTransform());
+    EXPECT_EQ(ScreenPoint(), pointOut);
+    EXPECT_EQ(ViewTransform(), viewTransformOut);
   }
 
   // Pan back
   ApzcPan(apzc, tm, time, touchEnd, touchStart, !aShouldTriggerScroll, false, &allowedTouchBehaviors);
   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
 
-  EXPECT_EQ(pointOut, ScreenPoint());
-  EXPECT_EQ(viewTransformOut, ViewTransform());
+  EXPECT_EQ(ScreenPoint(), pointOut);
+  EXPECT_EQ(ViewTransform(), viewTransformOut);
 
   apzc->Destroy();
 }
 
 static void
 ApzcPinch(AsyncPanZoomController* aApzc, int aFocusX, int aFocusY, float aScale) {
   aApzc->HandleGestureEvent(PinchGestureInput(PinchGestureInput::PINCHGESTURE_START,
                                             0,
@@ -368,34 +368,34 @@ TEST_F(AsyncPanZoomControllerTester, Pin
 
   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   ApzcPinch(apzc, 250, 300, 1.25);
 
   // the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
   fm = apzc->GetFrameMetrics();
-  EXPECT_EQ(fm.GetZoom().scale, 2.5f);
-  EXPECT_EQ(fm.GetScrollOffset().x, 305);
-  EXPECT_EQ(fm.GetScrollOffset().y, 310);
+  EXPECT_EQ(2.5f, fm.GetZoom().scale);
+  EXPECT_EQ(305, fm.GetScrollOffset().x);
+  EXPECT_EQ(310, fm.GetScrollOffset().y);
 
   // part 2 of the test, move to the top-right corner of the page and pinch and
   // make sure we stay in the correct spot
   fm.SetZoom(CSSToScreenScale(2.0));
   fm.SetScrollOffset(CSSPoint(930, 5));
   apzc->SetFrameMetrics(fm);
   // the visible area of the document in CSS pixels is x=930 y=5 w=50 h=100
 
   ApzcPinch(apzc, 250, 300, 0.5);
 
   // the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200
   fm = apzc->GetFrameMetrics();
-  EXPECT_EQ(fm.GetZoom().scale, 1.0f);
-  EXPECT_EQ(fm.GetScrollOffset().x, 880);
-  EXPECT_EQ(fm.GetScrollOffset().y, 0);
+  EXPECT_EQ(1.0f, fm.GetZoom().scale);
+  EXPECT_EQ(880, fm.GetScrollOffset().x);
+  EXPECT_EQ(0, fm.GetScrollOffset().y);
 
   apzc->Destroy();
 }
 
 TEST_F(AsyncPanZoomControllerTester, PinchWithTouchActionNone) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
@@ -419,19 +419,19 @@ TEST_F(AsyncPanZoomControllerTester, Pin
   apzc->SetTouchActionEnabled(true);
 
   apzc->SetAllowedTouchBehavior(values);
   ApzcPinch(apzc, 250, 300, 1.25);
 
   // The frame metrics should stay the same since touch-action:none makes
   // apzc ignore pinch gestures.
   fm = apzc->GetFrameMetrics();
-  EXPECT_EQ(fm.GetZoom().scale, 2.0f);
-  EXPECT_EQ(fm.GetScrollOffset().x, 300);
-  EXPECT_EQ(fm.GetScrollOffset().y, 300);
+  EXPECT_EQ(2.0f, fm.GetZoom().scale);
+  EXPECT_EQ(300, fm.GetScrollOffset().x);
+  EXPECT_EQ(300, fm.GetScrollOffset().y);
 }
 
 TEST_F(AsyncPanZoomControllerTester, Overzoom) {
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
 
   FrameMetrics fm;
   fm.mViewport = CSSRect(0, 0, 100, 100);
@@ -444,17 +444,17 @@ TEST_F(AsyncPanZoomControllerTester, Ove
   // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
 
   EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
 
   ApzcPinch(apzc, 50, 50, 0.5);
 
   fm = apzc->GetFrameMetrics();
-  EXPECT_EQ(fm.GetZoom().scale, 0.8f);
+  EXPECT_EQ(0.8f, fm.GetZoom().scale);
   // bug 936721 - PGO builds introduce rounding error so
   // use a fuzzy match instead
   EXPECT_LT(abs(fm.GetScrollOffset().x), 1e-5);
   EXPECT_LT(abs(fm.GetScrollOffset().y), 1e-5);
 }
 
 TEST_F(AsyncPanZoomControllerTester, SimpleTransform) {
   TimeStamp testStartTime = TimeStamp::Now();
@@ -462,18 +462,18 @@ TEST_F(AsyncPanZoomControllerTester, Sim
   nsRefPtr<MockContentController> mcc = new NiceMock<MockContentController>();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(0, mcc);
   apzc->SetFrameMetrics(TestFrameMetrics());
 
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
 
-  EXPECT_EQ(pointOut, ScreenPoint());
-  EXPECT_EQ(viewTransformOut, ViewTransform());
+  EXPECT_EQ(ScreenPoint(), pointOut);
+  EXPECT_EQ(ViewTransform(), viewTransformOut);
 }
 
 
 TEST_F(AsyncPanZoomControllerTester, ComplexTransform) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
   // This test assumes there is a page that gets rendered to
@@ -628,18 +628,18 @@ TEST_F(AsyncPanZoomControllerTester, Pan
   apzc->SetTouchActionEnabled(true);
   ApzcPan(apzc, tm, time, touchStart, touchEnd, true, true, &allowedTouchBehaviors);
 
   // Send the signal that content has handled and preventDefaulted the touch
   // events. This flushes the event queue.
   apzc->ContentReceivedTouch(true);
 
   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
-  EXPECT_EQ(pointOut, ScreenPoint());
-  EXPECT_EQ(viewTransformOut, ViewTransform());
+  EXPECT_EQ(ScreenPoint(), pointOut);
+  EXPECT_EQ(ViewTransform(), viewTransformOut);
 
   apzc->Destroy();
 }
 
 TEST_F(AsyncPanZoomControllerTester, Fling) {
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
 
@@ -688,17 +688,17 @@ TEST_F(AsyncPanZoomControllerTester, Ove
   int touchStart = 500;
   int touchEnd = 10;
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
 
   // Pan down
   ApzcPan(apzc, tm, time, touchStart, touchEnd);
   apzc->SampleContentTransformForFrame(testStartTime+TimeDuration::FromMilliseconds(1000), &viewTransformOut, pointOut);
-  EXPECT_EQ(pointOut, ScreenPoint(0, 90));
+  EXPECT_EQ(ScreenPoint(0, 90), pointOut);
 }
 
 TEST_F(AsyncPanZoomControllerTester, ShortPress) {
   nsRefPtr<MockContentControllerDelayed> mcc = new NiceMock<MockContentControllerDelayed>();
   nsRefPtr<TestAPZCTreeManager> tm = new TestAPZCTreeManager();
   nsRefPtr<TestAsyncPanZoomController> apzc = new TestAsyncPanZoomController(
     0, mcc, tm, AsyncPanZoomController::USE_GESTURE_DETECTOR);
 
@@ -865,33 +865,33 @@ TEST_F(AsyncPanZoomControllerTester, Lon
   mcc->ClearDelayedTask();
   apzc->ContentReceivedTouch(true);
 
   time += 1000;
 
   MultiTouchInput mti = MultiTouchInput(MultiTouchInput::MULTITOUCH_MOVE, time, 0);
   mti.mTouches.AppendElement(SingleTouchData(0, ScreenIntPoint(touchX, touchEndY), ScreenSize(0, 0), 0, 0));
   status = apzc->ReceiveInputEvent(mti);
-  EXPECT_EQ(status, nsEventStatus_eIgnore);
+  EXPECT_EQ(nsEventStatus_eIgnore, status);
 
   EXPECT_CALL(*mcc, HandleLongTapUp(CSSPoint(touchX, touchEndY), 0, apzc->GetGuid())).Times(1);
   status = ApzcUp(apzc, touchX, touchEndY, time);
   EXPECT_EQ(nsEventStatus_eIgnore, status);
 
   // Flush the event queue. Once the "contextmenu" event is handled, any touch
   // events that come from the same series of start->n*move->end events should
   // be discarded, even if only the "contextmenu" event is preventDefaulted.
   apzc->ContentReceivedTouch(false);
 
   ScreenPoint pointOut;
   ViewTransform viewTransformOut;
   apzc->SampleContentTransformForFrame(testStartTime, &viewTransformOut, pointOut);
 
-  EXPECT_EQ(pointOut, ScreenPoint());
-  EXPECT_EQ(viewTransformOut, ViewTransform());
+  EXPECT_EQ(ScreenPoint(), pointOut);
+  EXPECT_EQ(ViewTransform(), viewTransformOut);
 
   apzc->Destroy();
 }
 
 TEST_F(AsyncPanZoomControllerTester, LongPress) {
   DoLongPressTest(false, mozilla::layers::AllowedTouchBehavior::NONE);
 }
 
--- a/ipc/testshell/TestShellParent.cpp
+++ b/ipc/testshell/TestShellParent.cpp
@@ -54,17 +54,17 @@ TestShellCommandParent::SetCallback(JSCo
   mCx = aCx;
 
   return true;
 }
 
 bool
 TestShellCommandParent::RunCallback(const nsString& aResponse)
 {
-  NS_ENSURE_TRUE(*mCallback.ToJSValPtr() != JSVAL_NULL && mCx, false);
+  NS_ENSURE_TRUE(!mCallback.get().isNull() && mCx, false);
 
   // We're pulling a cx off the heap, so make sure it's stack-top.
   AutoCxPusher pusher(mCx);
   NS_ENSURE_TRUE(mCallback.ToJSObject(), false);
   JSAutoCompartment ac(mCx, mCallback.ToJSObject());
   JS::Rooted<JSObject*> global(mCx, JS::CurrentGlobalOrNull(mCx));
 
   JSString* str = JS_NewUCStringCopyN(mCx, aResponse.get(), aResponse.Length());
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -541,20 +541,20 @@ XPCShellEnvironment::Init()
     if (!globalObj) {
         NS_ERROR("Failed to get global JSObject!");
         return false;
     }
     JSAutoCompartment ac(cx, globalObj);
 
     backstagePass->SetGlobalObject(globalObj);
 
+    JS::Rooted<Value> privateVal(cx, PrivateValue(this));
     if (!JS_DefineProperty(cx, globalObj, "__XPCShellEnvironment",
-                           PRIVATE_TO_JSVAL(this), JS_PropertyStub,
-                           JS_StrictPropertyStub,
-                           JSPROP_READONLY | JSPROP_PERMANENT) ||
+                           privateVal, JSPROP_READONLY | JSPROP_PERMANENT,
+                           JS_PropertyStub, JS_StrictPropertyStub) ||
         !JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
         !JS_DefineProfilingFunctions(cx, globalObj))
     {
         NS_ERROR("JS_DefineFunctions failed!");
         return false;
     }
 
     mGlobalHolder = globalObj;
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -93,17 +93,17 @@ struct JSDContext
     JSD_ExecutionHookProc   debuggerHook;
     void*                   debuggerHookData;
     JSD_ExecutionHookProc   throwHook;
     void*                   throwHookData;
     JSD_CallHookProc        functionHook;
     void*                   functionHookData;
     JSD_CallHookProc        toplevelHook;
     void*                   toplevelHookData;
-    JSObject*               glob;
+    JS::Heap<JSObject*>     glob;
     JSD_UserCallbacks       userCallbacks;
     void*                   user;
     JSCList                 scripts;
     JSHashTable*            scriptsTable;
     JSCList                 sources;
     JSCList                 removedSources;
     unsigned                   sourceAlterCount;
     JSHashTable*            atoms;
@@ -201,26 +201,26 @@ struct JSDStackFrameInfo
 
 #define GOT_PROTO   ((short) (1 << 0))
 #define GOT_PROPS   ((short) (1 << 1))
 #define GOT_PARENT  ((short) (1 << 2))
 #define GOT_CTOR    ((short) (1 << 3))
 
 struct JSDValue
 {
-    jsval       val;
-    int        nref;
-    JSCList     props;
-    JSString*   string;
-    JSString*   funName;
-    const char* className;
-    JSDValue*   proto;
-    JSDValue*   parent;
-    JSDValue*   ctor;
-    unsigned       flags;
+    JS::Heap<JS::Value> val;
+    int                 nref;
+    JSCList             props;
+    JS::Heap<JSString*> string;
+    JS::Heap<JSString*> funName;
+    const char*         className;
+    JSDValue*           proto;
+    JSDValue*           parent;
+    JSDValue*           ctor;
+    unsigned            flags;
 };
 
 struct JSDProperty
 {
     JSCList     links;      /* we are part of a JSCList */
     int        nref;
     JSDValue*   val;
     JSDValue*   name;
--- a/js/jsd/jsd_high.cpp
+++ b/js/jsd/jsd_high.cpp
@@ -114,43 +114,43 @@ static JSDContext*
         goto label_newJSDContext_failure;
 
     if( ! jsd_InitObjectManager(jsdc) )
         goto label_newJSDContext_failure;
 
     if( ! jsd_InitScriptManager(jsdc) )
         goto label_newJSDContext_failure;
 
-
-    jsdc->glob = CreateJSDGlobal(cx, &global_class);
+    {
+        JS::RootedObject global(cx, CreateJSDGlobal(cx, &global_class));
+        if( ! global )
+            goto label_newJSDContext_failure;
 
-    if( ! jsdc->glob )
-        goto label_newJSDContext_failure;
+        jsdc->glob = global;
 
-    {
         JSAutoCompartment ac(cx, jsdc->glob);
-        ok = JS_AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") &&
-             JS_InitStandardClasses(cx, JS::HandleObject::fromMarkedLocation(&jsdc->glob));
+        ok = JS::AddNamedObjectRoot(cx, &jsdc->glob, "JSD context global") &&
+             JS_InitStandardClasses(cx, global);
     }
     if( ! ok )
         goto label_newJSDContext_failure;
 
     jsdc->data = nullptr;
     jsdc->inited = true;
 
     JSD_LOCK();
     JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
     JSD_UNLOCK();
 
     return jsdc;
 
 label_newJSDContext_failure:
     if( jsdc ) {
         if ( jsdc->glob )
-            JS_RemoveObjectRootRT(JS_GetRuntime(cx), &jsdc->glob);
+            JS::RemoveObjectRootRT(JS_GetRuntime(cx), &jsdc->glob);
         jsd_DestroyObjectManager(jsdc);
         jsd_DestroyAtomTable(jsdc);
         free(jsdc);
     }
     return nullptr;
 }
 
 static void
@@ -158,17 +158,17 @@ static void
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
 
     JSD_LOCK();
     JS_REMOVE_LINK(&jsdc->links);
     JSD_UNLOCK();
 
     if ( jsdc->glob ) {
-        JS_RemoveObjectRootRT(jsdc->jsrt, &jsdc->glob);
+        JS::RemoveObjectRootRT(jsdc->jsrt, &jsdc->glob);
     }
     jsd_DestroyObjectManager(jsdc);
     jsd_DestroyAtomTable(jsdc);
 
     jsdc->inited = false;
 
     /*
     * We should free jsdc here, but we let it leak in case there are any 
--- a/js/jsd/jsd_val.cpp
+++ b/js/jsd/jsd_val.cpp
@@ -197,17 +197,17 @@ jsd_GetValueString(JSDContext* jsdc, JSD
     if(string) {
         stringval = STRING_TO_JSVAL(string);
     }
     if(!string || !JS_WrapValue(cx, &stringval)) {
         return nullptr;
     }
 
     jsdval->string = JSVAL_TO_STRING(stringval);
-    if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
+    if(!JS::AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
         jsdval->string = nullptr;
 
     return jsdval->string;
 }
 
 JSString*
 jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
 {
@@ -247,17 +247,17 @@ jsd_NewValue(JSDContext* jsdc, jsval val
     if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
         return nullptr;
 
     if(JSVAL_IS_GCTHING(val))
     {
         bool ok;
         JSAutoCompartment ac(cx, jsdc->glob);
 
-        ok = JS_AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
+        ok = JS::AddNamedValueRoot(cx, &jsdval->val, "JSDValue");
         if(ok && JSVAL_IS_STRING(val)) {
             if(!JS_WrapValue(cx, &val)) {
                 ok = false;
             }
         }
 
         if(!ok)
         {
@@ -278,17 +278,17 @@ jsd_DropValue(JSDContext* jsdc, JSDValue
     MOZ_ASSERT(jsdval->nref > 0);
     if(0 == --jsdval->nref)
     {
         jsd_RefreshValue(jsdc, jsdval);
         if(JSVAL_IS_GCTHING(jsdval->val))
         {
             AutoSafeJSContext cx;
             JSAutoCompartment ac(cx, jsdc->glob);
-            JS_RemoveValueRoot(cx, &jsdval->val);
+            JS::RemoveValueRoot(cx, &jsdval->val);
         }
         free(jsdval);
     }
 }
 
 jsval
 jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval)
 {
@@ -407,17 +407,17 @@ jsd_RefreshValue(JSDContext* jsdc, JSDVa
 {
     AutoSafeJSContext cx;
     if(jsdval->string)
     {
         /* if the jsval is a string, then we didn't need to root the string */
         if(!JSVAL_IS_STRING(jsdval->val))
         {
             JSAutoCompartment ac(cx, jsdc->glob);
-            JS_RemoveStringRoot(cx, &jsdval->string);
+            JS::RemoveStringRoot(cx, &jsdval->string);
         }
         jsdval->string = nullptr;
     }
 
     jsdval->funName = nullptr;
     jsdval->className = nullptr;
     DROP_CLEAR_VALUE(jsdc, jsdval->proto);
     DROP_CLEAR_VALUE(jsdc, jsdval->parent);
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -118,16 +118,17 @@ namespace JS {
 // Data for tracking memory usage of things hanging off objects.
 struct ObjectsExtraSizes
 {
 #define FOR_EACH_SIZE(macro) \
     macro(Objects, NotLiveGCThing, mallocHeapSlots) \
     macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \
     macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \
     macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \
+    macro(Objects, NotLiveGCThing, nonHeapElementsMapped) \
     macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \
     macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \
     macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \
     macro(Objects, NotLiveGCThing, mallocHeapRegExpStatics) \
     macro(Objects, NotLiveGCThing, mallocHeapPropertyIteratorData) \
     macro(Objects, NotLiveGCThing, mallocHeapCtypesData)
 
     ObjectsExtraSizes()
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -35,20 +35,23 @@ enum TransferableOwnership {
     SCTAG_TMO_FIRST_OWNED = 2,
 
     // Data is a pointer that can be freed
     SCTAG_TMO_ALLOC_DATA = 2,
 
     // Data is a SharedArrayBufferObject's buffer
     SCTAG_TMO_SHARED_BUFFER = 3,
 
+    // Data is a memory mapped pointer
+    SCTAG_TMO_MAPPED_DATA = 4,
+
     // Data is embedding-specific. The engine can free it by calling the
     // freeTransfer op. The embedding can also use SCTAG_TMO_USER_MIN and
     // greater, up to 32 bits, to distinguish specific ownership variants.
-    SCTAG_TMO_CUSTOM = 4,
+    SCTAG_TMO_CUSTOM = 5,
 
     SCTAG_TMO_USER_MIN
 };
 } /* namespace JS */
 
 // Read structured data from the reader r. This hook is used to read a value
 // previously serialized by a call to the WriteStructuredCloneOp hook.
 //
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1068,17 +1068,17 @@ MapObject::initClass(JSContext *cx, JSOb
     if (proto) {
         // Define the "entries" method.
         JSFunction *fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
         if (!fun)
             return nullptr;
 
         // Define its alias.
         RootedValue funval(cx, ObjectValue(*fun));
-        if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, nullptr, nullptr, 0))
+        if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
             return nullptr;
     }
     return proto;
 }
 
 template <class Range>
 static void
 MarkKey(Range &r, const HashableValue &key, JSTracer *trc)
@@ -1637,19 +1637,19 @@ SetObject::initClass(JSContext *cx, JSOb
     if (proto) {
         // Define the "values" method.
         JSFunction *fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
         if (!fun)
             return nullptr;
 
         // Define its aliases.
         RootedValue funval(cx, ObjectValue(*fun));
-        if (!JS_DefineProperty(cx, proto, "keys", funval, nullptr, nullptr, 0))
+        if (!JS_DefineProperty(cx, proto, "keys", funval, 0))
             return nullptr;
-        if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, nullptr, nullptr, 0))
+        if (!JS_DefineProperty(cx, proto, js_std_iterator_str, funval, 0))
             return nullptr;
     }
     return proto;
 }
 
 void
 SetObject::mark(JSTracer *trc, JSObject *obj)
 {
--- a/js/src/builtin/SIMD.cpp
+++ b/js/src/builtin/SIMD.cpp
@@ -30,78 +30,95 @@ using mozilla::IsNaN;
 namespace js {
 extern const JSFunctionSpec Float32x4Methods[];
 extern const JSFunctionSpec Int32x4Methods[];
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // X4
 
-#define LANE_ACCESSOR(Type32x4, lane) \
-    bool Type32x4##Lane##lane(JSContext *cx, unsigned argc, Value *vp) { \
-        static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"}; \
-        CallArgs args = CallArgsFromVp(argc, vp); \
-        if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {        \
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
-                                 X4TypeDescr::class_.name, laneNames[lane], \
-                                 InformalValueTypeName(args.thisv())); \
-            return false; \
-        } \
-        TypedObject &typedObj = args.thisv().toObject().as<TypedObject>(); \
-        TypeDescr &descr = typedObj.typeDescr(); \
-        if (descr.kind() != TypeDescr::X4 || \
-            descr.as<X4TypeDescr>().type() != Type32x4::type) \
-        {  \
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
-                                 X4TypeDescr::class_.name, laneNames[lane], \
-                                 InformalValueTypeName(args.thisv())); \
-            return false; \
-        } \
-        Type32x4::Elem *data = reinterpret_cast<Type32x4::Elem *>(typedObj.typedMem()); \
-        Type32x4::setReturn(args, data[lane]); \
-        return true; \
+static const char *laneNames[] = {"lane 0", "lane 1", "lane 2", "lane3"};
+
+template<typename Type32x4, int lane>
+static bool GetX4Lane(JSContext *cx, unsigned argc, Value *vp) {
+    typedef typename Type32x4::Elem Elem;
+
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+                             X4TypeDescr::class_.name, laneNames[lane],
+                             InformalValueTypeName(args.thisv()));
+        return false;
     }
-    LANE_ACCESSOR(Float32x4, 0);
-    LANE_ACCESSOR(Float32x4, 1);
-    LANE_ACCESSOR(Float32x4, 2);
-    LANE_ACCESSOR(Float32x4, 3);
-    LANE_ACCESSOR(Int32x4, 0);
-    LANE_ACCESSOR(Int32x4, 1);
-    LANE_ACCESSOR(Int32x4, 2);
-    LANE_ACCESSOR(Int32x4, 3);
+
+    TypedObject &typedObj = args.thisv().toObject().as<TypedObject>();
+    TypeDescr &descr = typedObj.typeDescr();
+    if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+                             X4TypeDescr::class_.name, laneNames[lane],
+                             InformalValueTypeName(args.thisv()));
+        return false;
+    }
+
+    Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
+    Type32x4::setReturn(args, data[lane]);
+    return true;
+}
+
+#define LANE_ACCESSOR(type, lane) \
+static bool type##Lane##lane(JSContext *cx, unsigned argc, Value *vp) { \
+    return GetX4Lane<type, lane>(cx, argc, vp);\
+}
+
+#define FOUR_LANES_ACCESSOR(type) \
+    LANE_ACCESSOR(type, 0); \
+    LANE_ACCESSOR(type, 1); \
+    LANE_ACCESSOR(type, 2); \
+    LANE_ACCESSOR(type, 3);
+
+    FOUR_LANES_ACCESSOR(Int32x4);
+    FOUR_LANES_ACCESSOR(Float32x4);
+#undef FOUR_LANES_ACCESSOR
 #undef LANE_ACCESSOR
 
-#define SIGN_MASK(Type32x4) \
-    bool Type32x4##SignMask(JSContext *cx, unsigned argc, Value *vp) { \
-        CallArgs args = CallArgsFromVp(argc, vp); \
-        if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {        \
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
-                                 X4TypeDescr::class_.name, "signMask", \
-                                 InformalValueTypeName(args.thisv())); \
-            return false; \
-        } \
-        TypedObject &typedObj = args.thisv().toObject().as<TypedObject>(); \
-        TypeDescr &descr = typedObj.typeDescr(); \
-        if (descr.kind() != TypeDescr::X4 || \
-            descr.as<X4TypeDescr>().type() != Type32x4::type) \
-        { \
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, \
-                                 X4TypeDescr::class_.name, "signMask", \
-                                 InformalValueTypeName(args.thisv())); \
-            return false; \
-        } \
-        Type32x4::Elem *data = reinterpret_cast<Type32x4::Elem *>(typedObj.typedMem()); \
-        int32_t mx = data[0] < 0.0 ? 1 : 0; \
-        int32_t my = data[1] < 0.0 ? 1 : 0; \
-        int32_t mz = data[2] < 0.0 ? 1 : 0; \
-        int32_t mw = data[3] < 0.0 ? 1 : 0; \
-        int32_t result = mx | my << 1 | mz << 2 | mw << 3; \
-        args.rval().setInt32(result); \
-        return true; \
+template<typename Type32x4>
+static bool SignMask(JSContext *cx, unsigned argc, Value *vp) {
+    typedef typename Type32x4::Elem Elem;
+
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if(!args.thisv().isObject() || !args.thisv().toObject().is<TypedObject>()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+                             X4TypeDescr::class_.name, "signMask",
+                             InformalValueTypeName(args.thisv()));
+        return false;
     }
+
+    TypedObject &typedObj = args.thisv().toObject().as<TypedObject>();
+    TypeDescr &descr = typedObj.typeDescr();
+    if (descr.kind() != TypeDescr::X4 || descr.as<X4TypeDescr>().type() != Type32x4::type) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO,
+                             X4TypeDescr::class_.name, "signMask",
+                             InformalValueTypeName(args.thisv()));
+        return false;
+    }
+
+    Elem *data = reinterpret_cast<Elem *>(typedObj.typedMem());
+    int32_t mx = data[0] < 0.0 ? 1 : 0;
+    int32_t my = data[1] < 0.0 ? 1 : 0;
+    int32_t mz = data[2] < 0.0 ? 1 : 0;
+    int32_t mw = data[3] < 0.0 ? 1 : 0;
+    int32_t result = mx | my << 1 | mz << 2 | mw << 3;
+    args.rval().setInt32(result);
+    return true;
+}
+
+#define SIGN_MASK(type) \
+static bool type##SignMask(JSContext *cx, unsigned argc, Value *vp) { \
+    return SignMask<Int32x4>(cx, argc, vp); \
+}
     SIGN_MASK(Float32x4);
     SIGN_MASK(Int32x4);
 #undef SIGN_MASK
 
 const Class X4TypeDescr::class_ = {
     "X4",
     JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS),
     JS_PropertyStub,         /* addProperty */
@@ -346,19 +363,18 @@ SIMDObject::initClass(JSContext *cx, Han
                                   JSPROP_READONLY | JSPROP_PERMANENT))
     {
         return nullptr;
     }
 
     RootedValue SIMDValue(cx, ObjectValue(*SIMD));
 
     // Everything is set up, install SIMD on the global object.
-    if (!JSObject::defineProperty(cx, global, cx->names().SIMD,  SIMDValue, nullptr, nullptr, 0)) {
+    if (!JSObject::defineProperty(cx, global, cx->names().SIMD, SIMDValue, nullptr, nullptr, 0))
         return nullptr;
-    }
 
     global->setConstructor(JSProto_SIMD, SIMDValue);
 
     // Define float32x4 functions and install as a property of the SIMD object.
     global->setFloat32x4TypeDescr(*float32x4Object);
 
     // Define int32x4 functions and install as a property of the SIMD object.
     global->setInt32x4TypeDescr(*int32x4Object);
@@ -371,518 +387,510 @@ js_InitSIMDClass(JSContext *cx, HandleOb
 {
     JS_ASSERT(obj->is<GlobalObject>());
     Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
     return SIMDObject::initClass(cx, global);
 }
 
 template<typename V>
 static bool
-ObjectIsVector(JSObject &obj) {
+IsVectorObject(HandleValue v)
+{
+    if (!v.isObject())
+        return false;
+
+    JSObject &obj = v.toObject();
     if (!obj.is<TypedObject>())
         return false;
+
     TypeDescr &typeRepr = obj.as<TypedObject>().typeDescr();
     if (typeRepr.kind() != TypeDescr::X4)
         return false;
+
     return typeRepr.as<X4TypeDescr>().type() == V::type;
 }
 
+template<typename Elem>
+static Elem
+TypedObjectMemory(HandleValue v)
+{
+    return reinterpret_cast<Elem>(v.toObject().as<TypedObject>().typedMem());
+}
+
 template<typename V>
 JSObject *
 js::Create(JSContext *cx, typename V::Elem *data)
 {
+    typedef typename V::Elem Elem;
     Rooted<TypeDescr*> typeDescr(cx, &V::GetTypeDescr(*cx->global()));
     JS_ASSERT(typeDescr);
 
     Rooted<TypedObject *> result(cx, TypedObject::createZeroed(cx, typeDescr, 0));
     if (!result)
         return nullptr;
 
-    typename V::Elem *resultMem = reinterpret_cast<typename V::Elem *>(result->typedMem());
-    memcpy(resultMem, data, sizeof(typename V::Elem) * V::lanes);
+    Elem *resultMem = reinterpret_cast<Elem *>(result->typedMem());
+    memcpy(resultMem, data, sizeof(Elem) * V::lanes);
     return result;
 }
 
 template JSObject *js::Create<Float32x4>(JSContext *cx, Float32x4::Elem *data);
 template JSObject *js::Create<Int32x4>(JSContext *cx, Int32x4::Elem *data);
 
 namespace js {
 template<typename T, typename V>
 struct Abs {
-    static inline T apply(T x, T zero) {return V::toType(x < 0 ? -1 * x : x);}
+    static inline T apply(T x, T zero) { return V::toType(x < 0 ? -1 * x : x); }
 };
 template<typename T, typename V>
 struct Neg {
-    static inline T apply(T x, T zero) {return V::toType(-1 * x);}
+    static inline T apply(T x, T zero) { return V::toType(-1 * x); }
 };
 template<typename T, typename V>
 struct Not {
-    static inline T apply(T x, T zero) {return V::toType(~x);}
+    static inline T apply(T x, T zero) { return V::toType(~x); }
 };
 template<typename T, typename V>
 struct Rec {
-    static inline T apply(T x, T zero) {return V::toType(1 / x);}
+    static inline T apply(T x, T zero) { return V::toType(1 / x); }
 };
 template<typename T, typename V>
 struct RecSqrt {
-    static inline T apply(T x, T zero) {return V::toType(1 / sqrt(x));}
+    static inline T apply(T x, T zero) { return V::toType(1 / sqrt(x)); }
 };
 template<typename T, typename V>
 struct Sqrt {
-    static inline T apply(T x, T zero) {return V::toType(sqrt(x));}
+    static inline T apply(T x, T zero) { return V::toType(sqrt(x)); }
 };
 template<typename T, typename V>
 struct Add {
-    static inline T apply(T l, T r) {return V::toType(l + r);}
+    static inline T apply(T l, T r) { return V::toType(l + r); }
 };
 template<typename T, typename V>
 struct Sub {
-    static inline T apply(T l, T r) {return V::toType(l - r);}
+    static inline T apply(T l, T r) { return V::toType(l - r); }
 };
 template<typename T, typename V>
 struct Div {
-    static inline T apply(T l, T r) {return V::toType(l / r);}
+    static inline T apply(T l, T r) { return V::toType(l / r); }
 };
 template<typename T, typename V>
 struct Mul {
-    static inline T apply(T l, T r) {return V::toType(l * r);}
+    static inline T apply(T l, T r) { return V::toType(l * r); }
 };
 template<typename T, typename V>
 struct Minimum {
-    static inline T apply(T l, T r) {return V::toType(l < r ? l : r);}
+    static inline T apply(T l, T r) { return V::toType(l < r ? l : r); }
 };
 template<typename T, typename V>
 struct Maximum {
-    static inline T apply(T l, T r) {return V::toType(l > r ? l : r);}
+    static inline T apply(T l, T r) { return V::toType(l > r ? l : r); }
 };
 template<typename T, typename V>
 struct LessThan {
-    static inline T apply(T l, T r) {return V::toType(l < r ? 0xFFFFFFFF: 0x0);}
+    static inline T apply(T l, T r) { return V::toType(l < r ? 0xFFFFFFFF : 0x0); }
 };
 template<typename T, typename V>
 struct LessThanOrEqual {
-    static inline T apply(T l, T r) {return V::toType(l <= r ? 0xFFFFFFFF: 0x0);}
+    static inline T apply(T l, T r) { return V::toType(l <= r ? 0xFFFFFFFF : 0x0); }
 };
 template<typename T, typename V>
 struct GreaterThan {
-    static inline T apply(T l, T r) {return V::toType(l > r ? 0xFFFFFFFF: 0x0);}
+    static inline T apply(T l, T r) { return V::toType(l > r ? 0xFFFFFFFF : 0x0); }
 };
 template<typename T, typename V>
 struct GreaterThanOrEqual {
-    static inline T apply(T l, T r) {return V::toType(l >= r ? 0xFFFFFFFF: 0x0);}
+    static inline T apply(T l, T r) { return V::toType(l >= r ? 0xFFFFFFFF : 0x0); }
 };
 template<typename T, typename V>
 struct Equal {
-    static inline T apply(T l, T r) {return V::toType(l == r ? 0xFFFFFFFF: 0x0);}
+    static inline T apply(T l, T r) { return V::toType(l == r ? 0xFFFFFFFF : 0x0); }
 };
 template<typename T, typename V>
 struct NotEqual {
-    static inline T apply(T l, T r) {return V::toType(l != r ? 0xFFFFFFFF: 0x0);}
+    static inline T apply(T l, T r) { return V::toType(l != r ? 0xFFFFFFFF : 0x0); }
 };
 template<typename T, typename V>
 struct Xor {
-    static inline T apply(T l, T r) {return V::toType(l ^ r);}
+    static inline T apply(T l, T r) { return V::toType(l ^ r); }
 };
 template<typename T, typename V>
 struct And {
-    static inline T apply(T l, T r) {return V::toType(l & r);}
+    static inline T apply(T l, T r) { return V::toType(l & r); }
 };
 template<typename T, typename V>
 struct Or {
-    static inline T apply(T l, T r) {return V::toType(l | r);}
+    static inline T apply(T l, T r) { return V::toType(l | r); }
 };
 template<typename T, typename V>
 struct Scale {
-    static inline T apply(int32_t lane, T scalar, T x) {return V::toType(scalar * x);}
+    static inline T apply(int32_t lane, T scalar, T x) { return V::toType(scalar * x); }
 };
 template<typename T, typename V>
 struct WithX {
-    static inline T apply(int32_t lane, T scalar, T x) {return V::toType(lane == 0 ? scalar : x);}
+    static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 0 ? scalar : x); }
 };
 template<typename T, typename V>
 struct WithY {
-    static inline T apply(int32_t lane, T scalar, T x) {return V::toType(lane == 1 ? scalar : x);}
+    static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 1 ? scalar : x); }
 };
 template<typename T, typename V>
 struct WithZ {
-    static inline T apply(int32_t lane, T scalar, T x) {return V::toType(lane == 2 ? scalar : x);}
+    static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 2 ? scalar : x); }
 };
 template<typename T, typename V>
 struct WithW {
-    static inline T apply(int32_t lane, T scalar, T x) {return V::toType(lane == 3 ? scalar : x);}
+    static inline T apply(int32_t lane, T scalar, T x) { return V::toType(lane == 3 ? scalar : x); }
 };
 template<typename T, typename V>
 struct WithFlagX {
-    static inline T apply(T l, T f, T x) { return V::toType(l == 0 ? (f ? 0xFFFFFFFF : 0x0) : x);}
+    static inline T apply(T l, T f, T x) { return V::toType(l == 0 ? (f ? 0xFFFFFFFF : 0x0) : x); }
 };
 template<typename T, typename V>
 struct WithFlagY {
-    static inline T apply(T l, T f, T x) { return V::toType(l == 1 ? (f ? 0xFFFFFFFF : 0x0) : x);}
+    static inline T apply(T l, T f, T x) { return V::toType(l == 1 ? (f ? 0xFFFFFFFF : 0x0) : x); }
 };
 template<typename T, typename V>
 struct WithFlagZ {
-    static inline T apply(T l, T f, T x) { return V::toType(l == 2 ? (f ? 0xFFFFFFFF : 0x0) : x);}
+    static inline T apply(T l, T f, T x) { return V::toType(l == 2 ? (f ? 0xFFFFFFFF : 0x0) : x); }
 };
 template<typename T, typename V>
 struct WithFlagW {
-    static inline T apply(T l, T f, T x) { return V::toType(l == 3 ? (f ? 0xFFFFFFFF : 0x0) : x);}
+    static inline T apply(T l, T f, T x) { return V::toType(l == 3 ? (f ? 0xFFFFFFFF : 0x0) : x); }
 };
 template<typename T, typename V>
 struct Shuffle {
-    static inline int32_t apply(int32_t l, int32_t mask) {return V::toType((mask >> l) & 0x3);}
+    static inline int32_t apply(int32_t l, int32_t mask) { return V::toType((mask >> l) & 0x3); }
 };
 }
 
 template<typename V, typename Op, typename Vret>
 static bool
 Func(JSContext *cx, unsigned argc, Value *vp)
 {
-    CallArgs args = CallArgsFromVp(argc, vp);
+    typedef typename V::Elem Elem;
+    typedef typename Vret::Elem RetElem;
 
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() != 1 && args.length() != 2) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+        return false;
+    }
+
+    RetElem result[Vret::lanes];
     if (args.length() == 1) {
-        if((!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject()))) {
+        if (!IsVectorObject<V>(args[0])) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
-        typename V::Elem *val =
-            reinterpret_cast<typename V::Elem *>(
-                args[0].toObject().as<TypedObject>().typedMem());
-        typename Vret::Elem result[Vret::lanes];
+
+        Elem *val = TypedObjectMemory<Elem *>(args[0]);
         for (int32_t i = 0; i < Vret::lanes; i++)
             result[i] = Op::apply(val[i], 0);
-
-        RootedObject obj(cx, Create<Vret>(cx, result));
-        if (!obj)
-            return false;
-
-        args.rval().setObject(*obj);
-        return true;
-
-    } else if (args.length() == 2) {
-        if((!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())) ||
-           (!args[1].isObject() || !ObjectIsVector<V>(args[1].toObject())))
+    } else {
+        JS_ASSERT(args.length() == 2);
+        if(!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]))
         {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
-        typename V::Elem *left =
-            reinterpret_cast<typename V::Elem *>(
-                args[0].toObject().as<TypedObject>().typedMem());
-        typename V::Elem *right =
-            reinterpret_cast<typename V::Elem *>(
-                args[1].toObject().as<TypedObject>().typedMem());
-
-        typename Vret::Elem result[Vret::lanes];
+        Elem *left = TypedObjectMemory<Elem *>(args[0]);
+        Elem *right = TypedObjectMemory<Elem *>(args[1]);
         for (int32_t i = 0; i < Vret::lanes; i++)
             result[i] = Op::apply(left[i], right[i]);
-
-        RootedObject obj(cx, Create<Vret>(cx, result));
-        if (!obj)
-            return false;
+    }
 
-        args.rval().setObject(*obj);
-        return true;
-    } else {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+    RootedObject obj(cx, Create<Vret>(cx, result));
+    if (!obj)
         return false;
-    }
+
+    args.rval().setObject(*obj);
+    return true;
 }
 
 template<typename V, typename OpWith, typename Vret>
 static bool
 FuncWith(JSContext *cx, unsigned argc, Value *vp)
 {
-    CallArgs args = CallArgsFromVp(argc, vp);
+    typedef typename V::Elem Elem;
+    typedef typename Vret::Elem RetElem;
 
-    if ((args.length() != 2) ||
-        (!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())) ||
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() != 2 || !IsVectorObject<V>(args[0]) ||
         (!args[1].isNumber() && !args[1].isBoolean()))
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
 
-    typename V::Elem *val =
-        reinterpret_cast<typename V::Elem *>(
-            args[0].toObject().as<TypedObject>().typedMem());
+    Elem *val = TypedObjectMemory<Elem *>(args[0]);
+    RetElem result[Vret::lanes];
 
-    typename Vret::Elem result[Vret::lanes];
-    for (int32_t i = 0; i < Vret::lanes; i++) {
-        if(args[1].isNumber()) {
-            typename Vret::Elem arg1;
-            Vret::toType2(cx, args[1], &arg1);
-            result[i] = OpWith::apply(i, arg1, val[i]);
-        } else if (args[1].isBoolean()) {
-            result[i] = OpWith::apply(i, args[1].toBoolean(), val[i]);
-        }
+    if (args[1].isNumber()) {
+        Elem withAsNumber;
+        if (!Vret::toType(cx, args[1], &withAsNumber))
+            return false;
+        for (int32_t i = 0; i < Vret::lanes; i++)
+            result[i] = OpWith::apply(i, withAsNumber, val[i]);
+    } else if (args[1].isBoolean()) {
+        bool withAsBool = args[1].toBoolean();
+        for (int32_t i = 0; i < Vret::lanes; i++)
+            result[i] = OpWith::apply(i, withAsBool, val[i]);
     }
+
     RootedObject obj(cx, Create<Vret>(cx, result));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 template<typename V, typename OpShuffle, typename Vret>
 static bool
 FuncShuffle(JSContext *cx, unsigned argc, Value *vp)
 {
+    typedef typename V::Elem Elem;
+    typedef typename Vret::Elem RetElem;
+
     CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() != 2 && args.length() != 3) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+        return false;
+    }
 
+    RetElem result[Vret::lanes];
     if (args.length() == 2) {
-        if ((!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())) ||
-            (!args[1].isNumber()))
+        if (!IsVectorObject<V>(args[0]) || !args[1].isNumber())
         {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
-        typename V::Elem *val =
-            reinterpret_cast<typename V::Elem *>(
-                args[0].toObject().as<TypedObject>().typedMem());
-        typename Vret::Elem result[Vret::lanes];
-        for (int32_t i = 0; i < Vret::lanes; i++) {
-            typename Vret::Elem arg1;
-            Vret::toType2(cx, args[1], &arg1);
-            result[i] = val[OpShuffle::apply(i * 2, arg1)];
-        }
-        RootedObject obj(cx, Create<Vret>(cx, result));
-        if (!obj)
+        Elem *val = TypedObjectMemory<Elem *>(args[0]);;
+        Elem arg1;
+        if (!Vret::toType(cx, args[1], &arg1))
             return false;
 
-        args.rval().setObject(*obj);
-        return true;
-    } else if (args.length() == 3) {
-        if ((!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())) ||
-            (!args[1].isObject() || !ObjectIsVector<V>(args[1].toObject())) ||
-            (!args[2].isNumber()))
+        for (int32_t i = 0; i < Vret::lanes; i++)
+            result[i] = val[OpShuffle::apply(i * 2, arg1)];
+    } else {
+        JS_ASSERT(args.length() == 3);
+        if (!IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]) || !args[2].isNumber())
         {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
-        typename V::Elem *val1 =
-            reinterpret_cast<typename V::Elem *>(
-                args[0].toObject().as<TypedObject>().typedMem());
-        typename V::Elem *val2 =
-            reinterpret_cast<typename V::Elem *>(
-                args[1].toObject().as<TypedObject>().typedMem());
-        typename Vret::Elem result[Vret::lanes];
-        for (int32_t i = 0; i < Vret::lanes; i++) {
-            typename Vret::Elem arg2;
-            Vret::toType2(cx, args[2], &arg2);
-            if(i < Vret::lanes / 2) {
-                result[i] = val1[OpShuffle::apply(i * 2, arg2)];
-            } else {
-                result[i] = val2[OpShuffle::apply(i * 2, arg2)];
-            }
-        }
-        RootedObject obj(cx, Create<Vret>(cx, result));
-        if (!obj)
+
+        Elem *val1 = TypedObjectMemory<Elem *>(args[0]);
+        Elem *val2 = TypedObjectMemory<Elem *>(args[1]);
+        Elem arg2;
+        if (!Vret::toType(cx, args[2], &arg2))
             return false;
 
-        args.rval().setObject(*obj);
-        return true;
-    } else {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
+        for (int32_t i = 0; i < Vret::lanes; i++) {
+            if (i < Vret::lanes / 2)
+                result[i] = val1[OpShuffle::apply(i * 2, arg2)];
+            else
+                result[i] = val2[OpShuffle::apply(i * 2, arg2)];
+        }
+    }
+
+    RootedObject obj(cx, Create<Vret>(cx, result));
+    if (!obj)
         return false;
-    }
+
+    args.rval().setObject(*obj);
+    return true;
 }
 
 template<typename V, typename Vret>
 static bool
 FuncConvert(JSContext *cx, unsigned argc, Value *vp)
 {
-    CallArgs args = CallArgsFromVp(argc, vp);
+    typedef typename V::Elem Elem;
+    typedef typename Vret::Elem RetElem;
 
-    if ((args.length() != 1) ||
-       (!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())))
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() != 1 || !IsVectorObject<V>(args[0]))
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
-    typename V::Elem *val =
-        reinterpret_cast<typename V::Elem *>(
-            args[0].toObject().as<TypedObject>().typedMem());
-    typename Vret::Elem result[Vret::lanes];
+
+    Elem *val = TypedObjectMemory<Elem *>(args[0]);
+    RetElem result[Vret::lanes];
     for (int32_t i = 0; i < Vret::lanes; i++)
-        result[i] = static_cast<typename Vret::Elem>(val[i]);
+        result[i] = RetElem(val[i]);
 
     RootedObject obj(cx, Create<Vret>(cx, result));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 template<typename V, typename Vret>
 static bool
 FuncConvertBits(JSContext *cx, unsigned argc, Value *vp)
 {
-    CallArgs args = CallArgsFromVp(argc, vp);
+    typedef typename Vret::Elem RetElem;
 
-    if ((args.length() != 1) ||
-       (!args[0].isObject() || !ObjectIsVector<V>(args[0].toObject())))
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() != 1 || !IsVectorObject<V>(args[0]))
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
-    typename Vret::Elem *val =
-        reinterpret_cast<typename Vret::Elem *>(
-            args[0].toObject().as<TypedObject>().typedMem());
 
+    RetElem *val = TypedObjectMemory<RetElem *>(args[0]);
     RootedObject obj(cx, Create<Vret>(cx, val));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 template<typename Vret>
 static bool
 FuncZero(JSContext *cx, unsigned argc, Value *vp)
 {
+    typedef typename Vret::Elem RetElem;
+
     CallArgs args = CallArgsFromVp(argc, vp);
-
     if (args.length() != 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
-    typename Vret::Elem result[Vret::lanes];
+
+    RetElem result[Vret::lanes];
     for (int32_t i = 0; i < Vret::lanes; i++)
-        result[i] = static_cast<typename Vret::Elem>(0);
+        result[i] = RetElem(0);
 
     RootedObject obj(cx, Create<Vret>(cx, result));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 template<typename Vret>
 static bool
 FuncSplat(JSContext *cx, unsigned argc, Value *vp)
 {
-    CallArgs args = CallArgsFromVp(argc, vp);
+    typedef typename Vret::Elem RetElem;
 
-    if ((args.length() != 1) || (!args[0].isNumber())) {
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() != 1 || !args[0].isNumber()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
-    typename Vret::Elem result[Vret::lanes];
-    for (int32_t i = 0; i < Vret::lanes; i++) {
-        typename Vret::Elem arg0;
-        Vret::toType2(cx, args[0], &arg0);
-        result[i] = static_cast<typename Vret::Elem>(arg0);
-    }
+
+    RetElem arg;
+    if (!Vret::toType(cx, args[0], &arg))
+        return false;
+
+    RetElem result[Vret::lanes];
+    for (int32_t i = 0; i < Vret::lanes; i++)
+        result[i] = arg;
 
     RootedObject obj(cx, Create<Vret>(cx, result));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
 Int32x4Bool(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-
-    if ((args.length() != 4) ||
-        (!args[0].isBoolean()) || !args[1].isBoolean() ||
-        (!args[2].isBoolean()) || !args[3].isBoolean())
+    if (args.length() != 4 ||
+        !args[0].isBoolean() || !args[1].isBoolean() ||
+        !args[2].isBoolean() || !args[3].isBoolean())
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
+
     int32_t result[Int32x4::lanes];
     for (int32_t i = 0; i < Int32x4::lanes; i++)
         result[i] = args[i].toBoolean() ? 0xFFFFFFFF : 0x0;
 
     RootedObject obj(cx, Create<Int32x4>(cx, result));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
 Float32x4Clamp(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-
-    if ((args.length() != 3) ||
-        (!args[0].isObject() || !ObjectIsVector<Float32x4>(args[0].toObject())) ||
-        (!args[1].isObject() || !ObjectIsVector<Float32x4>(args[1].toObject())) ||
-        (!args[2].isObject() || !ObjectIsVector<Float32x4>(args[2].toObject())))
+    if (args.length() != 3 || !IsVectorObject<Float32x4>(args[0]) ||
+        !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
-    float *val = reinterpret_cast<float *>(
-        args[0].toObject().as<TypedObject>().typedMem());
-    float *lowerLimit = reinterpret_cast<float *>(
-        args[1].toObject().as<TypedObject>().typedMem());
-    float *upperLimit = reinterpret_cast<float *>(
-        args[2].toObject().as<TypedObject>().typedMem());
+
+    float *val = TypedObjectMemory<float *>(args[0]);
+    float *lowerLimit = TypedObjectMemory<float *>(args[1]);
+    float *upperLimit = TypedObjectMemory<float *>(args[2]);
 
     float result[Float32x4::lanes];
-    result[0] = val[0] < lowerLimit[0] ? lowerLimit[0] : val[0];
-    result[1] = val[1] < lowerLimit[1] ? lowerLimit[1] : val[1];
-    result[2] = val[2] < lowerLimit[2] ? lowerLimit[2] : val[2];
-    result[3] = val[3] < lowerLimit[3] ? lowerLimit[3] : val[3];
-    result[0] = result[0] > upperLimit[0] ? upperLimit[0] : result[0];
-    result[1] = result[1] > upperLimit[1] ? upperLimit[1] : result[1];
-    result[2] = result[2] > upperLimit[2] ? upperLimit[2] : result[2];
-    result[3] = result[3] > upperLimit[3] ? upperLimit[3] : result[3];
+    for (int32_t i = 0; i < Float32x4::lanes; i++) {
+        result[i] = val[i] < lowerLimit[i] ? lowerLimit[i] : val[i];
+        result[i] = result[i] > upperLimit[i] ? upperLimit[i] : result[i];
+    }
+
     RootedObject obj(cx, Create<Float32x4>(cx, result));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 static bool
 Int32x4Select(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-
-    if ((args.length() != 3) ||
-        (!args[0].isObject() || !ObjectIsVector<Int32x4>(args[0].toObject())) ||
-        (!args[1].isObject() || !ObjectIsVector<Float32x4>(args[1].toObject())) ||
-        (!args[2].isObject() || !ObjectIsVector<Float32x4>(args[2].toObject())))
+    if (args.length() != 3 || !IsVectorObject<Int32x4>(args[0]) ||
+        !IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return false;
     }
-    int32_t *val = reinterpret_cast<int32_t *>(
-        args[0].toObject().as<TypedObject>().typedMem());
-    int32_t *tv = reinterpret_cast<int32_t *>(
-        args[1].toObject().as<TypedObject>().typedMem());
-    int32_t *fv = reinterpret_cast<int32_t *>(
-        args[2].toObject().as<TypedObject>().typedMem());
+
+    int32_t *val = TypedObjectMemory<int32_t *>(args[0]);
+    int32_t *tv = TypedObjectMemory<int32_t *>(args[1]);
+    int32_t *fv = TypedObjectMemory<int32_t *>(args[2]);
+
     int32_t tr[Int32x4::lanes];
     for (int32_t i = 0; i < Int32x4::lanes; i++)
         tr[i] = And<int32_t, Int32x4>::apply(val[i], tv[i]);
+
     int32_t fr[Int32x4::lanes];
     for (int32_t i = 0; i < Int32x4::lanes; i++)
         fr[i] = And<int32_t, Int32x4>::apply(Not<int32_t, Int32x4>::apply(val[i], 0), fv[i]);
+
     int32_t orInt[Int32x4::lanes];
     for (int32_t i = 0; i < Int32x4::lanes; i++)
         orInt[i] = Or<int32_t, Int32x4>::apply(tr[i], fr[i]);
-    float *result[Float32x4::lanes];
-    *result = reinterpret_cast<float *>(&orInt);
-    RootedObject obj(cx, Create<Float32x4>(cx, *result));
+
+    float *result = reinterpret_cast<float *>(orInt);
+    RootedObject obj(cx, Create<Float32x4>(cx, result));
     if (!obj)
         return false;
 
     args.rval().setObject(*obj);
     return true;
 }
 
 #define DEFINE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId)     \
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -112,49 +112,48 @@ class SIMDObject : public JSObject
     static bool toString(JSContext *cx, unsigned int argc, jsval *vp);
 };
 
 // These classes exist for use with templates below.
 
 struct Float32x4 {
     typedef float Elem;
     static const int32_t lanes = 4;
-    static const X4TypeDescr::Type type =
-        X4TypeDescr::TYPE_FLOAT32;
+    static const X4TypeDescr::Type type = X4TypeDescr::TYPE_FLOAT32;
 
     static TypeDescr &GetTypeDescr(GlobalObject &global) {
         return global.float32x4TypeDescr().as<TypeDescr>();
     }
     static Elem toType(Elem a) {
         return a;
     }
-    static void toType2(JSContext *cx, JS::Handle<JS::Value> v, Elem *out) {
+    static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
         *out = v.toNumber();
+        return true;
     }
-    static void setReturn(CallArgs &args, float value) {
+    static void setReturn(CallArgs &args, Elem value) {
         args.rval().setDouble(JS::CanonicalizeNaN(value));
     }
 };
 
 struct Int32x4 {
     typedef int32_t Elem;
     static const int32_t lanes = 4;
-    static const X4TypeDescr::Type type =
-        X4TypeDescr::TYPE_INT32;
+    static const X4TypeDescr::Type type = X4TypeDescr::TYPE_INT32;
 
     static TypeDescr &GetTypeDescr(GlobalObject &global) {
         return global.int32x4TypeDescr().as<TypeDescr>();
     }
     static Elem toType(Elem a) {
         return ToInt32(a);
     }
-    static void toType2(JSContext *cx, JS::Handle<JS::Value> v, Elem *out) {
-        ToInt32(cx,v,out);
+    static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
+        return ToInt32(cx, v, out);
     }
-    static void setReturn(CallArgs &args, int32_t value) {
+    static void setReturn(CallArgs &args, Elem value) {
         args.rval().setInt32(value);
     }
 };
 
 template<typename V>
 JSObject *Create(JSContext *cx, typename V::Elem *data);
 
 #define DECLARE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands, Flags, MIRId)                                       \
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1050,24 +1050,24 @@ ShellObjectMetadataCallback(JSContext *c
 
     RootedObject stack(cx, NewDenseEmptyArray(cx));
     if (!stack)
         return false;
 
     static int createdIndex = 0;
     createdIndex++;
 
-    if (!JS_DefineProperty(cx, obj, "index", Int32Value(createdIndex),
-                           JS_PropertyStub, JS_StrictPropertyStub, 0))
+    if (!JS_DefineProperty(cx, obj, "index", createdIndex, 0,
+                           JS_PropertyStub, JS_StrictPropertyStub))
     {
         return false;
     }
 
-    if (!JS_DefineProperty(cx, obj, "stack", ObjectValue(*stack),
-                           JS_PropertyStub, JS_StrictPropertyStub, 0))
+    if (!JS_DefineProperty(cx, obj, "stack", stack, 0,
+                           JS_PropertyStub, JS_StrictPropertyStub))
     {
         return false;
     }
 
     int stackIndex = 0;
     for (NonBuiltinScriptFrameIter iter(cx); !iter.done(); ++iter) {
         if (iter.isFunctionFrame() && iter.compartment() == cx->compartment()) {
             if (!JS_DefinePropertyById(cx, stack, INT_TO_JSID(stackIndex), ObjectValue(*iter.callee()),
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -874,22 +874,22 @@ InitCTypeClass(JSContext* cx, HandleObje
   JS_ASSERT(ctor);
   JS_ASSERT(fnproto);
 
   // Set up ctypes.CType.prototype.
   RootedObject prototype(cx, JS_NewObject(cx, &sCTypeProtoClass, fnproto, parent));
   if (!prototype)
     return nullptr;
 
-  if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return nullptr;
 
-  if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return nullptr;
 
   // Define properties and functions common to all CTypes.
   if (!JS_DefineProperties(cx, prototype, sCTypeProps) ||
       !JS_DefineFunctions(cx, prototype, sCTypeFunctions))
     return nullptr;
 
   if (!JS_FreezeObject(cx, ctor) || !JS_FreezeObject(cx, prototype))
@@ -930,22 +930,22 @@ InitCDataClass(JSContext* cx, HandleObje
   if (!JS_SetPrototype(cx, ctor, CTypeProto))
     return nullptr;
 
   // Set up ctypes.CData.prototype.
   RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, NullPtr(), parent));
   if (!prototype)
     return nullptr;
 
-  if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return nullptr;
 
-  if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return nullptr;
 
   // Define properties and functions common to all CDatas.
   if (!JS_DefineProperties(cx, prototype, sCDataProps) ||
       !JS_DefineFunctions(cx, prototype, sCDataFunctions))
     return nullptr;
 
   if (//!JS_FreezeObject(cx, prototype) || // XXX fixme - see bug 541212!
@@ -995,28 +995,28 @@ InitTypeConstructor(JSContext* cx,
     return false;
 
   // Set up the .prototype and .prototype.constructor properties.
   typeProto.set(JS_NewObject(cx, &sCTypeProtoClass, CTypeProto, parent));
   if (!typeProto)
     return false;
 
   // Define property before proceeding, for GC safety.
-  if (!JS_DefineProperty(cx, obj, "prototype", OBJECT_TO_JSVAL(typeProto),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, obj, "prototype", typeProto,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   if (fns && !JS_DefineFunctions(cx, typeProto, fns))
     return false;
 
   if (!JS_DefineProperties(cx, typeProto, props))
     return false;
 
-  if (!JS_DefineProperty(cx, typeProto, "constructor", OBJECT_TO_JSVAL(obj),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, typeProto, "constructor", obj,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   // Stash ctypes.{Pointer,Array,Struct}Type.prototype on a reserved slot of
   // the type constructor, for faster lookup.
   js::SetFunctionNativeReserved(obj, SLOT_FN_CTORPROTO, OBJECT_TO_JSVAL(typeProto));
 
   // Create an object to serve as the common ancestor for all CData objects
   // created from the given type constructor. This has ctypes.CData.prototype
@@ -1241,33 +1241,32 @@ InitTypeClasses(JSContext* cx, HandleObj
       TYPE_##name, INT_TO_JSVAL(sizeof(type)),                                 \
       INT_TO_JSVAL(ffiType.alignment), &ffiType));                             \
   if (!typeObj_##name)                                                         \
     return false;
 #include "ctypes/typedefs.h"
 
   // Alias 'ctypes.unsigned' as 'ctypes.unsigned_int', since they represent
   // the same type in C.
-  if (!JS_DefineProperty(cx, parent, "unsigned",
-         OBJECT_TO_JSVAL(typeObj_unsigned_int), nullptr, nullptr,
-         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, parent, "unsigned", typeObj_unsigned_int,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   // Create objects representing the special types void_t and voidptr_t.
   RootedObject typeObj(cx,
     CType::DefineBuiltin(cx, parent, "void_t", CTypeProto, CDataProto, "void",
                          TYPE_void_t, JSVAL_VOID, JSVAL_VOID, &ffi_type_void));
   if (!typeObj)
     return false;
 
   typeObj = PointerType::CreateInternal(cx, typeObj);
   if (!typeObj)
     return false;
-  if (!JS_DefineProperty(cx, parent, "voidptr_t", OBJECT_TO_JSVAL(typeObj),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, parent, "voidptr_t", typeObj,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   return true;
 }
 
 bool
 IsCTypesGlobal(JSObject* obj)
 {
@@ -1322,18 +1321,18 @@ using namespace js::ctypes;
 JS_PUBLIC_API(bool)
 JS_InitCTypesClass(JSContext* cx, HandleObject global)
 {
   // attach ctypes property to global object
   RootedObject ctypes(cx, JS_NewObject(cx, &sCTypesGlobalClass, NullPtr(), NullPtr()));
   if (!ctypes)
     return false;
 
-  if (!JS_DefineProperty(cx, global, "ctypes", OBJECT_TO_JSVAL(ctypes),
-         JS_PropertyStub, JS_StrictPropertyStub, JSPROP_READONLY | JSPROP_PERMANENT)){
+  if (!JS_DefineProperty(cx, global, "ctypes", ctypes, JSPROP_READONLY | JSPROP_PERMANENT,
+                         JS_PropertyStub, JS_StrictPropertyStub)){
     return false;
   }
 
   if (!InitTypeClasses(cx, ctypes))
     return false;
 
   // attach API functions and properties
   if (!JS_DefineFunctions(cx, ctypes, sModuleFunctions) ||
@@ -1347,22 +1346,22 @@ JS_InitCTypesClass(JSContext* cx, Handle
 
   RootedObject prototype(cx, JS_NewObject(cx, &sCDataFinalizerProtoClass, NullPtr(), ctypes));
   if (!prototype)
     return false;
 
   if (!JS_DefineFunctions(cx, prototype, sCDataFinalizerFunctions))
     return false;
 
-  if (!JS_DefineProperty(cx, ctor, "prototype", OBJECT_TO_JSVAL(prototype),
-                         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
-    return false;
-
-  if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(ctor),
-                         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, ctor, "prototype", prototype,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+    return false;
+
+  if (!JS_DefineProperty(cx, prototype, "constructor", ctor,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
 
   // Seal the ctypes object, to prevent modification.
   return JS_FreezeObject(cx, ctypes);
 }
 
 JS_PUBLIC_API(void)
@@ -3227,18 +3226,18 @@ CType::Create(JSContext* cx,
   JS_SetReservedSlot(typeObj, SLOT_ALIGN, align);
 
   if (dataProto) {
     // Set up the 'prototype' and 'prototype.constructor' properties.
     RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, parent));
     if (!prototype)
       return nullptr;
 
-    if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj),
-           nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
+    if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
+                           JSPROP_READONLY | JSPROP_PERMANENT))
       return nullptr;
 
     // Set the 'prototype' object.
     //if (!JS_FreezeObject(cx, prototype)) // XXX fixme - see bug 541212!
     //  return nullptr;
     JS_SetReservedSlot(typeObj, SLOT_PROTO, OBJECT_TO_JSVAL(prototype));
   }
 
@@ -3276,18 +3275,18 @@ CType::DefineBuiltin(JSContext* cx,
     return nullptr;
 
   // Create a new CType object with the common properties and slots.
   RootedObject typeObj(cx, Create(cx, typeProto, dataProto, type, nameStr, size, align, ffiType));
   if (!typeObj)
     return nullptr;
 
   // Define the CType as a 'propName' property on 'parent'.
-  if (!JS_DefineProperty(cx, parent, propName, OBJECT_TO_JSVAL(typeObj),
-         nullptr, nullptr, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, parent, propName, typeObj,
+                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
     return nullptr;
 
   return typeObj;
 }
 
 void
 CType::Finalize(JSFreeOp *fop, JSObject* obj)
 {
@@ -4789,18 +4788,18 @@ StructType::DefineInternal(JSContext* cx
 
   // Set up the 'prototype' and 'prototype.constructor' properties.
   // The prototype will reflect the struct fields as properties on CData objects
   // created from this type.
   RootedObject prototype(cx, JS_NewObject(cx, &sCDataProtoClass, dataProto, NullPtr()));
   if (!prototype)
     return false;
 
-  if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj),
-         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
+  if (!JS_DefineProperty(cx, prototype, "constructor", typeObj,
+                         JSPROP_READONLY | JSPROP_PERMANENT))
     return false;
 
   // Create a FieldInfoHash to stash on the type object, and an array to root
   // its constituents. (We cannot simply stash the hash in a reserved slot now
   // to get GC safety for free, since if anything in this function fails we
   // do not want to mutate 'typeObj'.)
   AutoPtr<FieldInfoHash> fields(cx->new_<FieldInfoHash>());
   if (!fields || !fields->init(len)) {
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -103,16 +103,30 @@ size_t
 gc::GetPageFaultCount()
 {
     PROCESS_MEMORY_COUNTERS pmc;
     if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
         return 0;
     return pmc.PageFaultCount;
 }
 
+void *
+gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
+{
+    // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
+    return nullptr;
+}
+
+// Deallocate mapped memory for object.
+void
+gc::DeallocateMappedContent(void *p, size_t length)
+{
+    // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
+}
+
 #elif defined(SOLARIS)
 
 #include <sys/mman.h>
 #include <unistd.h>
 
 #ifndef MAP_NOSYNC
 # define MAP_NOSYNC 0
 #endif
@@ -161,20 +175,37 @@ gc::MarkPagesInUse(JSRuntime *rt, void *
 }
 
 size_t
 gc::GetPageFaultCount()
 {
     return 0;
 }
 
+void *
+gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
+{
+    // Not implemented.
+    return nullptr;
+}
+
+// Deallocate mapped memory for object.
+void
+gc::DeallocateMappedContent(void *p, size_t length)
+{
+    // Not implemented.
+}
+
 #elif defined(XP_UNIX)
 
+#include <algorithm>
 #include <sys/mman.h>
 #include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 void
 gc::InitMemorySubsystem(JSRuntime *rt)
 {
     rt->gcSystemPageSize = rt->gcSystemAllocGranularity = size_t(sysconf(_SC_PAGESIZE));
 }
 
@@ -281,11 +312,72 @@ gc::GetPageFaultCount()
 {
     struct rusage usage;
     int err = getrusage(RUSAGE_SELF, &usage);
     if (err)
         return 0;
     return usage.ru_majflt;
 }
 
+void *
+gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
+{
+#define NEED_PAGE_ALIGNED 0
+    size_t pa_start; // Page aligned starting
+    size_t pa_end; // Page aligned ending
+    size_t pa_size; // Total page aligned size
+    size_t page_size = sysconf(_SC_PAGESIZE); // Page size
+    struct stat st;
+    uint8_t *buf;
+
+    // Make sure file exists and do sanity check for offset and size.
+    if (fstat(fd, &st) < 0 || offset >= (size_t) st.st_size ||
+        length == 0 || length > (size_t) st.st_size - offset)
+        return nullptr;
+
+    // Check for minimal alignment requirement.
+#if NEED_PAGE_ALIGNED
+    alignment = std::max(alignment, page_size);
+#endif
+    if (offset & (alignment - 1))
+        return nullptr;
+
+    // Page aligned starting of the offset.
+    pa_start = offset & ~(page_size - 1);
+    // Calculate page aligned ending by adding one page to the page aligned
+    // starting of data end position(offset + length - 1).
+    pa_end = ((offset + length - 1) & ~(page_size - 1)) + page_size;
+    pa_size = pa_end - pa_start;
+
+    // Ask for a continuous memory location.
+    buf = (uint8_t *) MapMemory(pa_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (buf == MAP_FAILED)
+        return nullptr;
+
+    buf = (uint8_t *) mmap(buf, pa_size, PROT_READ | PROT_WRITE,
+                           MAP_PRIVATE | MAP_FIXED, fd, pa_start);
+    if (buf == MAP_FAILED)
+        return nullptr;
+
+    // Reset the data before target file, which we don't need to see.
+    memset(buf, 0, offset - pa_start);
+
+    // Reset the data after target file, which we don't need to see.
+    memset(buf + (offset - pa_start) + length, 0, pa_end - (offset + length));
+
+    return buf + (offset - pa_start);
+}
+
+void
+gc::DeallocateMappedContent(void *p, size_t length)
+{
+    void *pa_start; // Page aligned starting
+    size_t page_size = sysconf(_SC_PAGESIZE); // Page size
+    size_t total_size; // Total allocated size
+
+    pa_start = (void *)(uintptr_t(p) & ~(page_size - 1));
+    total_size = ((uintptr_t(p) + length) & ~(page_size - 1)) + page_size - uintptr_t(pa_start);
+    munmap(pa_start, total_size);
+}
+
 #else
 #error "Memory mapping functions are not defined for your OS."
 #endif
--- a/js/src/gc/Memory.h
+++ b/js/src/gc/Memory.h
@@ -36,12 +36,21 @@ MarkPagesUnused(JSRuntime *rt, void *p, 
 // platforms.
 bool
 MarkPagesInUse(JSRuntime *rt, void *p, size_t size);
 
 // Returns #(hard faults) + #(soft faults)
 size_t
 GetPageFaultCount();
 
+// Allocate memory mapped content.
+// The offset must be aligned according to alignment requirement.
+void *
+AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment);
+
+// Deallocate memory mapped content.
+void
+DeallocateMappedContent(void *p, size_t length);
+
 } // namespace gc
 } // namespace js
 
 #endif /* gc_Memory_h */
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug995817.js
@@ -0,0 +1,17 @@
+setJitCompilerOption('baseline.usecount.trigger', 1);
+let r;
+(function() {
+     function f() {
+         return (1 + -1 / 0) << null;
+     }
+     assertEq(f(), 0);
+     assertEq(f(), 0);
+
+     function g(x,y) {
+         var a = x|0;
+         var b = y|0;
+         return (a / b + a / b) | 0;
+     }
+     assertEq(g(3,4), 1);
+     assertEq(g(3,4), 1);
+})();
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -100,16 +100,19 @@ class OutOfLineUpdateCache :
 
 // This function is declared here because it needs to instantiate an
 // OutOfLineUpdateCache, but we want to keep it visible inside the
 // CodeGeneratorShared such as we can specialize inline caches in function of
 // the architecture.
 bool
 CodeGeneratorShared::addCache(LInstruction *lir, size_t cacheIndex)
 {
+    if (cacheIndex == SIZE_MAX)
+        return false;
+
     DataPtr<IonCache> cache(this, cacheIndex);
     MInstruction *mir = lir->mirRaw()->toInstruction();
     if (mir->resumePoint())
         cache->setScriptedLocation(mir->block()->info().script(),
                                    mir->resumePoint()->pc());
     else
         cache->setIdempotent();
 
@@ -5507,22 +5510,22 @@ CodeGenerator::visitStoreElementHoleV(LS
         masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
     else
         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
-                                   bool strict);
-typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
-static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
-    FunctionInfo<SetObjectElementFn>(SetObjectElement),
-    FunctionInfo<SetElementParFn>(SetElementPar));
+typedef bool (*SetDenseElementFn)(JSContext *, HandleObject, int32_t, HandleValue,
+                                  bool strict);
+typedef bool (*SetDenseElementParFn)(ForkJoinContext *, HandleObject, int32_t, HandleValue, bool);
+static const VMFunctionsModal SetDenseElementInfo = VMFunctionsModal(
+    FunctionInfo<SetDenseElementFn>(SetDenseElement),
+    FunctionInfo<SetDenseElementParFn>(SetDenseElementPar));
 
 bool
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
 {
     Register object, elements;
     LInstruction *ins = ool->ins();
     const LAllocation *index;
     MIRType valueType;
@@ -5592,21 +5595,21 @@ CodeGenerator::visitOutOfLineStoreElemen
     }
 
     masm.bind(&callStub);
     saveLive(ins);
 
     pushArg(Imm32(current->mir()->strict()));
     pushArg(value);
     if (index->isConstant())
-        pushArg(*index->toConstant());
+        pushArg(Imm32(ToInt32(index)));
     else
-        pushArg(TypedOrValueRegister(MIRType_Int32, ToAnyRegister(index)));
+        pushArg(ToRegister(index));
     pushArg(object);
-    if (!callVM(SetObjectElementInfo, ins))
+    if (!callVM(SetDenseElementInfo, ins))
         return false;
 
     restoreLive(ins);
     masm.jump(ool->rejoin());
     return true;
 }
 
 typedef bool (*ArrayPopShiftFn)(JSContext *, HandleObject, MutableHandleValue);
@@ -6615,16 +6618,23 @@ CodeGenerator::visitCallGetElement(LCall
     if (op == JSOP_GETELEM) {
         return callVM(GetElementInfo, lir);
     } else {
         JS_ASSERT(op == JSOP_CALLELEM);
         return callVM(CallElementInfo, lir);
     }
 }
 
+typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
+                                   bool strict);
+typedef bool (*SetElementParFn)(ForkJoinContext *, HandleObject, HandleValue, HandleValue, bool);
+static const VMFunctionsModal SetObjectElementInfo = VMFunctionsModal(
+    FunctionInfo<SetObjectElementFn>(SetObjectElement),
+    FunctionInfo<SetElementParFn>(SetElementPar));
+
 bool
 CodeGenerator::visitCallSetElement(LCallSetElement *lir)
 {
     pushArg(Imm32(current->mir()->strict()));
     pushArg(ToValue(lir, LCallSetElement::Value));
     pushArg(ToValue(lir, LCallSetElement::Index));
     pushArg(ToRegister(lir->getOperand(0)));
     return callVM(SetObjectElementInfo, lir);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4066,23 +4066,42 @@ class MMul : public MBinaryArithInstruct
 class MDiv : public MBinaryArithInstruction
 {
     bool canBeNegativeZero_;
     bool canBeNegativeOverflow_;
     bool canBeDivideByZero_;
     bool canBeNegativeDividend_;
     bool unsigned_;
 
+    // A Division can be truncated in 4 differents ways:
+    //   1. Ignore Infinities (x / 0 --> 0).
+    //   2. Ignore overflow (INT_MIN / -1 == (INT_MAX + 1) --> INT_MIN)
+    //   3. Ignore negative zeros. (-0 --> 0)
+    //   4. Ignore remainder. (3 / 4 --> 0)
+    //
+    // isTruncatedIndirectly is used to represent that we are interested in the
+    // truncated result, but only if they it can safely flow in operations which
+    // are computed modulo 2^32, such as (2) and (3).
+    //
+    // A division can return either Infinities (1) or a remainder (4) when both
+    // operands are integers. Infinities are not safe, as they would have
+    // absorbed other math operations. Remainders are not safe, as multiple can
+    // add up to integers. This implies that we need to distinguish between a
+    // division which is truncated directly (isTruncated) or which flow into
+    // truncated operations (isTruncatedIndirectly).
+    bool isTruncatedIndirectly_;
+
     MDiv(MDefinition *left, MDefinition *right, MIRType type)
       : MBinaryArithInstruction(left, right),
         canBeNegativeZero_(true),
         canBeNegativeOverflow_(true),
         canBeDivideByZero_(true),
         canBeNegativeDividend_(true),
-        unsigned_(false)
+        unsigned_(false),
+        isTruncatedIndirectly_(false)
     {
         if (type != MIRType_Value)
             specialization_ = type;
         setResultType(type);
     }
 
   public:
     INSTRUCTION_HEADER(Div)
@@ -4128,16 +4147,36 @@ class MDiv : public MBinaryArithInstruct
     bool canBeNegativeDividend() const {
         return canBeNegativeDividend_;
     }
 
     bool isUnsigned() const {
         return unsigned_;
     }
 
+    bool isTruncatedIndirectly() const {
+        return isTruncatedIndirectly_;
+    }
+    void setTruncatedIndirectly(bool truncate) {
+        isTruncatedIndirectly_ = truncate;
+    }
+
+    bool canTruncateInfinities() const {
+        return isTruncated();
+    }
+    bool canTruncateRemainder() const {
+        return isTruncated();
+    }
+    bool canTruncateOverflow() const {
+        return isTruncated() || isTruncatedIndirectly();
+    }
+    bool canTruncateNegativeZero() const {
+        return isTruncated() || isTruncatedIndirectly();
+    }
+
     bool isFloat32Commutative() const { return true; }
 
     void computeRange(TempAllocator &alloc);
     bool fallible() const;
     bool truncate();
     void collectRangeInfoPreTrunc();
 };
 
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -271,16 +271,24 @@ jit::SetElementPar(ForkJoinContext *cx, 
     // for certain deoptimizing behaviors, such as marking having written to
     // holes and non-indexed element accesses. We don't do that here, as we
     // can't modify any TI state anyways. If we need to add a new type, we
     // would bail out.
     RootedValue v(cx, value);
     return baseops::SetPropertyHelper<ParallelExecution>(cx, obj, obj, id, 0, &v, strict);
 }
 
+bool
+jit::SetDenseElementPar(ForkJoinContext *cx, HandleObject obj, int32_t index, HandleValue value,
+                        bool strict)
+{
+    RootedValue indexVal(cx, Int32Value(index));
+    return SetElementPar(cx, obj, indexVal, value, strict);
+}
+
 JSString *
 jit::ConcatStringsPar(ForkJoinContext *cx, HandleString left, HandleString right)
 {
     return ConcatStrings<NoGC>(cx, left, right);
 }
 
 JSFlatString *
 jit::IntToStringPar(ForkJoinContext *cx, int i)
--- a/js/src/jit/ParallelFunctions.h
+++ b/js/src/jit/ParallelFunctions.h
@@ -28,16 +28,18 @@ bool InterruptCheckPar(ForkJoinContext *
 // generation.
 JSObject *ExtendArrayPar(ForkJoinContext *cx, JSObject *array, uint32_t length);
 
 // Set properties and elements on thread local objects.
 bool SetPropertyPar(ForkJoinContext *cx, HandleObject obj, HandlePropertyName name,
                     HandleValue value, bool strict, jsbytecode *pc);
 bool SetElementPar(ForkJoinContext *cx, HandleObject obj, HandleValue index,
                    HandleValue value, bool strict);
+bool SetDenseElementPar(ForkJoinContext *cx, HandleObject obj, int32_t index,
+                        HandleValue value, bool strict);
 
 // String related parallel functions. These tend to call existing VM functions
 // that take a ThreadSafeContext.
 JSString *ConcatStringsPar(ForkJoinContext *cx, HandleString left, HandleString right);
 JSFlatString *IntToStringPar(ForkJoinContext *cx, int i);
 JSString *DoubleToStringPar(ForkJoinContext *cx, double d);
 JSString *PrimitiveToStringPar(ForkJoinContext *cx, HandleValue input);
 bool StringToNumberPar(ForkJoinContext *cx, JSString *str, double *out);
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -2212,17 +2212,38 @@ MMul::truncate()
 
     return false;
 }
 
 bool
 MDiv::truncate()
 {
     // Remember analysis, needed to remove negative zero checks.
-    setTruncated(true);
+    setTruncatedIndirectly(true);
+
+    // Check if this division only flows in bitwise instructions.
+    if (!isTruncated()) {
+        bool allUsesExplictlyTruncate = true;
+        for (MUseDefIterator use(this); allUsesExplictlyTruncate && use; use++) {
+            switch (use.def()->op()) {
+              case MDefinition::Op_BitAnd:
+              case MDefinition::Op_BitOr:
+              case MDefinition::Op_BitXor:
+              case MDefinition::Op_Lsh:
+              case MDefinition::Op_Rsh:
+              case MDefinition::Op_Ursh:
+                break;
+              default:
+                allUsesExplictlyTruncate = false;
+            }
+        }
+
+        if (allUsesExplictlyTruncate)
+            setTruncated(true);
+    }
 
     // Divisions where the lhs and rhs are unsigned and the result is
     // truncated can be lowered more efficiently.
     if (specialization() == MIRType_Int32 && tryUseUnsignedOperands()) {
         unsigned_ = true;
         return true;
     }
 
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -1032,16 +1032,55 @@ Recompile(JSContext *cx)
 
     MethodStatus status = Recompile(cx, script, nullptr, nullptr, isConstructing);
     if (status == Method_Error)
         return false;
 
     return true;
 }
 
+bool
+SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
+                bool strict)
+{
+    // This function is called from Ion code for StoreElementHole's OOL path.
+    // In this case we know the object is native, has no indexed properties
+    // and we can use setDenseElement instead of setDenseElementWithType.
+
+    MOZ_ASSERT(obj->isNative());
+    MOZ_ASSERT(!obj->isIndexed());
+
+    JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
+    do {
+        if (index < 0)
+            break;
+        bool isArray = obj->is<ArrayObject>();
+        if (isArray && !obj->as<ArrayObject>().lengthIsWritable())
+            break;
+        uint32_t idx = uint32_t(index);
+        result = obj->ensureDenseElements(cx, idx, 1);
+        if (result != JSObject::ED_OK)
+            break;
+        if (isArray) {
+            ArrayObject &arr = obj->as<ArrayObject>();
+            if (idx >= arr.length())
+                arr.setLengthInt32(idx + 1);
+        }
+        obj->setDenseElement(idx, value);
+        return true;
+    } while (false);
+
+    if (result == JSObject::ED_FAILED)
+        return false;
+    MOZ_ASSERT(result == JSObject::ED_SPARSE);
+
+    RootedValue indexVal(cx, Int32Value(index));
+    return SetObjectElement(cx, obj, indexVal, value, strict);
+}
+
 #ifdef DEBUG
 void
 AssertValidObjectPtr(JSContext *cx, JSObject *obj)
 {
     // Check what we can, so that we'll hopefully assert/crash if we get a
     // bogus object (pointer).
     JS_ASSERT(obj->compartment() == cx->compartment());
     JS_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -672,16 +672,19 @@ JSObject *CreateDerivedTypedObj(JSContex
                                 HandleObject owner, int32_t offset);
 
 bool Recompile(JSContext *cx);
 JSString *RegExpReplace(JSContext *cx, HandleString string, HandleObject regexp,
                         HandleString repl);
 JSString *StringReplace(JSContext *cx, HandleString string, HandleString pattern,
                         HandleString repl);
 
+bool SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue value,
+                     bool strict);
+
 #ifdef DEBUG
 void AssertValidObjectPtr(JSContext *cx, JSObject *obj);
 void AssertValidStringPtr(JSContext *cx, JSString *str);
 void AssertValidValue(JSContext *cx, Value *v);
 #endif
 
 } // namespace jit
 } // namespace js
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -519,60 +519,59 @@ bool
 CodeGeneratorARM::divICommon(MDiv *mir, Register lhs, Register rhs, Register output,
                              LSnapshot *snapshot, Label &done)
 {
     if (mir->canBeNegativeOverflow()) {
         // Handle INT32_MIN / -1;
         // The integer division will give INT32_MIN, but we want -(double)INT32_MIN.
         masm.ma_cmp(lhs, Imm32(INT32_MIN)); // sets EQ if lhs == INT32_MIN
         masm.ma_cmp(rhs, Imm32(-1), Assembler::Equal); // if EQ (LHS == INT32_MIN), sets EQ if rhs == -1
-        if (mir->isTruncated()) {
+        if (mir->canTruncateOverflow()) {
             // (-INT32_MIN)|0 = INT32_MIN
             Label skip;
             masm.ma_b(&skip, Assembler::NotEqual);
             masm.ma_mov(Imm32(INT32_MIN), output);
             masm.ma_b(&done);
             masm.bind(&skip);
         } else {
             JS_ASSERT(mir->fallible());
             if (!bailoutIf(Assembler::Equal, snapshot))
                 return false;
         }
     }
 
-    // 0/X (with X < 0) is bad because both of these values *should* be doubles, and
-    // the result should be -0.0, which cannot be represented in integers.
-    // X/0 is bad because it will give garbage (or abort), when it should give
-    // either \infty, -\infty or NAN.
-
-    // Prevent 0 / X (with X < 0) and X / 0
-    // testing X / Y.  Compare Y with 0.
-    // There are three cases: (Y < 0), (Y == 0) and (Y > 0)
-    // If (Y < 0), then we compare X with 0, and bail if X == 0
-    // If (Y == 0), then we simply want to bail.  Since this does not set
-    // the flags necessary for LT to trigger, we don't test X, and take the
-    // bailout because the EQ flag is set.
-    // if (Y > 0), we don't set EQ, and we don't trigger LT, so we don't take the bailout.
-    if (mir->canBeDivideByZero() || mir->canBeNegativeZero()) {
+    // Handle divide by zero.
+    if (mir->canBeDivideByZero()) {
         masm.ma_cmp(rhs, Imm32(0));
-        masm.ma_cmp(lhs, Imm32(0), Assembler::LessThan);
-        if (mir->isTruncated()) {
-            // Infinity|0 == 0 and -0|0 == 0
+        if (mir->canTruncateInfinities()) {
+            // Infinity|0 == 0
             Label skip;
             masm.ma_b(&skip, Assembler::NotEqual);
             masm.ma_mov(Imm32(0), output);
             masm.ma_b(&done);
             masm.bind(&skip);
         } else {
             JS_ASSERT(mir->fallible());
             if (!bailoutIf(Assembler::Equal, snapshot))
                 return false;
         }
     }
 
+    // Handle negative 0.
+    if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) {
+        Label nonzero;
+        masm.ma_cmp(lhs, Imm32(0));
+        masm.ma_b(&nonzero, Assembler::NotEqual);
+        masm.ma_cmp(rhs, Imm32(0));
+        JS_ASSERT(mir->fallible());
+        if (!bailoutIf(Assembler::LessThan, snapshot))
+            return false;
+        masm.bind(&nonzero);
+    }
+
     return true;
 }
 
 bool
 CodeGeneratorARM::visitDivI(LDivI *ins)
 {
     // Extract the registers from this instruction
     Register lhs = ToRegister(ins->lhs());
@@ -580,17 +579,17 @@ CodeGeneratorARM::visitDivI(LDivI *ins)
     Register temp = ToRegister(ins->getTemp(0));
     Register output = ToRegister(ins->output());
     MDiv *mir = ins->mir();
 
     Label done;
     if (!divICommon(mir, lhs, rhs, output, ins->snapshot(), done))
         return false;
 
-    if (mir->isTruncated()) {
+    if (mir->canTruncateRemainder()) {
         masm.ma_sdiv(lhs, rhs, output);
     } else {
         masm.ma_sdiv(lhs, rhs, ScratchRegister);
         masm.ma_mul(ScratchRegister, rhs, temp);
         masm.ma_cmp(lhs, temp);
         if (!bailoutIf(Assembler::NotEqual, ins->snapshot()))
             return false;
         masm.ma_mov(ScratchRegister, output);
@@ -622,17 +621,17 @@ CodeGeneratorARM::visitSoftDivI(LSoftDiv
     masm.setupAlignedABICall(2);
     masm.passABIArg(lhs);
     masm.passABIArg(rhs);
     if (gen->compilingAsmJS())
         masm.callWithABI(AsmJSImm_aeabi_idivmod);
     else
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, __aeabi_idivmod));
     // idivmod returns the quotient in r0, and the remainder in r1.
-    if (!mir->isTruncated()) {
+    if (!mir->canTruncateRemainder()) {
         JS_ASSERT(mir->fallible());
         masm.ma_cmp(r1, Imm32(0));
         if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
             return false;
     }
 
     masm.bind(&done);
 
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -249,16 +249,18 @@ class CodeGeneratorShared : public LInst
         size_t dataOffset = runtimeData_.length();
         masm.propagateOOM(runtimeData_.appendN(0, size));
         return dataOffset;
     }
 
     template <typename T>
     inline size_t allocateCache(const T &cache) {
         size_t index = allocateCache(cache, sizeof(mozilla::AlignedStorage2<T>));
+        if (masm.oom())
+            return SIZE_MAX;
         // Use the copy constructor on the allocated space.
         JS_ASSERT(index == cacheList_.back());
         new (&runtimeData_[index]) T(cache);
         return index;
     }
 
   protected:
     // Encodes an LSnapshot into the compressed snapshot buffer, returning
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -928,17 +928,17 @@ CodeGeneratorX86Shared::visitDivI(LDivI 
     // Put the lhs in eax, for either the negative overflow case or the regular
     // divide case.
     if (lhs != eax)
         masm.mov(lhs, eax);
 
     // Handle divide by zero.
     if (mir->canBeDivideByZero()) {
         masm.testl(rhs, rhs);
-        if (mir->isTruncated()) {
+        if (mir->canTruncateInfinities()) {
             // Truncated division by zero is zero (Infinity|0 == 0)
             if (!ool)
                 ool = new(alloc()) ReturnZero(output);
             masm.j(Assembler::Zero, ool->entry());
         } else {
             JS_ASSERT(mir->fallible());
             if (!bailoutIf(Assembler::Zero, ins->snapshot()))
                 return false;
@@ -946,46 +946,46 @@ CodeGeneratorX86Shared::visitDivI(LDivI 
     }
 
     // Handle an integer overflow exception from -2147483648 / -1.
     if (mir->canBeNegativeOverflow()) {
         Label notmin;
         masm.cmpl(lhs, Imm32(INT32_MIN));
         masm.j(Assembler::NotEqual, &notmin);
         masm.cmpl(rhs, Imm32(-1));
-        if (mir->isTruncated()) {
+        if (mir->canTruncateOverflow()) {
             // (-INT32_MIN)|0 == INT32_MIN and INT32_MIN is already in the
             // output register (lhs == eax).
             masm.j(Assembler::Equal, &done);
         } else {
             JS_ASSERT(mir->fallible());
             if (!bailoutIf(Assembler::Equal, ins->snapshot()))
                 return false;
         }
         masm.bind(&notmin);
     }
 
     // Handle negative 0.
-    if (!mir->isTruncated() && mir->canBeNegativeZero()) {
+    if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) {
         Label nonzero;
         masm.testl(lhs, lhs);
         masm.j(Assembler::NonZero, &nonzero);
         masm.cmpl(rhs, Imm32(0));
         if (!bailoutIf(Assembler::LessThan, ins->snapshot()))
             return false;
         masm.bind(&nonzero);
     }
 
     // Sign extend the lhs into edx to make (edx:eax), since idiv is 64-bit.
     if (lhs != eax)
         masm.mov(lhs, eax);
     masm.cdq();
     masm.idiv(rhs);
 
-    if (!mir->isTruncated()) {
+    if (!mir->canTruncateRemainder()) {
         // If the remainder is > 0, bailout since this must be a double.
         masm.testl(remainder, remainder);
         if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
             return false;
     }
 
     masm.bind(&done);
 
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -40,16 +40,17 @@ UNIFIED_SOURCES += [
     'testHashTableInit.cpp',
     'testIndexToString.cpp',
     'testIntern.cpp',
     'testIntString.cpp',
     'testIntTypesABI.cpp',
     'testJSEvaluateScript.cpp',
     'testLookup.cpp',
     'testLooselyEqual.cpp',
+    'testMappedArrayBuffer.cpp',
     'testNewObject.cpp',
     'testNullRoot.cpp',
     'testObjectEmulatingUndefined.cpp',
     'testOOM.cpp',
     'testOps.cpp',
     'testOriginPrincipals.cpp',
     'testParseJSON.cpp',
     'testPersistentRooted.cpp',
--- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp
+++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp
@@ -41,19 +41,18 @@ BEGIN_TEST(testAddPropertyHook)
     JS::RootedValue proto(cx, OBJECT_TO_JSVAL(obj));
     JS_InitClass(cx, global, obj, &AddPropertyClass, nullptr, 0, nullptr, nullptr, nullptr,
                  nullptr);
 
     obj = JS_NewArrayObject(cx, 0);
     CHECK(obj);
     JS::RootedValue arr(cx, OBJECT_TO_JSVAL(obj));
 
-    CHECK(JS_DefineProperty(cx, global, "arr", arr,
-                            JS_PropertyStub, JS_StrictPropertyStub,
-                            JSPROP_ENUMERATE));
+    CHECK(JS_DefineProperty(cx, global, "arr", arr, JSPROP_ENUMERATE,
+                            JS_PropertyStub, JS_StrictPropertyStub));
 
     for (int i = 0; i < ExpectedCount; ++i) {
         obj = JS_NewObject(cx, &AddPropertyClass, JS::NullPtr(), JS::NullPtr());
         CHECK(obj);
         JS::RootedValue vobj(cx, OBJECT_TO_JSVAL(obj));
         JS::RootedObject arrObj(cx, JSVAL_TO_OBJECT(arr));
         CHECK(JS_DefineElement(cx, arrObj, i, vobj,
                                JS_PropertyStub, JS_StrictPropertyStub,
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -20,18 +20,18 @@ static const JSClass global_class = {
     JS_ConvertStub,
     nullptr,
     nullptr,
     nullptr,
     nullptr,
     JS_GlobalObjectTraceHook
 };
 
-static JSObject *trusted_glob = nullptr;
-static JSObject *trusted_fun = nullptr;
+static JS::Heap<JSObject *> trusted_glob;
+static JS::Heap<JSObject *> trusted_fun;
 
 static bool
 CallTrusted(JSContext *cx, unsigned argc, jsval *vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 
     if (!JS_SaveFrameChain(cx))
         return false;
@@ -48,38 +48,38 @@ CallTrusted(JSContext *cx, unsigned argc
 
 BEGIN_TEST(testChromeBuffer)
 {
     JS_SetTrustedPrincipals(rt, &system_principals);
 
     trusted_glob = JS_NewGlobalObject(cx, &global_class, &system_principals, JS::FireOnNewGlobalHook);
     CHECK(trusted_glob);
 
-    if (!JS_AddNamedObjectRoot(cx, &trusted_glob, "trusted-global"))
+    if (!JS::AddNamedObjectRoot(cx, &trusted_glob, "trusted-global"))
         return false;
 
     JS::RootedFunction fun(cx);
 
     /*
      * Check that, even after untrusted content has exhausted the stack, code
      * compiled with "trusted principals" can run using reserved trusted-only
      * buffer space.
      */
     {
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "x";
             const char *bytes = "return x ? 1 + trusted(x-1) : 0";
-            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
+            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
                                            bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
-            if (!JS_AddNamedObjectRoot(cx, &trusted_fun, "trusted-function"))
+            if (!JS::AddNamedObjectRoot(cx, &trusted_fun, "trusted-function"))
                 return false;
         }
 
         JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
         CHECK(JS_WrapValue(cx, &v));
 
         const char *paramName = "trusted";
         const char *bytes = "try {                                      "
@@ -109,17 +109,17 @@ BEGIN_TEST(testChromeBuffer)
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "untrusted";
             const char *bytes = "try {                                  "
                                 "  untrusted();                         "
                                 "} catch (e) {                          "
                                 "  return 'From trusted: ' + e;         "
                                 "}                                      ";
-            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
+            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
                                            bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
         }
 
         JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
@@ -146,17 +146,17 @@ BEGIN_TEST(testChromeBuffer)
     /*
      * Check that JS_SaveFrameChain called on the way from content to chrome
      * (say, as done by XPCJSContextSTack::Push) works.
      */
     {
         {
             JSAutoCompartment ac(cx, trusted_glob);
             const char *bytes = "return 42";
-            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
+            JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             CHECK(fun = JS_CompileFunction(cx, global, "trusted", 0, nullptr,
                                            bytes, strlen(bytes), options));
             trusted_fun = JS_GetFunctionObject(fun);
         }
 
         JS::RootedFunction fun(cx, JS_NewFunction(cx, CallTrusted, 0, 0, global, "callTrusted"));
@@ -177,13 +177,15 @@ BEGIN_TEST(testChromeBuffer)
         JS::RootedValue rval(cx);
         CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, arg, &rval));
         CHECK(JSVAL_TO_INT(rval) == 42);
     }
 
     return true;
 }
 virtual void uninit() {
-    JS_RemoveObjectRoot(cx, &trusted_glob);
-    JS_RemoveObjectRoot(cx, &trusted_fun);
+    trusted_glob = nullptr;
+    trusted_fun = nullptr;
+    JS::RemoveObjectRoot(cx, &trusted_glob);
+    JS::RemoveObjectRoot(cx, &trusted_fun);
     JSAPITest::uninit();
 }
 END_TEST(testChromeBuffer)
--- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
+++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp
@@ -29,26 +29,26 @@ BEGIN_TEST(testDefineGetterSetterNonEnum
 
     JSFunction *funSet = JS_NewFunction(cx, NativeGetterSetter, 1, 0, JS::NullPtr(), "set");
     CHECK(funSet);
     JS::RootedObject funSetObj(cx, JS_GetFunctionObject(funSet));
     JS::RootedValue vset(cx, OBJECT_TO_JSVAL(funSetObj));
 
     JS::RootedObject vObject(cx, JSVAL_TO_OBJECT(vobj));
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
-                            JSVAL_VOID,
+                            JS::UndefinedHandleValue,
+                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE,
                             JS_DATA_TO_FUNC_PTR(JSPropertyOp, (JSObject*) funGetObj),
-                            JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, (JSObject*) funSetObj),
-                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE));
+                            JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, (JSObject*) funSetObj)));
 
     CHECK(JS_DefineProperty(cx, vObject, PROPERTY_NAME,
-                            JSVAL_VOID,
+                            JS::UndefinedHandleValue,
+                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_PERMANENT,
                             JS_DATA_TO_FUNC_PTR(JSPropertyOp, (JSObject*) funGetObj),
-                            JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, (JSObject*) funSetObj),
-                            JSPROP_GETTER | JSPROP_SETTER | JSPROP_PERMANENT));
+                            JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, (JSObject*) funSetObj)));
 
     JS::Rooted<JSPropertyDescriptor> desc(cx);
     CHECK(JS_GetOwnPropertyDescriptor(cx, vObject, PROPERTY_NAME, 0, &desc));
     CHECK(desc.object());
     CHECK(desc.hasGetterObject());
     CHECK(desc.hasSetterObject());
     CHECK(desc.isPermanent());
     CHECK(!desc.isEnumerable());
--- a/js/src/jsapi-tests/testDefineProperty.cpp
+++ b/js/src/jsapi-tests/testDefineProperty.cpp
@@ -12,12 +12,12 @@ BEGIN_TEST(testDefineProperty_bug564344)
     JS::RootedValue x(cx);
     EVAL("function f() {}\n"
          "var x = {p: f};\n"
          "x.p();  // brand x's scope\n"
          "x;", &x);
 
     JS::RootedObject obj(cx, JSVAL_TO_OBJECT(x));
     for (int i = 0; i < 2; i++)
-        CHECK(JS_DefineProperty(cx, obj, "q", JSVAL_VOID, nullptr, nullptr, JSPROP_SHARED));
+        CHECK(JS_DefineProperty(cx, obj, "q", JS::UndefinedHandleValue, JSPROP_SHARED));
     return true;
 }
 END_TEST(testDefineProperty_bug564344)
--- a/js/src/jsapi-tests/testGCExactRooting.cpp
+++ b/js/src/jsapi-tests/testGCExactRooting.cpp
@@ -10,14 +10,14 @@
 BEGIN_TEST(testGCExactRooting)
 {
     JS::RootedObject rootCx(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
     JS::RootedObject rootRt(cx->runtime(), JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
 
     JS_GC(cx->runtime());
 
     /* Use the objects we just created to ensure that they are still alive. */
-    JS_DefineProperty(cx, rootCx, "foo", JS::DoubleValue(0), nullptr, nullptr, 0);
-    JS_DefineProperty(cx, rootRt, "foo", JS::DoubleValue(0), nullptr, nullptr, 0);
+    JS_DefineProperty(cx, rootCx, "foo", JS::UndefinedHandleValue, 0);
+    JS_DefineProperty(cx, rootRt, "foo", JS::UndefinedHandleValue, 0);
 
     return true;
 }
 END_TEST(testGCExactRooting)
--- a/js/src/jsapi-tests/testLookup.cpp
+++ b/js/src/jsapi-tests/testLookup.cpp
@@ -82,17 +82,17 @@ static const JSClass document_class = {
     JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, (JSResolveOp) document_resolve, JS_ConvertStub
 };
 
 BEGIN_TEST(testLookup_bug570195)
 {
     JS::RootedObject obj(cx, JS_NewObject(cx, &document_class, JS::NullPtr(), JS::NullPtr()));
     CHECK(obj);
-    CHECK(JS_DefineProperty(cx, global, "document", OBJECT_TO_JSVAL(obj), nullptr, nullptr, 0));
+    CHECK(JS_DefineProperty(cx, global, "document", obj, 0));
     JS::RootedValue v(cx);
     EVAL("document.all ? true : false", &v);
     CHECK_SAME(v, JSVAL_FALSE);
     EVAL("document.hasOwnProperty('all')", &v);
     CHECK_SAME(v, JSVAL_TRUE);
     return true;
 }
 END_TEST(testLookup_bug570195)
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testMappedArrayBuffer.cpp
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+
+#ifdef XP_UNIX
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "jsfriendapi.h"
+#include "js/StructuredClone.h"
+#include "jsapi-tests/tests.h"
+#include "vm/ArrayBufferObject.h"
+
+const char test_data[] = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+const char test_filename[] = "temp-bug945152_MappedArrayBuffer";
+
+BEGIN_TEST(testMappedArrayBuffer_bug945152)
+{
+    TempFile test_file;
+    FILE *test_stream = test_file.open(test_filename);
+    CHECK(fputs(test_data, test_stream) != EOF);
+    test_file.close();
+
+    // Offset 0.
+    CHECK(TestCreateObject(0, 12));
+
+    // Aligned offset.
+    CHECK(TestCreateObject(8, 12));
+
+    // Unaligned offset.
+    CHECK(CreateNewObject(11, 12) == nullptr);
+
+    // Offset + length greater than file size.
+    CHECK(CreateNewObject(8, sizeof(test_data) - 7) == nullptr);
+
+    // Release the mapped content.
+    CHECK(TestReleaseContents());
+
+    // Neuter mapped array buffer.
+    CHECK(TestNeuterObject());
+
+    // Clone mapped array buffer.
+    CHECK(TestCloneObject());
+
+    // Steal mapped array buffer contents.
+    CHECK(TestStealContents());
+
+    // Transfer mapped array buffer contents.
+    CHECK(TestTransferObject());
+
+    test_file.remove();
+
+    return true;
+}
+
+JSObject *CreateNewObject(const int offset, const int length)
+{
+    int fd = open(test_filename, O_RDONLY);
+    void *ptr = JS_CreateMappedArrayBufferContents(fd, offset, length);
+    close(fd);
+    if (!ptr)
+        return nullptr;
+    JSObject *obj = JS_NewMappedArrayBufferWithContents(cx, length, ptr);
+
+    return obj;
+}
+
+bool VerifyObject(JS::HandleObject obj, const int offset, const int length, const bool mapped)
+{
+    CHECK(obj);
+    CHECK(JS_IsArrayBufferObject(obj));
+    CHECK_EQUAL(JS_GetArrayBufferByteLength(obj), length);
+    if (mapped)
+        CHECK(JS_IsMappedArrayBufferObject(obj));
+    else
+        CHECK(!JS_IsMappedArrayBufferObject(obj));
+    const char *data = reinterpret_cast<const char *>(JS_GetArrayBufferData(obj));
+    CHECK(data);
+    CHECK(memcmp(data, test_data + offset, length) == 0);
+
+    return true;
+}
+
+bool TestCreateObject(const int offset, const int length)
+{
+    JS::RootedObject obj(cx, CreateNewObject(offset, length));
+    CHECK(VerifyObject(obj, offset, length, true));
+
+    return true;
+}
+
+bool TestReleaseContents()
+{
+    int fd = open(test_filename, O_RDONLY);
+    void *ptr = JS_CreateMappedArrayBufferContents(fd, 0, 12);
+    close(fd);
+    if (!ptr)
+        return false;
+    JS_ReleaseMappedArrayBufferContents(ptr, 12);
+
+    return true;
+}
+
+bool TestNeuterObject()
+{
+    JS::RootedObject obj(cx, CreateNewObject(8, 12));
+    CHECK(obj);
+    JS_NeuterArrayBuffer(cx, obj);
+    CHECK(isNeutered(obj));
+
+    return true;
+}
+
+bool TestCloneObject()
+{
+    JS::RootedObject obj1(cx, CreateNewObject(8, 12));
+    CHECK(obj1);
+    JSAutoStructuredCloneBuffer cloned_buffer;
+    JS::RootedValue v1(cx, OBJECT_TO_JSVAL(obj1));
+    const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx);
+    CHECK(cloned_buffer.write(cx, v1, callbacks, nullptr));
+    JS::RootedValue v2(cx);
+    CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr));
+    JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2));
+    CHECK(VerifyObject(obj2, 8, 12, false));
+
+    return true;
+}
+
+bool TestStealContents()
+{
+    JS::RootedObject obj(cx, CreateNewObject(8, 12));
+    CHECK(obj);
+    void *contents = JS_StealArrayBufferContents(cx, obj);
+    CHECK(contents);
+    CHECK(memcmp(contents, test_data + 8, 12) == 0);
+    CHECK(isNeutered(obj));
+
+    return true;
+}
+
+bool TestTransferObject()
+{
+    JS::RootedObject obj1(cx, CreateNewObject(8, 12));
+    CHECK(obj1);
+    JS::RootedValue v1(cx, OBJECT_TO_JSVAL(obj1));
+
+    // Create an Array of transferable values.
+    JS::AutoValueVector argv(cx);
+    argv.append(v1);
+    JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::subarray(argv, 0, 1)));
+    CHECK(obj);
+    JS::RootedValue transferable(cx, OBJECT_TO_JSVAL(obj));
+
+    JSAutoStructuredCloneBuffer cloned_buffer;
+    const JSStructuredCloneCallbacks *callbacks = js::GetContextStructuredCloneCallbacks(cx);
+    CHECK(cloned_buffer.write(cx, v1, transferable, callbacks, nullptr));
+    JS::RootedValue v2(cx);
+    CHECK(cloned_buffer.read(cx, &v2, callbacks, nullptr));
+    JS::RootedObject obj2(cx, JSVAL_TO_OBJECT(v2));
+    CHECK(VerifyObject(obj2, 8, 12, true));
+    CHECK(isNeutered(obj1));
+
+    return true;
+}
+
+bool isNeutered(JS::HandleObject obj)
+{
+    JS::RootedValue v(cx);
+    return JS_GetProperty(cx, obj, "byteLength", &v) && v.toInt32() == 0;
+}
+
+static void GC(JSContext *cx)
+{
+    JS_GC(JS_GetRuntime(cx));
+    // Trigger another to wait for background finalization to end.
+    JS_GC(JS_GetRuntime(cx));
+}
+
+END_TEST(testMappedArrayBuffer_bug945152)
+#endif
--- a/js/src/jsapi-tests/testNullRoot.cpp
+++ b/js/src/jsapi-tests/testNullRoot.cpp
@@ -4,26 +4,30 @@
 /* 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 "jsapi-tests/tests.h"
 
 BEGIN_TEST(testNullRoot)
 {
-    JS::RootedObject obj(cx);
-    CHECK(JS_AddObjectRoot(cx, obj.address()));
+    obj = nullptr;
+    CHECK(JS::AddObjectRoot(cx, &obj));
 
-    JS::RootedString str(cx);
-    CHECK(JS_AddStringRoot(cx, str.address()));
+    str = nullptr;
+    CHECK(JS::AddStringRoot(cx, &str));
 
-    JS::RootedScript script(cx);
-    CHECK(JS_AddNamedScriptRoot(cx, script.address(), "testNullRoot's script"));
+    script = nullptr;
+    CHECK(JS::AddNamedScriptRoot(cx, &script, "testNullRoot's script"));
 
     // This used to crash because obj was nullptr.
     JS_GC(cx->runtime());
 
-    JS_RemoveObjectRoot(cx, obj.address());
-    JS_RemoveStringRoot(cx, str.address());
-    JS_RemoveScriptRoot(cx, script.address());
+    JS::RemoveObjectRoot(cx, &obj);
+    JS::RemoveStringRoot(cx, &str);
+    JS::RemoveScriptRoot(cx, &script);
     return true;
 }
+
+JS::Heap<JSObject *> obj;
+JS::Heap<JSString *> str;
+JS::Heap<JSScript *> script;
 END_TEST(testNullRoot)
--- a/js/src/jsapi-tests/testResolveRecursion.cpp
+++ b/js/src/jsapi-tests/testResolveRecursion.cpp
@@ -23,46 +23,50 @@ BEGIN_TEST(testResolveRecursion)
         JS_PropertyStub,       // get
         JS_StrictPropertyStub, // set
         JS_EnumerateStub,
         (JSResolveOp) my_resolve,
         JS_ConvertStub
     };
 
     obj1 = obj2 = nullptr;
-    JS_AddObjectRoot(cx, &obj1);
-    JS_AddObjectRoot(cx, &obj2);
+    JS::AddObjectRoot(cx, &obj1);
+    JS::AddObjectRoot(cx, &obj2);
 
     obj1 = JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr());
     CHECK(obj1);
     obj2 = JS_NewObject(cx, &my_resolve_class, JS::NullPtr(), JS::NullPtr());
     CHECK(obj2);
     JS_SetPrivate(obj1, this);
     JS_SetPrivate(obj2, this);
 
-    CHECK(JS_DefineProperty(cx, global, "obj1", OBJECT_TO_JSVAL(obj1), nullptr, nullptr, 0));
-    CHECK(JS_DefineProperty(cx, global, "obj2", OBJECT_TO_JSVAL(obj2), nullptr, nullptr, 0));
+    JS::RootedValue obj1Val(cx, ObjectValue(*obj1));
+    JS::RootedValue obj2Val(cx, ObjectValue(*obj2));
+    CHECK(JS_DefineProperty(cx, global, "obj1", obj1Val, 0));
+    CHECK(JS_DefineProperty(cx, global, "obj2", obj2Val, 0));
 
     resolveEntryCount = 0;
     resolveExitCount = 0;
 
     /* Start the essence of the test via invoking the first resolve hook. */
     JS::RootedValue v(cx);
     EVAL("obj1.x", &v);
     CHECK_SAME(v, JSVAL_FALSE);
     CHECK_EQUAL(resolveEntryCount, 4);
     CHECK_EQUAL(resolveExitCount, 4);
 
-    JS_RemoveObjectRoot(cx, &obj1);
-    JS_RemoveObjectRoot(cx, &obj2);
+    obj1 = nullptr;
+    obj2 = nullptr;
+    JS::RemoveObjectRoot(cx, &obj1);
+    JS::RemoveObjectRoot(cx, &obj2);
     return true;
 }
 
-JSObject *obj1;
-JSObject *obj2;
+JS::Heap<JSObject *> obj1;
+JS::Heap<JSObject *> obj2;
 unsigned resolveEntryCount;
 unsigned resolveExitCount;
 
 struct AutoIncrCounters {
 
     AutoIncrCounters(cls_testResolveRecursion *t) : t(t) {
         t->resolveEntryCount++;
     }
--- a/js/src/jsapi-tests/testSetProperty.cpp
+++ b/js/src/jsapi-tests/testSetProperty.cpp
@@ -6,25 +6,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsapi-tests/tests.h"
 
 BEGIN_TEST(testSetProperty_NativeGetterStubSetter)
 {
     JS::RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
     CHECK(obj);
-    JS::RootedValue vobj(cx, OBJECT_TO_JSVAL(obj));
 
-    CHECK(JS_DefineProperty(cx, global, "globalProp", vobj,
-                            JS_PropertyStub, JS_StrictPropertyStub,
-                            JSPROP_ENUMERATE));
+    CHECK(JS_DefineProperty(cx, global, "globalProp", obj, JSPROP_ENUMERATE,
+                            JS_PropertyStub, JS_StrictPropertyStub));
 
-    CHECK(JS_DefineProperty(cx, obj, "prop", JSVAL_VOID,
-                            NativeGet, JS_StrictPropertyStub,
-                            JSPROP_SHARED));
+    CHECK(JS_DefineProperty(cx, obj, "prop", JS::UndefinedHandleValue, JSPROP_SHARED,
+                            NativeGet, JS_StrictPropertyStub));
 
     EXEC("'use strict';                                     \n"
          "var error, passed = false;                        \n"
          "try                                               \n"
          "{                                                 \n"
          "  this.globalProp.prop = 42;                      \n"
          "  throw new Error('setting property succeeded!'); \n"
          "}                                                 \n"
@@ -67,17 +64,17 @@ END_TEST(testSetProperty_NativeGetterStu
 
 BEGIN_TEST(testSetProperty_InheritedGlobalSetter)
 {
     // This is a JSAPI test because jsapi-test globals do not have a resolve
     // hook and therefore can use the property cache in some cases where the
     // shell can't.
     JS_ASSERT(JS_GetClass(global)->resolve == &JS_ResolveStub);
 
-    CHECK(JS_DefineProperty(cx, global, "HOTLOOP", INT_TO_JSVAL(8), nullptr, nullptr, 0));
+    CHECK(JS_DefineProperty(cx, global, "HOTLOOP", 8, 0));
     EXEC("var n = 0;\n"
          "var global = this;\n"
          "function f() { n++; }\n"
          "Object.defineProperty(Object.prototype, 'x', {set: f});\n"
          "for (var i = 0; i < HOTLOOP; i++)\n"
          "    global.x = i;\n");
     EXEC("if (n != HOTLOOP)\n"
          "    throw 'FAIL';\n");
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -26,46 +26,45 @@ bool JSAPITest::init()
         return false;
     JS_EnterCompartment(cx, global);
     return true;
 }
 
 bool JSAPITest::exec(const char *bytes, const char *filename, int lineno)
 {
     JS::RootedValue v(cx);
-    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&this->global);
+    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(this->global.unsafeGet());
     return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, &v) ||
         fail(bytes, filename, lineno);
 }
 
 bool JSAPITest::evaluate(const char *bytes, const char *filename, int lineno,
                          JS::MutableHandleValue vp)
 {
-    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&this->global);
+    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(this->global.unsafeGet());
     return JS_EvaluateScript(cx, global, bytes, strlen(bytes), filename, lineno, vp) ||
         fail(bytes, filename, lineno);
 }
 
 bool JSAPITest::definePrint()
 {
-    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&this->global);
+    JS::HandleObject global = JS::HandleObject::fromMarkedLocation(this->global.unsafeGet());
     return JS_DefineFunction(cx, global, "print", (JSNative) print, 0, 0);
 }
 
 JSObject * JSAPITest::createGlobal(JSPrincipals *principals)
 {
     /* Create the global object. */
     JS::CompartmentOptions options;
     options.setVersion(JSVERSION_LATEST);
     global = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook, options);
     if (!global)
         return nullptr;
-    JS_AddNamedObjectRoot(cx, &global, "test-global");
-    JS::HandleObject globalHandle = JS::HandleObject::fromMarkedLocation(&global);
-
+    JS::AddNamedObjectRoot(cx, &global, "test-global");
+    JS::HandleObject globalHandle = JS::HandleObject::fromMarkedLocation(global.unsafeGet());
     JSAutoCompartment ac(cx, globalHandle);
 
     /* Populate the global object with the standard globals, like Object and
        Array. */
     if (!JS_InitStandardClasses(cx, globalHandle))
         return nullptr;
     return global;
 }
@@ -90,17 +89,17 @@ int main(int argc, char *argv[])
 
         printf("%s\n", name);
         if (!test->init()) {
             printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name);
             failures++;
             continue;
         }
 
-        JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&test->global);
+        JS::HandleObject global = JS::HandleObject::fromMarkedLocation(test->global.unsafeGet());
         if (test->run(global)) {
             printf("TEST-PASS | %s | ok\n", name);
         } else {
             JSAPITestString messages = test->messages();
             printf("%s | %s | %.*s\n",
                    (test->knownFail ? "TEST-KNOWN-FAIL" : "TEST-UNEXPECTED-FAIL"),
                    name, (int) messages.length(), messages.begin());
             if (!test->knownFail)
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -49,17 +49,17 @@ inline JSAPITestString operator+(JSAPITe
 class JSAPITest
 {
   public:
     static JSAPITest *list;
     JSAPITest *next;
 
     JSRuntime *rt;
     JSContext *cx;
-    JSObject *global;
+    JS::Heap<JSObject *> global;
     bool knownFail;
     JSAPITestString msgs;
     JSCompartment *oldCompartment;
 
     JSAPITest() : rt(nullptr), cx(nullptr), global(nullptr),
                   knownFail(false), oldCompartment(nullptr) {
         next = list;
         list = this;
@@ -69,18 +69,19 @@ class JSAPITest
 
     virtual bool init();
 
     virtual void uninit() {
         if (oldCompartment) {
             JS_LeaveCompartment(cx, oldCompartment);
             oldCompartment = nullptr;
         }
+        global = nullptr;
         if (cx) {
-            JS_RemoveObjectRoot(cx, &global);
+            JS::RemoveObjectRoot(cx, &global);
             JS_LeaveCompartment(cx, nullptr);
             JS_EndRequest(cx);
             JS_DestroyContext(cx);
             cx = nullptr;
         }
         if (rt) {
             destroyRuntime();
             rt = nullptr;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1481,129 +1481,137 @@ JS_strdup(JSRuntime *rt, const char *s)
     if (!p)
         return nullptr;
     return static_cast<char*>(js_memcpy(p, s, n));
 }
 
 #undef JS_AddRoot
 
 JS_PUBLIC_API(bool)
-JS_AddValueRoot(JSContext *cx, jsval *vp)
+JS::AddValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddValueRoot(cx, vp, nullptr);
-}
-
-JS_PUBLIC_API(bool)
-JS_AddStringRoot(JSContext *cx, JSString **rp)
+    return AddValueRoot(cx, vp->unsafeGet(), nullptr);
+}
+
+JS_PUBLIC_API(bool)
+JS::AddStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddStringRoot(cx, rp, nullptr);
-}
-
-JS_PUBLIC_API(bool)
-JS_AddObjectRoot(JSContext *cx, JSObject **rp)
+    return AddStringRoot(cx, rp->unsafeGet(), nullptr);
+}
+
+JS_PUBLIC_API(bool)
+JS::AddObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddObjectRoot(cx, rp, nullptr);
-}
-
-JS_PUBLIC_API(bool)
-JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name)
+    return AddObjectRoot(cx, rp->unsafeGet(), nullptr);
+}
+
+JS_PUBLIC_API(bool)
+JS::AddNamedValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddValueRoot(cx, vp, name);
-}
-
-JS_PUBLIC_API(bool)
-JS_AddNamedValueRootRT(JSRuntime *rt, jsval *vp, const char *name)
-{
-    return AddValueRootRT(rt, vp, name);
-}
-
-JS_PUBLIC_API(bool)
-JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
+    return AddValueRoot(cx, vp->unsafeGet(), name);
+}
+
+JS_PUBLIC_API(bool)
+JS::AddNamedValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp, const char *name)
+{
+    return AddValueRootRT(rt, vp->unsafeGet(), name);
+}
+
+JS_PUBLIC_API(bool)
+JS::AddNamedStringRoot(JSContext *cx, JS::Heap<JSString *> *rp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddStringRoot(cx, rp, name);
-}
-
-JS_PUBLIC_API(bool)
-JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
+    return AddStringRoot(cx, rp->unsafeGet(), name);
+}
+
+JS_PUBLIC_API(bool)
+JS::AddNamedObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddObjectRoot(cx, rp, name);
-}
-
-JS_PUBLIC_API(bool)
-JS_AddNamedScriptRoot(JSContext *cx, JSScript **rp, const char *name)
+    return AddObjectRoot(cx, rp->unsafeGet(), name);
+}
+
+JS_PUBLIC_API(bool)
+JS::AddNamedScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp, const char *name)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return AddScriptRoot(cx, rp, name);
+    return AddScriptRoot(cx, rp->unsafeGet(), name);
 }
 
 /* We allow unrooting from finalizers within the GC */
 
 JS_PUBLIC_API(void)
-JS_RemoveValueRoot(JSContext *cx, jsval *vp)
+JS::RemoveValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)vp);
+    *vp = UndefinedValue();
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveStringRoot(JSContext *cx, JSString **rp)
+JS::RemoveStringRoot(JSContext *cx, JS::Heap<JSString *> *rp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
+JS::RemoveObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveScriptRoot(JSContext *cx, JSScript **rp)
+JS::RemoveScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp)
 {
     CHECK_REQUEST(cx);
     RemoveRoot(cx->runtime(), (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveValueRootRT(JSRuntime *rt, jsval *vp)
+JS::RemoveValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp)
 {
     RemoveRoot(rt, (void *)vp);
+    *vp = UndefinedValue();
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveStringRootRT(JSRuntime *rt, JSString **rp)
+JS::RemoveStringRootRT(JSRuntime *rt, JS::Heap<JSString *> *rp)
 {
     RemoveRoot(rt, (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveObjectRootRT(JSRuntime *rt, JSObject **rp)
+JS::RemoveObjectRootRT(JSRuntime *rt, JS::Heap<JSObject *> *rp)
 {
     RemoveRoot(rt, (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(void)
-JS_RemoveScriptRootRT(JSRuntime *rt, JSScript **rp)
+JS::RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp)
 {
     RemoveRoot(rt, (void *)rp);
+    *rp = nullptr;
 }
 
 JS_PUBLIC_API(bool)
 JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
 {
     AssertHeapIsIdle(rt);
     return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data));
 }
@@ -3087,25 +3095,74 @@ DefineSelfHostedProperty(JSContext *cx,
     JSStrictPropertyOp setterOp = JS_DATA_TO_FUNC_PTR(StrictPropertyOp, setterFunc.get());
 
     return DefineProperty(cx, obj, name, JS::UndefinedHandleValue,
                           GetterWrapper(getterOp), SetterWrapper(setterOp),
                           attrs, flags);
 }
 
 JS_PUBLIC_API(bool)
-JS_DefineProperty(JSContext *cx, JSObject *objArg, const char *name, jsval valueArg,
-                  PropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
-{
-    RootedObject obj(cx, objArg);
-    RootedValue value(cx, valueArg);
+JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value,
+                  unsigned attrs,
+                  PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
+{
+    return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
+                          attrs, 0);
+}
+
+JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleObject valueArg,
+                  unsigned attrs,
+                  PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
+{
+    RootedValue value(cx, ObjectValue(*valueArg));
+    return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
+                          attrs, 0);
+}
+
+JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleString valueArg,
+                  unsigned attrs,
+                  PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
+{
+    RootedValue value(cx, StringValue(valueArg));
     return DefineProperty(cx, obj, name, value, GetterWrapper(getter), SetterWrapper(setter),
                           attrs, 0);
 }
 
+JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, int32_t valueArg,
+                  unsigned attrs,
+                  PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
+{
+    Value value = Int32Value(valueArg);
+    return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
+                          GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
+}
+
+JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, uint32_t valueArg,
+                  unsigned attrs,
+                  PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
+{
+    Value value = UINT_TO_JSVAL(valueArg);
+    return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
+                          GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
+}
+
+JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, HandleObject obj, const char *name, double valueArg,
+                  unsigned attrs,
+                  PropertyOp getter /* = nullptr */, JSStrictPropertyOp setter /* = nullptr */)
+{
+    Value value = NumberValue(valueArg);
+    return DefineProperty(cx, obj, name, HandleValue::fromMarkedLocation(&value),
+                          GetterWrapper(getter), SetterWrapper(setter), attrs, 0);
+}
+
 static bool
 DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
                  const Value &value_, PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
                  unsigned flags)
 {
     RootedValue value(cx, value_);
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
     JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
@@ -5919,17 +5976,17 @@ JS_RestoreExceptionState(JSContext *cx, 
 JS_PUBLIC_API(void)
 JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     if (state) {
         if (state->throwing && JSVAL_IS_GCTHING(state->exception)) {
             assertSameCompartment(cx, state->exception);
-            JS_RemoveValueRoot(cx, &state->exception);
+            RemoveRoot(cx->runtime(), &state->exception);
         }
         js_free(state);
     }
 }
 
 JS_PUBLIC_API(JSErrorReport *)
 JS_ErrorFromException(JSContext *cx, HandleObject obj)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1884,16 +1884,17 @@ JS_updateMallocCounter(JSContext *cx, si
 
 extern JS_PUBLIC_API(char *)
 JS_strdup(JSContext *cx, const char *s);
 
 /* Duplicate a string.  Does not report an error on failure. */
 extern JS_PUBLIC_API(char *)
 JS_strdup(JSRuntime *rt, const char *s);
 
+namespace JS {
 
 /*
  * A GC root is a pointer to a jsval, JSObject * or JSString * that itself
  * points into the GC heap. JS_AddValueRoot takes a pointer to a jsval and
  * JS_AddGCThingRoot takes a pointer to a JSObject * or JString *.
  *
  * Note that, since JS_Add*Root stores the address of a variable (of type
  * jsval, JSString *, or JSObject *), that variable must live until
@@ -1911,62 +1912,64 @@ JS_strdup(JSRuntime *rt, const char *s);
  *
  * Also, use JS_AddNamed*Root(cx, &structPtr->memberObj, "structPtr->memberObj")
  * in preference to JS_Add*Root(cx, &structPtr->memberObj), in order to identify
  * roots by their source callsites.  This way, you can find the callsite while
  * debugging if you should fail to do JS_Remove*Root(cx, &structPtr->memberObj)
  * before freeing structPtr's memory.
  */
 extern JS_PUBLIC_API(bool)
-JS_AddValueRoot(JSContext *cx, jsval *vp);
+AddValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp);
 
 extern JS_PUBLIC_API(bool)
-JS_AddStringRoot(JSContext *cx, JSString **rp);
+AddStringRoot(JSContext *cx, JS::Heap<JSString *> *rp);
 
 extern JS_PUBLIC_API(bool)
-JS_AddObjectRoot(JSContext *cx, JSObject **rp);
+AddObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name);
+AddNamedValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedValueRootRT(JSRuntime *rt, jsval *vp, const char *name);
+AddNamedValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name);
+AddNamedStringRoot(JSContext *cx, JS::Heap<JSString *> *rp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name);
+AddNamedObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp, const char *name);
 
 extern JS_PUBLIC_API(bool)
-JS_AddNamedScriptRoot(JSContext *cx, JSScript **rp, const char *name);
+AddNamedScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp, const char *name);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveValueRoot(JSContext *cx, jsval *vp);
+RemoveValueRoot(JSContext *cx, JS::Heap<JS::Value> *vp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveStringRoot(JSContext *cx, JSString **rp);
+RemoveStringRoot(JSContext *cx, JS::Heap<JSString *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveObjectRoot(JSContext *cx, JSObject **rp);
+RemoveObjectRoot(JSContext *cx, JS::Heap<JSObject *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveScriptRoot(JSContext *cx, JSScript **rp);
+RemoveScriptRoot(JSContext *cx, JS::Heap<JSScript *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveValueRootRT(JSRuntime *rt, jsval *vp);
+RemoveValueRootRT(JSRuntime *rt, JS::Heap<JS::Value> *vp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveStringRootRT(JSRuntime *rt, JSString **rp);
+RemoveStringRootRT(JSRuntime *rt, JS::Heap<JSString *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveObjectRootRT(JSRuntime *rt, JSObject **rp);
+RemoveObjectRootRT(JSRuntime *rt, JS::Heap<JSObject *> *rp);
 
 extern JS_PUBLIC_API(void)
-JS_RemoveScriptRootRT(JSRuntime *rt, JSScript **rp);
+RemoveScriptRootRT(JSRuntime *rt, JS::Heap<JSScript *> *rp);
+
+} /* namespace JS */
 
 /*
  * Register externally maintained GC roots.
  *
  * traceOp: the trace operation. For each root the implementation should call
  *          JS_CallTracer whenever the root contains a traceable thing.
  * data:    the data argument to pass to each invocation of traceOp.
  */
@@ -2755,18 +2758,44 @@ JS_DefineObject(JSContext *cx, JSObject 
 
 extern JS_PUBLIC_API(bool)
 JS_DefineConstDoubles(JSContext *cx, JS::HandleObject obj, const JSConstDoubleSpec *cds);
 
 extern JS_PUBLIC_API(bool)
 JS_DefineProperties(JSContext *cx, JS::HandleObject obj, const JSPropertySpec *ps);
 
 extern JS_PUBLIC_API(bool)
-JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
-                  JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
+JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleValue value,
+                  unsigned attrs,
+                  JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr);
+
+extern JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleObject value,
+                  unsigned attrs,
+                  JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr);
+
+extern JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleString value,
+                  unsigned attrs,
+                  JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr);
+
+extern JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, int32_t value,
+                  unsigned attrs,
+                  JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr);
+
+extern JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, uint32_t value,
+                  unsigned attrs,
+                  JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr);
+
+extern JS_PUBLIC_API(bool)
+JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, double value,
+                  unsigned attrs,
+                  JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr);
 
 extern JS_PUBLIC_API(bool)
 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
                       JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
 extern JS_PUBLIC_API(bool)
 JS_DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                      JS::HandleValue descriptor, bool *bp);
@@ -3132,16 +3161,39 @@ JS_AllocateArrayBufferContents(JSContext
 /*
  * Reallocate memory allocated by JS_AllocateArrayBufferContents, growing or
  * shrinking it as appropriate. If oldContents is null then this behaves like
  * JS_AllocateArrayBufferContents.
  */
 extern JS_PUBLIC_API(void *)
 JS_ReallocateArrayBufferContents(JSContext *cx, uint32_t nbytes, void *oldContents, uint32_t oldNbytes);
 
+/*
+ * Create a new mapped array buffer with the given memory mapped contents.
+ */
+extern JS_PUBLIC_API(JSObject *)
+JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents);
+
+/*
+ * Create memory mapped array buffer contents.
+ * Caller must take care of closing fd after calling this function.
+ */
+extern JS_PUBLIC_API(void *)
+JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length);
+
+/*
+ * Release the allocated resource of mapped array buffer contents before the
+ * object is created.
+ * If a new object has been created by JS_NewMappedArrayBufferWithContents()
+ * with this content, then JS_NeuterArrayBuffer() should be used instead to
+ * release the resource used by the object.
+ */
+extern JS_PUBLIC_API(void)
+JS_ReleaseMappedArrayBufferContents(void *contents, size_t length);
+
 extern JS_PUBLIC_API(JSIdArray *)
 JS_Enumerate(JSContext *cx, JS::HandleObject obj);
 
 /*
  * Create an object to iterate over enumerable properties of obj, in arbitrary
  * property definition order.  NB: This differs from longstanding for..in loop
  * order, which uses order of property definition in obj.
  */
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -267,23 +267,21 @@ JS_FRIEND_API(void)
 JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape)
 {
     MarkCycleCollectorChildren(trc, static_cast<Shape *>(shape));
 }
 
 static bool
 DefineHelpProperty(JSContext *cx, HandleObject obj, const char *prop, const char *value)
 {
-    JSAtom *atom = Atomize(cx, value, strlen(value));
+    RootedAtom atom(cx, Atomize(cx, value, strlen(value)));
     if (!atom)
         return false;
-    jsval v = STRING_TO_JSVAL(atom);
-    return JS_DefineProperty(cx, obj, prop, v,
-                             JS_PropertyStub, JS_StrictPropertyStub,
-                             JSPROP_READONLY | JSPROP_PERMANENT);
+    return JS_DefineProperty(cx, obj, prop, atom, JSPROP_READONLY | JSPROP_PERMANENT,
+                             JS_PropertyStub, JS_StrictPropertyStub);
 }
 
 JS_FRIEND_API(bool)
 JS_DefineFunctionsWithHelp(JSContext *cx, HandleObject obj, const JSFunctionSpecWithHelp *fs)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
     CHECK_REQUEST(cx);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -147,21 +147,25 @@ JS_FRIEND_API(void)
 js_ReportOverRecursed(JSContext *maybecx);
 
 JS_FRIEND_API(bool)
 js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
 
 JS_FRIEND_API(const char *)
 js_ObjectClassName(JSContext *cx, JS::HandleObject obj);
 
+namespace js {
+
 JS_FRIEND_API(bool)
-js_AddObjectRoot(JSRuntime *rt, JSObject **objp);
+AddRawValueRoot(JSContext *cx, JS::Value *vp, const char *name);
 
 JS_FRIEND_API(void)
-js_RemoveObjectRoot(JSRuntime *rt, JSObject **objp);
+RemoveRawValueRoot(JSContext *cx, JS::Value *vp);
+
+} /* namespace js */
 
 #ifdef JS_DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
  * the debugger find them and to support temporarily hacking js_Dump* calls
  * into other code.
  */
@@ -1330,16 +1334,24 @@ JS_IsArrayBufferObject(JSObject *obj);
  * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
  * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
  * ArrayBuffer, and the unwrapping will succeed.
  */
 extern JS_FRIEND_API(uint32_t)
 JS_GetArrayBufferByteLength(JSObject *obj);
 
 /*
+ * Check whether the obj is ArrayBufferObject and memory mapped. Note that this
+ * may return false if a security wrapper is encountered that denies the
+ * unwrapping.
+ */
+extern JS_FRIEND_API(bool)
+JS_IsMappedArrayBufferObject(JSObject *obj);
+
+/*
  * Return the number of elements in a typed array.
  *
  * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
  * be known that it would pass such a test: it is a typed array or a wrapper of
  * a typed array, and the unwrapping will succeed.
  */
 extern JS_FRIEND_API(uint32_t)
 JS_GetTypedArrayLength(JSObject *obj);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1247,25 +1247,25 @@ js::AddObjectRoot(JSRuntime *rt, JSObjec
 
 extern bool
 js::AddScriptRoot(JSContext *cx, JSScript **rp, const char *name)
 {
     return AddRoot(cx, rp, name, JS_GC_ROOT_SCRIPT_PTR);
 }
 
 extern JS_FRIEND_API(bool)
-js_AddObjectRoot(JSRuntime *rt, JSObject **objp)
-{
-    return AddRoot(rt, objp, nullptr, JS_GC_ROOT_OBJECT_PTR);
+js::AddRawValueRoot(JSContext *cx, Value *vp, const char *name)
+{
+    return AddRoot(cx, vp, name, JS_GC_ROOT_VALUE_PTR);
 }
 
 extern JS_FRIEND_API(void)
-js_RemoveObjectRoot(JSRuntime *rt, JSObject **objp)
-{
-    RemoveRoot(rt, objp);
+js::RemoveRawValueRoot(JSContext *cx, Value *vp)
+{
+    RemoveRoot(cx->runtime(), vp);
 }
 
 void
 js::RemoveRoot(JSRuntime *rt, void *rp)
 {
     rt->gcRootsHash.remove(rp);
     rt->gcPoke = true;
 }
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1003,28 +1003,28 @@ struct MarkStack {
         if (baseCapacity_ > maxCapacity_)
             baseCapacity_ = maxCapacity_;
 
         reset();
     }
 
     bool push(T item) {
         if (tos_ == end_) {
-            if (!enlarge())
+            if (!enlarge(1))
                 return false;
         }
         JS_ASSERT(tos_ < end_);
         *tos_++ = item;
         return true;
     }
 
     bool push(T item1, T item2, T item3) {
         T *nextTos = tos_ + 3;
         if (nextTos > end_) {
-            if (!enlarge())
+            if (!enlarge(3))
                 return false;
             nextTos = tos_ + 3;
         }
         JS_ASSERT(nextTos <= end_);
         tos_[0] = item1;
         tos_[1] = item2;
         tos_[2] = item3;
         tos_ = nextTos;
@@ -1052,24 +1052,22 @@ struct MarkStack {
             // If the realloc fails, just keep using the existing stack; it's
             // not ideal but better than failing.
             newStack = stack_;
             baseCapacity_ = capacity();
         }
         setStack(newStack, 0, baseCapacity_);
     }
 
-    bool enlarge() {
-        if (capacity() == maxCapacity_)
+    /* Grow the stack, ensuring there is space for at least count elements. */
+    bool enlarge(unsigned count) {
+        size_t newCapacity = Min(maxCapacity_, capacity() * 2);
+        if (newCapacity < capacity() + count)
             return false;
 
-        size_t newCapacity = capacity() * 2;
-        if (newCapacity > maxCapacity_)
-            newCapacity = maxCapacity_;
-
         size_t tosIndex = position();
 
         T *newStack = (T *)js_realloc(stack_, sizeof(T) * newCapacity);
         if (!newStack)
             return false;
 
         setStack(newStack, tosIndex, newCapacity);
         return true;
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -1595,18 +1595,19 @@ js_InitMathClass(JSContext *cx, HandleOb
 {
     RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
     if (!proto)
         return nullptr;
     RootedObject Math(cx, NewObjectWithGivenProto(cx, &MathClass, proto, obj, SingletonObject));
     if (!Math)
         return nullptr;
 
-    if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
-                           JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+    if (!JS_DefineProperty(cx, obj, js_Math_str, Math, 0,
+                           JS_PropertyStub, JS_StrictPropertyStub))
+    {
         return nullptr;
     }
 
     if (!JS_DefineFunctions(cx, Math, math_static_methods))
         return nullptr;
     if (!JS_DefineConstDoubles(cx, Math, math_constants))
         return nullptr;
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -874,18 +874,18 @@ js_InitJSONClass(JSContext *cx, HandleOb
     if (!GlobalObject::getOrCreateBooleanPrototype(cx, global))
         return nullptr;
 
     RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
     RootedObject JSON(cx, NewObjectWithClassProto(cx, &JSONClass, proto, global, SingletonObject));
     if (!JSON)
         return nullptr;
 
-    if (!JS_DefineProperty(cx, global, js_JSON_str, OBJECT_TO_JSVAL(JSON),
-                           JS_PropertyStub, JS_StrictPropertyStub, 0))
+    if (!JS_DefineProperty(cx, global, js_JSON_str, JSON, 0,
+                           JS_PropertyStub, JS_StrictPropertyStub))
         return nullptr;
 
     if (!JS_DefineFunctions(cx, JSON, json_static_methods))
         return nullptr;
 
     global->setConstructor(JSProto_JSON, ObjectValue(*JSON));
 
     return JSON;
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -3280,16 +3280,16 @@ js_InitProxyClass(JSContext *cx, HandleO
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
     RootedFunction ctor(cx);
     ctor = global->createConstructor(cx, proxy, cx->names().Proxy, 2);
     if (!ctor)
         return nullptr;
 
     if (!JS_DefineFunctions(cx, ctor, static_methods))
         return nullptr;
-    if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(ctor),
-                           JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+    if (!JS_DefineProperty(cx, obj, "Proxy", ctor, 0,
+                           JS_PropertyStub, JS_StrictPropertyStub)) {
         return nullptr;
     }
 
     global->setConstructor(JSProto_Proxy, ObjectValue(*ctor));
     return ctor;
 }
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -3333,18 +3333,18 @@ JS_InitReflect(JSContext *cx, HandleObje
     RootedObject proto(cx, obj->as<GlobalObject>().getOrCreateObjectPrototype(cx));
     if (!proto)
         return nullptr;
     RootedObject Reflect(cx, NewObjectWithGivenProto(cx, &JSObject::class_, proto,
                                                      obj, SingletonObject));
     if (!Reflect)
         return nullptr;
 
-    if (!JS_DefineProperty(cx, obj, "Reflect", OBJECT_TO_JSVAL(Reflect),
-                           JS_PropertyStub, JS_StrictPropertyStub, 0)) {
+    if (!JS_DefineProperty(cx, obj, "Reflect", Reflect, 0,
+                           JS_PropertyStub, JS_StrictPropertyStub)) {
         return nullptr;
     }
 
     if (!JS_DefineFunctions(cx, Reflect, static_methods))
         return nullptr;
 
     return Reflect;
 }
--- a/js/src/perf/jsperf.cpp
+++ b/js/src/perf/jsperf.cpp
@@ -241,18 +241,18 @@ RegisterPerfMeasurement(JSContext *cx, H
         return 0;
 
     RootedObject ctor(cx);
     ctor = JS_GetConstructor(cx, prototype);
     if (!ctor)
         return 0;
 
     for (const pm_const *c = pm_consts; c->name; c++) {
-        if (!JS_DefineProperty(cx, ctor, c->name, INT_TO_JSVAL(c->value),
-                               JS_PropertyStub, JS_StrictPropertyStub, PM_CATTRS))
+        if (!JS_DefineProperty(cx, ctor, c->name, c->value, PM_CATTRS,
+                               JS_PropertyStub, JS_StrictPropertyStub))
             return 0;
     }
 
     if (!JS_FreezeObject(cx, prototype) ||
         !JS_FreezeObject(cx, ctor)) {
         return 0;
     }
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -108,17 +108,17 @@ static size_t gMaxStackSize = 128 * size
 
 /*
  * Limit the timeout to 30 minutes to prevent an overflow on platfoms
  * that represent the time internally in microseconds using 32-bit int.
  */
 static double MAX_TIMEOUT_INTERVAL = 1800.0;
 static double gTimeoutInterval = -1.0;
 static volatile bool gTimedOut = false;
-static JS::Value gTimeoutFunc;
+static Maybe<JS::PersistentRootedValue> gTimeoutFunc;
 
 static bool enableDisassemblyDumps = false;
 
 static bool printTiming = false;
 static const char *jsCacheDir = nullptr;
 static const char *jsCacheAsmJSPath = nullptr;
 static bool jsCachingEnabled = true;
 mozilla::Atomic<bool> jsCacheOpened(false);
@@ -357,21 +357,21 @@ GetContextData(JSContext *cx)
 
 static bool
 ShellInterruptCallback(JSContext *cx)
 {
     if (!gTimedOut)
         return true;
 
     bool result;
-    if (!gTimeoutFunc.isNull()) {
+    RootedValue timeoutFunc(cx, gTimeoutFunc.ref());
+    if (!timeoutFunc.isNull()) {
         JS::AutoSaveExceptionState savedExc(cx);
-        JSAutoCompartment ac(cx, &gTimeoutFunc.toObject());
+        JSAutoCompartment ac(cx, &timeoutFunc.toObject());
         RootedValue rval(cx);
-        HandleValue timeoutFunc = HandleValue::fromMarkedLocation(&gTimeoutFunc);
         if (!JS_CallFunctionValue(cx, JS::NullPtr(), timeoutFunc,
                                   JS::HandleValueArray::empty(), &rval))
         {
             return false;
         }
         if (rval.isBoolean())
             result = rval.toBoolean();
         else
@@ -3298,17 +3298,17 @@ ScheduleWatchdog(JSRuntime *rt, double t
 #endif /* !JS_THREADSAFE */
 
 static void
 CancelExecution(JSRuntime *rt)
 {
     gTimedOut = true;
     JS_RequestInterruptCallback(rt);
 
-    if (!gTimeoutFunc.isNull()) {
+    if (!gTimeoutFunc.ref().get().isNull()) {
         static const char msg[] = "Script runs for too long, terminating.\n";
 #if defined(XP_UNIX) && !defined(JS_THREADSAFE)
         /* It is not safe to call fputs from signals. */
         /* Dummy assignment avoids GCC warning on "attribute warn_unused_result" */
         ssize_t dummy = write(2, msg, sizeof(msg) - 1);
         (void)dummy;
 #else
         fputs(msg, stderr);
@@ -3352,17 +3352,17 @@ Timeout(JSContext *cx, unsigned argc, Va
         return false;
 
     if (args.length() > 1) {
         RootedValue value(cx, args[1]);
         if (!value.isObject() || !value.toObject().is<JSFunction>()) {
             JS_ReportError(cx, "Second argument must be a timeout function");
             return false;
         }
-        gTimeoutFunc = value;
+        gTimeoutFunc.ref() = value;
     }
 
     args.rval().setUndefined();
     return SetTimeoutValue(cx, t);
 }
 
 static bool
 Elapsed(JSContext *cx, unsigned argc, jsval *vp)
@@ -3533,43 +3533,39 @@ class OffThreadState {
     bool init() { return monitor.init(); }
 
     bool startIfIdle(JSContext *cx, JSString *newSource) {
         AutoLockMonitor alm(monitor);
         if (state != IDLE)
             return false;
 
         JS_ASSERT(!token);
-        JS_ASSERT(!source);
-
-        source = newSource;
-        if (!JS_AddStringRoot(cx, &source))
-            return false;
+
+        source.construct(cx, newSource);
 
         state = COMPILING;
         return true;
     }
 
     void abandon(JSContext *cx) {
         AutoLockMonitor alm(monitor);
         JS_ASSERT(state == COMPILING);
         JS_ASSERT(!token);
-        JS_ASSERT(source);
-
-        JS_RemoveStringRoot(cx, &source);
-        source = nullptr;
+        JS_ASSERT(source.ref());
+
+        source.destroy();
 
         state = IDLE;
     }
 
     void markDone(void *newToken) {
         AutoLockMonitor alm(monitor);
         JS_ASSERT(state == COMPILING);
         JS_ASSERT(!token);
-        JS_ASSERT(source);
+        JS_ASSERT(source.ref());
         JS_ASSERT(newToken);
 
         token = newToken;
         state = DONE;
         alm.notify();
     }
 
     void *waitUntilDone(JSContext *cx) {
@@ -3577,32 +3573,31 @@ class OffThreadState {
         if (state == IDLE)
             return nullptr;
 
         if (state == COMPILING) {
             while (state != DONE)
                 alm.wait();
         }
 
-        JS_ASSERT(source);
-        JS_RemoveStringRoot(cx, &source);
-        source = nullptr;
+        JS_ASSERT(source.ref());
+        source.destroy();
 
         JS_ASSERT(token);
         void *holdToken = token;
         token = nullptr;
         state = IDLE;
         return holdToken;
     }
 
   private:
     Monitor monitor;
     State state;
     void *token;
-    JSString *source;
+    Maybe<PersistentRootedString> source;
 };
 
 static OffThreadState offThreadState;
 
 static void
 OffThreadCompileScriptCallback(void *token, void *callbackData)
 {
     offThreadState.markDone(token);
@@ -5016,30 +5011,29 @@ env_setProperty(JSContext *cx, HandleObj
     return true;
 }
 
 static bool
 env_enumerate(JSContext *cx, HandleObject obj)
 {
     static bool reflected;
     char **evp, *name, *value;
-    JSString *valstr;
+    RootedString valstr(cx);
     bool ok;
 
     if (reflected)
         return true;
 
     for (evp = (char **)JS_GetPrivate(obj); (name = *evp) != nullptr; evp++) {
         value = strchr(name, '=');
         if (!value)
             continue;
         *value++ = '\0';
         valstr = JS_NewStringCopyZ(cx, value);
-        ok = valstr && JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
-                                         nullptr, nullptr, JSPROP_ENUMERATE);
+        ok = valstr && JS_DefineProperty(cx, obj, name, valstr, JSPROP_ENUMERATE);
         value[-1] = '=';
         if (!ok)
             return false;
     }
 
     reflected = true;
     return true;
 }
@@ -5055,20 +5049,18 @@ env_resolve(JSContext *cx, HandleObject 
         return false;
 
     const char *name = idstr.ptr();
     const char *value = getenv(name);
     if (value) {
         RootedString valstr(cx, JS_NewStringCopyZ(cx, value));
         if (!valstr)
             return false;
-        if (!JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
-                               nullptr, nullptr, JSPROP_ENUMERATE)) {
+        if (!JS_DefineProperty(cx, obj, name, valstr, JSPROP_ENUMERATE))
             return false;
-        }
         objp.set(obj);
     }
     return true;
 }
 
 static const JSClass env_class = {
     "environment", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub,  JS_DeletePropertyStub,
@@ -5659,18 +5651,17 @@ BindScriptArgs(JSContext *cx, JSObject *
     RootedObject obj(cx, obj_);
 
     MultiStringRange msr = op->getMultiStringArg("scriptArgs");
     RootedObject scriptArgs(cx);
     scriptArgs = JS_NewArrayObject(cx, 0);
     if (!scriptArgs)
         return false;
 
-    if (!JS_DefineProperty(cx, obj, "scriptArgs", OBJECT_TO_JSVAL(scriptArgs),
-                           nullptr, nullptr, 0))
+    if (!JS_DefineProperty(cx, obj, "scriptArgs", scriptArgs, 0))
         return false;
 
     for (size_t i = 0; !msr.empty(); msr.popFront(), ++i) {
         const char *scriptArg = msr.front();
         JSString *str = JS_NewStringCopyZ(cx, scriptArg);
         if (!str ||
             !JS_DefineElement(cx, scriptArgs, i, STRING_TO_JSVAL(str), nullptr, nullptr,
                               JSPROP_ENUMERATE)) {
@@ -6157,19 +6148,17 @@ main(int argc, char **argv, char **envp)
     rt = JS_NewRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS);
     if (!rt)
         return 1;
 
     JS::SetOutOfMemoryCallback(rt, my_OOMCallback);
     if (!SetRuntimeOptions(rt, op))
         return 1;
 
-    gTimeoutFunc = NullValue();
-    if (!JS_AddNamedValueRootRT(rt, &gTimeoutFunc, "gTimeoutFunc"))
-        return 1;
+    gTimeoutFunc.construct(rt, NullValue());
 
     JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
 #ifdef JSGC_GENERATIONAL
     Maybe<JS::AutoDisableGenerationalGC> noggc;
     if (op.getBoolOption("no-ggc"))
         noggc.construct(rt);
 #endif
 
@@ -6205,23 +6194,22 @@ main(int argc, char **argv, char **envp)
 
     result = Shell(cx, &op, envp);
 
 #ifdef DEBUG
     if (OOM_printAllocationCount)
         printf("OOM max count: %u\n", OOM_counter);
 #endif
 
-    gTimeoutFunc = NullValue();
-    JS_RemoveValueRootRT(rt, &gTimeoutFunc);
-
     DestroyContext(cx, true);
 
     KillWatchdog();
 
+    gTimeoutFunc.destroy();
+
 #ifdef JS_THREADSAFE
     for (size_t i = 0; i < workerThreads.length(); i++)
         PR_JoinThread(workerThreads[i]);
 #endif
 
 #ifdef JSGC_GENERATIONAL
     if (!noggc.empty())
         noggc.destroy();
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -29,16 +29,17 @@
 #include "jsutil.h"
 #ifdef XP_WIN
 # include "jswin.h"
 #endif
 #include "jswrapper.h"
 
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
+#include "gc/Memory.h"
 #include "jit/AsmJS.h"
 #include "jit/AsmJSModule.h"
 #include "js/MemoryMetrics.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/WrapperObject.h"
@@ -337,17 +338,19 @@ ArrayBufferObject::neuter(JSContext *cx,
 
     for (ArrayBufferViewObject *view = buffer->viewList(); view; view = view->nextView()) {
         view->neuter(newData);
 
         // Notify compiled jit code that the base pointer has moved.
         MarkObjectStateChange(cx, view);
     }
 
-    if (newData != buffer->dataPointer())
+    if (buffer->isMappedArrayBuffer())
+        buffer->changeContents(cx, nullptr);
+    else if (newData != buffer->dataPointer())
         buffer->changeContents(cx, newData);
 
     buffer->setByteLength(0);
     buffer->setViewList(nullptr);
     buffer->setIsNeutered();
 
     // If this is happening during an incremental GC, remove the buffer from
     // the list of live buffers with multiple views if necessary.
@@ -367,16 +370,17 @@ ArrayBufferObject::neuter(JSContext *cx,
     }
 }
 
 void
 ArrayBufferObject::changeContents(JSContext *cx, void *newData)
 {
     JS_ASSERT(!isAsmJSArrayBuffer());
     JS_ASSERT(!isSharedArrayBuffer());
+    JS_ASSERT_IF(isMappedArrayBuffer(), !newData);
 
     // Update all views.
     ArrayBufferViewObject *viewListHead = viewList();
     for (ArrayBufferViewObject *view = viewListHead; view; view = view->nextView()) {
         // Watch out for NULL data pointers in views. This means that the view
         // is not fully initialized (in which case it'll be initialized later
         // with the correct pointer).
         uint8_t *viewDataPointer = view->dataPointer();
@@ -515,16 +519,31 @@ ArrayBufferObject::canNeuterAsmJSArrayBu
         return true;
 
     return false;
 #else
     return true;
 #endif
 }
 
+void *
+ArrayBufferObject::createMappedArrayBuffer(int fd, size_t offset, size_t length)
+{
+    return AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT);
+}
+
+void
+ArrayBufferObject::releaseMappedArray()
+{
+    if(!isMappedArrayBuffer() || isNeutered())
+        return;
+
+    DeallocateMappedContent(dataPointer(), byteLength());
+}
+
 void
 ArrayBufferObject::addView(ArrayBufferViewObject *view)
 {
     // Note that pre-barriers are not needed here because either the list was
     // previously empty, in which case no pointer is being overwritten, or the
     // list was nonempty and will be made weak during this call (and weak
     // pointers cannot violate the snapshot-at-the-beginning invariant.)
 
@@ -550,24 +569,26 @@ ArrayBufferObject::dataPointer() const
 
 void
 ArrayBufferObject::releaseData(FreeOp *fop)
 {
     JS_ASSERT(ownsData());
 
     if (isAsmJSArrayBuffer())
         releaseAsmJSArray(fop);
+    else if (isMappedArrayBuffer())
+        releaseMappedArray();
     else
         fop->free_(dataPointer());
 }
 
 void
 ArrayBufferObject::setDataPointer(void *data, OwnsState ownsData)
 {
-    MOZ_ASSERT_IF(!is<SharedArrayBufferObject>(), data != nullptr);
+    MOZ_ASSERT_IF(!is<SharedArrayBufferObject>() && !isMappedArrayBuffer(), data != nullptr);
     setSlot(DATA_SLOT, PrivateValue(data));
     setOwnsData(ownsData);
 }
 
 size_t
 ArrayBufferObject::byteLength() const
 {
     return size_t(getSlot(BYTE_LENGTH_SLOT).toDouble());
@@ -588,18 +609,21 @@ ArrayBufferObject::flags() const
 void
 ArrayBufferObject::setFlags(uint32_t flags)
 {
     setSlot(FLAGS_SLOT, Int32Value(flags));
 }
 
 ArrayBufferObject *
 ArrayBufferObject::create(JSContext *cx, uint32_t nbytes, void *data /* = nullptr */,
-                          NewObjectKind newKind /* = GenericObject */)
+                          NewObjectKind newKind /* = GenericObject */,
+                          bool mapped /* = false */)
 {
+    JS_ASSERT_IF(mapped, data);
+
     // If we need to allocate data, try to use a larger object size class so
     // that the array buffer's data can be allocated inline with the object.
     // The extra space will be left unused by the object's fixed slots and
     // available for the buffer's data, see NewObject().
     size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_);
 
     size_t nslots = reservedSlots;
     if (!data) {
@@ -625,16 +649,18 @@ ArrayBufferObject::create(JSContext *cx,
         return nullptr;
     }
     JS_ASSERT(obj->getClass() == &class_);
 
     JS_ASSERT(!gc::IsInsideNursery(cx->runtime(), obj));
 
     if (data) {
         obj->initialize(nbytes, data, OwnsData);
+        if (mapped)
+            obj->setIsMappedArrayBuffer();
     } else {
         void *data = obj->fixedData(reservedSlots);
         memset(data, 0, nbytes);
         obj->initialize(nbytes, data, DoesntOwnData);
     }
 
     return obj;
 }
@@ -707,19 +733,24 @@ ArrayBufferObject::ensureNonInline(JSCon
 ArrayBufferObject::stealContents(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
     if (!buffer->canNeuter(cx)) {
         js_ReportOverRecursed(cx);
         return nullptr;
     }
 
     void *oldData = buffer->dataPointer();
-    void *newData = AllocateArrayBufferContents(cx, buffer->byteLength());
-    if (!newData)
-        return nullptr;
+    void *newData;
+    if (buffer->isMappedArrayBuffer())
+        newData = oldData;
+    else {
+        newData = AllocateArrayBufferContents(cx, buffer->byteLength());
+        if (!newData)
+            return nullptr;
+    }
 
     if (buffer->hasStealableContents()) {
         buffer->setOwnsData(DoesntOwnData);
         ArrayBufferObject::neuter(cx, buffer, newData);
         return oldData;
     } else {
         memcpy(newData, oldData, buffer->byteLength());
         ArrayBufferObject::neuter(cx, buffer, oldData);
@@ -740,16 +771,18 @@ ArrayBufferObject::addSizeOfExcludingThi
     if (MOZ_UNLIKELY(buffer.isAsmJSArrayBuffer())) {
 #if defined (JS_CPU_X64)
         // On x64, ArrayBufferObject::prepareForAsmJS switches the
         // ArrayBufferObject to use mmap'd storage.
         sizes->nonHeapElementsAsmJS += buffer.byteLength();
 #else
         sizes->mallocHeapElementsAsmJS += mallocSizeOf(buffer.dataPointer());
 #endif
+    } else if (MOZ_UNLIKELY(buffer.isMappedArrayBuffer())) {
+        sizes->nonHeapElementsMapped += buffer.byteLength();
     } else if (buffer.dataPointer()) {
         sizes->mallocHeapElementsNonAsmJS += mallocSizeOf(buffer.dataPointer());
     }
 }
 
 /* static */ void
 ArrayBufferObject::finalize(FreeOp *fop, JSObject *obj)
 {
@@ -1004,17 +1037,17 @@ JS_NewArrayBuffer(JSContext *cx, uint32_
     JS_ASSERT(nbytes <= INT32_MAX);
     return ArrayBufferObject::create(cx, nbytes);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents)
 {
     JS_ASSERT(contents);
-    return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject);
+    return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject, false);
 }
 
 JS_PUBLIC_API(void *)
 JS_AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes)
 {
     return AllocateArrayBufferContents(maybecx, nbytes);
 }
 
@@ -1042,16 +1075,47 @@ JS_StealArrayBufferContents(JSContext *c
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
         return nullptr;
     }
 
     Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
     return ArrayBufferObject::stealContents(cx, buffer);
 }
 
+JS_PUBLIC_API(JSObject *)
+JS_NewMappedArrayBufferWithContents(JSContext *cx, size_t nbytes, void *contents)
+{
+    JS_ASSERT(contents);
+    return ArrayBufferObject::create(cx, nbytes, contents, TenuredObject, true);
+}
+
+JS_PUBLIC_API(void *)
+JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length)
+{
+    return ArrayBufferObject::createMappedArrayBuffer(fd, offset, length);
+}
+
+JS_PUBLIC_API(void)
+JS_ReleaseMappedArrayBufferContents(void *contents, size_t length)
+{
+    DeallocateMappedContent(contents, length);
+}
+
+JS_FRIEND_API(bool)
+JS_IsMappedArrayBufferObject(JSObject *obj)
+{
+    obj = CheckedUnwrap(obj);
+    if (!obj)
+        return false;
+
+    return obj->is<ArrayBufferObject>()
+           ? obj->as<ArrayBufferObject>().isMappedArrayBuffer()
+           : false;
+}
+
 JS_FRIEND_API(void *)
 JS_GetArrayBufferViewData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
     return obj->is<DataViewObject>() ? obj->as<DataViewObject>().dataPointer()
                                      : obj->as<TypedArrayObject>().viewData();
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -55,32 +55,34 @@ class ArrayBufferObject : public JSObjec
   public:
     static const uint8_t DATA_SLOT = 0;
     static const uint8_t BYTE_LENGTH_SLOT = 1;
     static const uint8_t VIEW_LIST_SLOT = 2;
     static const uint8_t FLAGS_SLOT = 3;
 
     static const uint8_t RESERVED_SLOTS = 4;
 
+    static const size_t ARRAY_BUFFER_ALIGNMENT = 8;
+
     static const Class class_;
 
     static const Class protoClass;
     static const JSFunctionSpec jsfuncs[];
     static const JSFunctionSpec jsstaticfuncs[];
 
     static bool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp);
 
     static bool fun_slice(JSContext *cx, unsigned argc, Value *vp);
 
     static bool fun_isView(JSContext *cx, unsigned argc, Value *vp);
 
     static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
 
     static ArrayBufferObject *create(JSContext *cx, uint32_t nbytes, void *contents = nullptr,
-                                     NewObjectKind newKind = GenericObject);
+                                     NewObjectKind newKind = GenericObject, bool mapped = false);
 
     static JSObject *createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
                                  uint32_t begin, uint32_t end);
 
     static bool createDataViewForThisImpl(JSContext *cx, CallArgs args);
     static bool createDataViewForThis(JSContext *cx, unsigned argc, Value *vp);
 
     template<typename T>
@@ -145,23 +147,26 @@ class ArrayBufferObject : public JSObjec
      * ArrayBuffer.prototype and neutered ArrayBuffers.
      */
     bool hasData() const {
         return getClass() == &class_;
     }
 
     bool isAsmJSArrayBuffer() const { return flags() & ASMJS_BUFFER; }
     bool isSharedArrayBuffer() const { return flags() & SHARED_BUFFER; }
+    bool isMappedArrayBuffer() const { return flags() & MAPPED_BUFFER; }
     bool isNeutered() const { return flags() & NEUTERED_BUFFER; }
 
     static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
     static bool canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
 
     static void finalize(FreeOp *fop, JSObject *obj);
 
+    static void *createMappedArrayBuffer(int fd, size_t offset, size_t length);
+
     static size_t flagsOffset() {
         return getFixedSlotOffset(FLAGS_SLOT);
     }
 
     static uint32_t neuteredFlag() { return NEUTERED_BUFFER; }
 
   protected:
     enum OwnsState {
@@ -183,17 +188,18 @@ class ArrayBufferObject : public JSObjec
         // The dataPointer() is owned by this buffer and should be released
         // when no longer in use. Releasing the pointer may be done by either
         // freeing or unmapping it, and how to do this is determined by the
         // buffer's other flags.
         OWNS_DATA          =  0x2,
 
         ASMJS_BUFFER       =  0x4,
         SHARED_BUFFER      =  0x8,
-        NEUTERED_BUFFER    = 0x10
+        MAPPED_BUFFER      = 0x10,
+        NEUTERED_BUFFER    = 0x20
     };
 
     uint32_t flags() const;
     void setFlags(uint32_t flags);
 
     bool inLiveList() const { return flags() & IN_LIVE_LIST; }
     void setInLiveList(bool value) {
         setFlags(value ? (flags() | IN_LIVE_LIST) : (flags() & ~IN_LIVE_LIST));
@@ -201,26 +207,28 @@ class ArrayBufferObject : public JSObjec
 
     bool ownsData() const { return flags() & OWNS_DATA; }
     void setOwnsData(OwnsState owns) {
         setFlags(owns ? (flags() | OWNS_DATA) : (flags() & ~OWNS_DATA));
     }
 
     void setIsAsmJSArrayBuffer() { setFlags(flags() | ASMJS_BUFFER); }
     void setIsSharedArrayBuffer() { setFlags(flags() | SHARED_BUFFER); }
+    void setIsMappedArrayBuffer() { setFlags(flags() | MAPPED_BUFFER); }
     void setIsNeutered() { setFlags(flags() | NEUTERED_BUFFER); }
 
     void initialize(size_t byteLength, void *data, OwnsState ownsState) {
         setByteLength(byteLength);
         setFlags(0);
         setViewListNoBarrier(nullptr);
         setDataPointer(data, ownsState);
     }
 
     void releaseAsmJSArray(FreeOp *fop);
+    void releaseMappedArray();
 };
 
 /*
  * ArrayBufferViewObject
  *
  * Common definitions shared by all ArrayBufferViews.
  */
 
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -383,16 +383,18 @@ Discard(uint64_t *buffer, size_t nbytes,
 
         uint64_t extraData = LittleEndian::readUint64(point++);
 
         if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
             continue;
 
         if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
             js_free(content);
+        } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) {
+            JS_ReleaseMappedArrayBufferContents(content, extraData);
         } else if (ownership == JS::SCTAG_TMO_SHARED_BUFFER) {
             SharedArrayRawBuffer *raw = static_cast<SharedArrayRawBuffer*>(content);
             if (raw)
                 raw->dropReference();
         } else if (cb && cb->freeTransfer) {
             cb->freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, cbClosure);
         } else {
             MOZ_ASSERT(false, "unknown ownership");
@@ -843,16 +845,17 @@ JSStructuredCloneWriter::writeTypedArray
 
     return out.write(tarr->byteOffset());
 }
 
 bool
 JSStructuredCloneWriter::writeArrayBuffer(HandleObject obj)
 {
     ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
+
     return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, buffer.byteLength()) &&
            out.writeBytes(buffer.dataPointer(), buffer.byteLength());
 }
 
 bool
 JSStructuredCloneWriter::startObject(HandleObject obj, bool *backref)
 {
     /* Handle cycles in the object graph. */
@@ -1031,17 +1034,20 @@ JSStructuredCloneWriter::transferOwnersh
 #endif
 
         if (obj->is<ArrayBufferObject>()) {
             size_t nbytes = obj->as<ArrayBufferObject>().byteLength();
             content = JS_StealArrayBufferContents(context(), obj);
             if (!content)
                 return false; // Destructor will clean up the already-transferred data
             tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
-            ownership = JS::SCTAG_TMO_ALLOC_DATA;
+            if (obj->as<ArrayBufferObject>().isMappedArrayBuffer())
+                ownership = JS::SCTAG_TMO_MAPPED_DATA;
+            else
+                ownership = JS::SCTAG_TMO_ALLOC_DATA;
             extraData = nbytes;
         } else if (obj->is<SharedArrayBufferObject>()) {
             SharedArrayRawBuffer *rawbuf = obj->as<SharedArrayBufferObject>().rawBufferObject();
 
             // Avoids a race condition where the parent thread frees the buffer
             // before the child has accepted the transferable.
             rawbuf->addReference();
 
@@ -1542,18 +1548,22 @@ JSStructuredCloneReader::readTransferMap
             return false;
 
         uint64_t extraData;
         if (!in.read(&extraData))
             return false;
 
         if (tag == SCTAG_TRANSFER_MAP_ARRAY_BUFFER) {
             size_t nbytes = extraData;
-            JS_ASSERT(data == JS::SCTAG_TMO_ALLOC_DATA);
-            obj = JS_NewArrayBufferWithContents(cx, nbytes, content);
+            JS_ASSERT(data == JS::SCTAG_TMO_ALLOC_DATA ||
+                      data == JS::SCTAG_TMO_MAPPED_DATA);
+            if (data == JS::SCTAG_TMO_ALLOC_DATA)
+                obj = JS_NewArrayBufferWithContents(cx, nbytes, content);
+            else if (data == JS::SCTAG_TMO_MAPPED_DATA)
+                obj = JS_NewMappedArrayBufferWithContents(cx, nbytes, content);
         } else if (tag == SCTAG_TRANSFER_MAP_SHARED_BUFFER) {
             JS_ASSERT(data == JS::SCTAG_TMO_SHARED_BUFFER);
             obj = SharedArrayBufferObject::New(context(), (SharedArrayRawBuffer *)content);
         } else {
             if (!callbacks || !callbacks->readTransfer) {
                 ReportErrorTransferable(cx, callbacks);
                 return false;
             }
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -410,17 +410,17 @@ mozJSComponentLoader::LoadModule(FileLoc
         if (NS_FAILED(rv))
             return nullptr;
     }
 
     ModuleEntry* mod;
     if (mModules.Get(spec, &mod))
     return mod;
 
-    nsAutoPtr<ModuleEntry> entry(new ModuleEntry);
+    nsAutoPtr<ModuleEntry> entry(new ModuleEntry(mContext));
 
     JSAutoRequest ar(mContext);
     RootedValue dummy(mContext);
     rv = ObjectForLocation(file, uri, &entry->obj, &entry->thisObjectKey,
                            &entry->location, false, &dummy);
     if (NS_FAILED(rv)) {
         return nullptr;
     }
@@ -716,49 +716,45 @@ mozJSComponentLoader::PrepareObjectForLo
         rv = xpc->WrapNative(aCx, obj, aComponentFile,
                              NS_GET_IID(nsIFile),
                              getter_AddRefs(locationHolder));
         NS_ENSURE_SUCCESS(rv, nullptr);
 
         RootedObject locationObj(aCx, locationHolder->GetJSObject());
         NS_ENSURE_TRUE(locationObj, nullptr);
 
-        if (!JS_DefineProperty(aCx, obj, "__LOCATION__",
-                               ObjectValue(*locationObj),
-                               nullptr, nullptr, 0)) {
+        if (!JS_DefineProperty(aCx, obj, "__LOCATION__", locationObj, 0))
             return nullptr;
-        }
     }
 
     nsAutoCString nativePath;
     rv = aURI->GetSpec(nativePath);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     // Expose the URI from which the script was imported through a special
     // variable that we insert into the JSM.
-    JSString *exposedUri = JS_NewStringCopyN(aCx, nativePath.get(),
-                                             nativePath.Length());
-    if (!JS_DefineProperty(aCx, obj, "__URI__",
-                           STRING_TO_JSVAL(exposedUri), nullptr, nullptr, 0)) {
+    RootedString exposedUri(aCx, JS_NewStringCopyN(aCx, nativePath.get(), nativePath.Length()));
+    NS_ENSURE_TRUE(exposedUri, nullptr);
+
+    if (!JS_DefineProperty(aCx, obj, "__URI__", exposedUri, 0))
         return nullptr;
-    }
 
     if (createdNewGlobal) {
         RootedObject global(aCx, holder->GetJSObject());
         JS_FireOnNewGlobalObject(aCx, global);
     }
 
     return obj;
 }
 
 nsresult
 mozJSComponentLoader::ObjectForLocation(nsIFile *aComponentFile,
                                         nsIURI *aURI,
-                                        JSObject **aObject,
-                                        JSScript **aTableScript,
+                                        MutableHandleObject aObject,
+                                        MutableHandleScript aTableScript,
                                         char **aLocation,
                                         bool aPropagateExceptions,
                                         MutableHandleValue aException)
 {
     JSCLContextHelper cx(mContext);
 
     JS_AbortIfWrongThread(JS_GetRuntime(cx));
 
@@ -999,31 +995,34 @@ mozJSComponentLoader::ObjectForLocation(
             LOG(("Successfully wrote to cache\n"));
         } else {
             LOG(("Failed to write to cache\n"));
         }
     }
 
     // Assign aObject here so that it's available to recursive imports.
     // See bug 384168.
-    *aObject = obj;
+    aObject.set(obj);
 
     RootedScript tableScript(cx, script);
     if (!tableScript) {
         tableScript = JS_GetFunctionScript(cx, function);
         MOZ_ASSERT(tableScript);
     }
 
-    *aTableScript = tableScript;
+    aTableScript.set(tableScript);
 
     if (js::GetObjectJSClass(obj) == &kFakeBackstagePassJSClass) {
         MOZ_ASSERT(mReuseLoaderGlobal);
-        // tableScript stays in the table until shutdown. To avoid it being
-        // collected and another script getting the same address, we root
-        // tableScript lower down in this function.
+        // tableScript stays in the table until shutdown.  It is rooted by
+        // virtue of the fact that aTableScript is a handle to
+        // ModuleEntry::thisObjectKey, which is a PersistentRootedScript.  Since
+        // ModuleEntries are never dynamically unloaded when mReuseLoaderGlobal
+        // is true, this prevents it from being collected and another script
+        // getting the same address.
         mThisObjects.Put(tableScript, obj);
     }
     bool ok = false;
 
     {
         AutoSaveContextOptions asco(cx);
         if (aPropagateExceptions)
             ContextOptionsRef(cx).setDontReportUncaught(true);
@@ -1035,33 +1034,31 @@ mozJSComponentLoader::ObjectForLocation(
         }
      }
 
     if (!ok) {
         if (aPropagateExceptions) {
             JS_GetPendingException(cx, aException);
             JS_ClearPendingException(cx);
         }
-        *aObject = nullptr;
-        *aTableScript = nullptr;
+        aObject.set(nullptr);
+        aTableScript.set(nullptr);
         mThisObjects.Remove(tableScript);
         return NS_ERROR_FAILURE;
     }
 
     /* Freed when we remove from the table. */
     *aLocation = ToNewCString(nativePath);
     if (!*aLocation) {
-        *aObject = nullptr;
-        *aTableScript = nullptr;
+        aObject.set(nullptr);
+        aTableScript.set(nullptr);
         mThisObjects.Remove(tableScript);
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    JS_AddNamedObjectRoot(cx, aObject, *aLocation);
-    JS_AddNamedScriptRoot(cx, aTableScript, *aLocation);
     return NS_OK;
 }
 
 /* static */ PLDHashOperator
 mozJSComponentLoader::ClearModules(const nsACString& key, ModuleEntry*& entry, void* cx)
 {
     entry->Clear();
     return PL_DHASH_REMOVE;
@@ -1233,17 +1230,17 @@ mozJSComponentLoader::ImportInto(const n
 
     nsAutoCString key;
     rv = resolvedURI->GetSpec(key);
     NS_ENSURE_SUCCESS(rv, rv);
 
     ModuleEntry* mod;
     nsAutoPtr<ModuleEntry> newEntry;
     if (!mImports.Get(key, &mod) && !mInProgressImports.Get(key, &mod)) {
-        newEntry = new ModuleEntry;
+        newEntry = new ModuleEntry(callercx);
         if (!newEntry)
             return NS_ERROR_OUT_OF_MEMORY;
         mInProgressImports.Put(key, newEntry);
 
         RootedValue exception(callercx);
         rv = ObjectForLocation(sourceLocalFile, resURI, &newEntry->obj,
                                &newEntry->thisObjectKey,
                                &newEntry->location, true, &exception);
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -68,18 +68,18 @@ class mozJSComponentLoader : public mozi
     JSObject* PrepareObjectForLocation(JSCLContextHelper& aCx,
                                        nsIFile* aComponentFile,
                                        nsIURI *aComponent,
                                        bool aReuseLoaderGlobal,
                                        bool *aRealFile);
 
     nsresult ObjectForLocation(nsIFile* aComponentFile,
                                nsIURI *aComponent,
-                               JSObject **aObject,
-                               JSScript **aTableScript,
+                               JS::MutableHandleObject aObject,
+                               JS::MutableHandleScript aTableScript,
                                char **location,
                                bool aCatchException,
                                JS::MutableHandleValue aException);
 
     nsresult ImportInto(const nsACString &aLocation,
                         JS::HandleObject targetObj,
                         JSContext *callercx,
                         JS::MutableHandleObject vp);
@@ -89,63 +89,62 @@ class mozJSComponentLoader : public mozi
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
     nsCOMPtr<nsIXPConnectJSObjectHolder> mLoaderGlobal;
     JSRuntime *mRuntime;
     JSContext *mContext;
 
     class ModuleEntry : public mozilla::Module
     {
     public:
-        ModuleEntry() : mozilla::Module() {
+        ModuleEntry(JSContext* aCx)
+          : mozilla::Module(), obj(aCx, nullptr), thisObjectKey(aCx, nullptr)
+        {
             mVersion = mozilla::Module::kVersion;
             mCIDs = nullptr;
             mContractIDs = nullptr;
             mCategoryEntries = nullptr;
             getFactoryProc = GetFactory;
             loadProc = nullptr;
             unloadProc = nullptr;
 
-            obj = nullptr;
-            thisObjectKey = nullptr;
             location = nullptr;
         }
 
         ~ModuleEntry() {
             Clear();
         }
 
         void Clear() {
             getfactoryobj = nullptr;
 
             if (obj) {
                 mozilla::AutoJSContext cx;
                 JSAutoCompartment ac(cx, obj);
 
                 JS_SetAllNonReservedSlotsToUndefined(cx, obj);
-                JS_RemoveObjectRoot(cx, &obj);
-                if (thisObjectKey)
-                    JS_RemoveScriptRoot(cx, &thisObjectKey);
+                obj = nullptr;
+                thisObjectKey = nullptr;
             }
 
             if (location)
                 NS_Free(location);
 
             obj = nullptr;
             thisObjectKey = nullptr;
             location = nullptr;
         }
 
         size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
         static already_AddRefed<nsIFactory> GetFactory(const mozilla::Module& module,
                                                        const mozilla::Module::CIDEntry& entry);
 
         nsCOMPtr<xpcIJSGetFactory> getfactoryobj;
-        JSObject            *obj;
-        JSScript            *thisObjectKey;
+        JS::PersistentRootedObject obj;
+        JS::PersistentRootedScript thisObjectKey;
         char                *location;
     };
 
     friend class ModuleEntry;
 
     static size_t DataEntrySizeOfExcludingThis(const nsACString& aKey, ModuleEntry* const& aData,
                                                mozilla::MallocSizeOf aMallocSizeOf, void* arg);
     static size_t ClassEntrySizeOfExcludingThis(const nsACString& aKey,
--- a/js/xpconnect/public/nsAutoJSValHolder.h
+++ b/js/xpconnect/public/nsAutoJSValHolder.h
@@ -57,38 +57,34 @@ public:
     return Hold(JS_GetRuntime(aCx));
   }
 
   /**
    * Hold by rooting on the runtime.
    * Note that mVal may be JSVAL_NULL, which is not a problem.
    */
   bool Hold(JSRuntime* aRt) {
-    // Do we really care about different runtimes?
-    if (mRt && aRt != mRt) {
-      JS_RemoveValueRootRT(mRt, &mVal);
-      mRt = nullptr;
-    }
+    MOZ_ASSERT_IF(mRt, mRt == aRt);
 
-    if (!mRt && JS_AddNamedValueRootRT(aRt, &mVal, "nsAutoJSValHolder")) {
+    if (!mRt && JS::AddNamedValueRootRT(aRt, &mVal, "nsAutoJSValHolder")) {
       mRt = aRt;
     }
 
     return !!mRt;
   }
 
   /**
    * Manually release, nullifying mVal, and mRt, but returning
    * the original JS::Value.
    */
   JS::Value Release() {
     JS::Value oldval = mVal;
 
     if (mRt) {
-      JS_RemoveValueRootRT(mRt, &mVal); // infallible
+      JS::RemoveValueRootRT(mRt, &mVal); // infallible
       mRt = nullptr;
     }
 
     mVal = JSVAL_NULL;
 
     return oldval;
   }
 
@@ -103,37 +99,34 @@ public:
    * Explicit JSObject* conversion.
    */
   JSObject* ToJSObject() const {
     return mVal.isObject()
          ? &mVal.toObject()
          : nullptr;
   }
 
-  JS::Value* ToJSValPtr() {
-    return &mVal;
-  }
-
   /**
    * Pretend to be a JS::Value.
    */
   operator JS::Value() const { return mVal; }
+  JS::Value get() const { return mVal; }
 
   nsAutoJSValHolder &operator=(JSObject* aOther) {
     return *this = OBJECT_TO_JSVAL(aOther);
   }
 
   nsAutoJSValHolder &operator=(JS::Value aOther) {
 #ifdef DEBUG
     if (JSVAL_IS_GCTHING(aOther) && !JSVAL_IS_NULL(aOther)) {
       MOZ_ASSERT(IsHeld(), "Not rooted!");
     }
 #endif
     mVal = aOther;
     return *this;
   }
 
 private:
-  JS::Value mVal;
+  JS::Heap<JS::Value> mVal;
   JSRuntime* mRt;
 };
 
 #endif /* __NSAUTOJSVALHOLDER_H__ */
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3426,22 +3426,22 @@ nsXPCComponents_Utils::GetJSEngineTeleme
     RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
     if (!obj)
         return NS_ERROR_OUT_OF_MEMORY;
 
     unsigned attrs = JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
 
     size_t i = JS_SetProtoCalled(cx);
     RootedValue v(cx, DoubleValue(i));
-    if (!JS_DefineProperty(cx, obj, "setProto", v, nullptr, nullptr, attrs))
+    if (!JS_DefineProperty(cx, obj, "setProto", v, attrs))
         return NS_ERROR_OUT_OF_MEMORY;
 
     i = JS_GetCustomIteratorCount(cx);
     v.setDouble(i);
-    if (!JS_DefineProperty(cx, obj, "customIter", v, nullptr, nullptr, attrs))
+    if (!JS_DefineProperty(cx, obj, "customIter", v, attrs))
         return NS_ERROR_OUT_OF_MEMORY;
 
     rval.setObject(*obj);
     return NS_OK;
 }
 
 class MOZ_STACK_CLASS CloneIntoOptions : public OptionsBase
 {
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -18,20 +18,16 @@ using namespace JS;
 using namespace xpc;
 using mozilla::dom::DestroyProtoAndIfaceCache;
 
 /***************************************************************************/
 
 XPCJSContextStack::~XPCJSContextStack()
 {
     if (mSafeJSContext) {
-        {
-            JSAutoRequest ar(mSafeJSContext);
-            JS_RemoveObjectRoot(mSafeJSContext, &mSafeJSContextGlobal);
-        }
         mSafeJSContextGlobal = nullptr;
         JS_DestroyContextNoGC(mSafeJSContext);
         mSafeJSContext = nullptr;
     }
 }
 
 JSContext*
 XPCJSContextStack::Pop()
@@ -182,17 +178,16 @@ XPCJSContextStack::InitSafeJSContext()
     JS::CompartmentOptions options;
     options.setZone(JS::SystemZone)
            .setTrace(TraceXPCGlobal);
     mSafeJSContextGlobal = CreateGlobalObject(mSafeJSContext,
                                               &SafeJSContextGlobalClass,
                                               principal, options);
     if (!mSafeJSContextGlobal)
         MOZ_CRASH();
-    JS_AddNamedObjectRoot(mSafeJSContext, &mSafeJSContextGlobal, "SafeJSContext global");
 
     // Note: make sure to set the private before calling
     // InitClasses
     nsRefPtr<SandboxPrivate> sp = new SandboxPrivate(principal, mSafeJSContextGlobal);
     JS_SetPrivate(mSafeJSContextGlobal, sp.forget().take());
 
     // After this point either glob is null and the
     // nsIScriptObjectPrincipal ownership is either handled by the
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2156,16 +2156,22 @@ ReportCompartmentStats(const JS::Compart
     }
     if (nonHeapElementsAsmJS > 0) {
         REPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/non-heap/elements/asm.js"),
             KIND_NONHEAP, nonHeapElementsAsmJS,
             "asm.js array buffer elements outside both the malloc heap and "
             "the GC heap.");
     }
 
+    if (cStats.objectsExtra.nonHeapElementsMapped > 0) {
+        REPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/non-heap/elements/mapped"),
+            KIND_NONHEAP, cStats.objectsExtra.nonHeapElementsMapped,
+            "Memory-mapped array buffer elements.");
+    }
+
     REPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/non-heap/code/asm.js"),
         KIND_NONHEAP, cStats.objectsExtra.nonHeapCodeAsmJS,
         "AOT-compiled asm.js code.");
 
     ZCREPORT_BYTES(cJSPathPrefix + NS_LITERAL_CSTRING("objects/malloc-heap/asm.js-module-data"),
         cStats.objectsExtra.mallocHeapAsmJSModuleData,
         "asm.js module data.");
 
@@ -3033,17 +3039,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
    mGCIsRunning(false),
    mWrappedJSToReleaseArray(),
    mNativesToReleaseArray(),
    mDoingFinalization(false),
    mVariantRoots(nullptr),
    mWrappedJSRoots(nullptr),
    mObjectHolderRoots(nullptr),
    mWatchdogManager(new WatchdogManager(MOZ_THIS_IN_INITIALIZER_LIST())),
-   mJunkScope(nullptr),
+   mJunkScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr),
    mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite())
 {
     DOM_InitInterfaces();
 
     // these jsids filled in later when we have a JSContext to work with.
     mStrIDs[0] = JSID_VOID;
 
     MOZ_ASSERT(Runtime());
@@ -3471,23 +3477,17 @@ XPCJSRuntime::GetJunkScope()
         AutoSafeJSContext cx;
         SandboxOptions options;
         options.sandboxName.AssignASCII("XPConnect Junk Compartment");
         RootedValue v(cx);
         nsresult rv = CreateSandboxObject(cx, &v, nsContentUtils::GetSystemPrincipal(), options);
         NS_ENSURE_SUCCESS(rv, nullptr);
 
         mJunkScope = js::UncheckedUnwrap(&v.toObject());
-        JS_AddNamedObjectRoot(cx, &mJunkScope, "XPConnect Junk Compartment");
     }
     return mJunkScope;
 }
 
 void
 XPCJSRuntime::DeleteJunkScope()
 {
-    if(!mJunkScope)
-        return;
-
-    AutoSafeJSContext cx;
-    JS_RemoveObjectRoot(cx, &mJunkScope);
     mJunkScope = nullptr;
 }
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -117,20 +117,20 @@ xpc_qsDefineQuickStubs(JSContext *cx, JS
         if (entry) {
             for (;;) {
                 // Define quick stubs for attributes.
                 const xpc_qsPropertySpec *ps = propspecs + entry->prop_index;
                 const xpc_qsPropertySpec *ps_end = ps + entry->n_props;
                 for ( ; ps < ps_end; ++ps) {
                     if (!JS_DefineProperty(cx, proto,
                                            stringTable + ps->name_index,
-                                           JSVAL_VOID,
+                                           JS::UndefinedHandleValue,
+                                           flags | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS,
                                            (JSPropertyOp)ps->getter,
-                                           (JSStrictPropertyOp)ps->setter,
-                                           flags | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS))
+                                           (JSStrictPropertyOp)ps->setter))
                         return false;
                 }
 
                 // Define quick stubs for methods.
                 const xpc_qsFunctionSpec *fs = funcspecs + entry->func_index;
                 const xpc_qsFunctionSpec *fs_end = fs + entry->n_funcs;
                 for ( ; fs < fs_end; ++fs) {
                     if (!JS_DefineFunction(cx, proto,
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -645,62 +645,66 @@ File(JSContext *cx, unsigned argc, Value
   if (NS_FAILED(rv)) {
     JS_ReportError(cx, "Could not wrap native object!");
     return false;
   }
 
   return true;
 }
 
-static Value sScriptedInterruptCallback = UndefinedValue();
+static Maybe<PersistentRootedValue> sScriptedInterruptCallback;
 
 static bool
 XPCShellInterruptCallback(JSContext *cx)
 {
+    MOZ_ASSERT(!sScriptedInterruptCallback.empty());
+    RootedValue callback(cx, sScriptedInterruptCallback.ref());
+
     // If no interrupt callback was set by script, no-op.
-    if (sScriptedInterruptCallback.isUndefined())
+    if (callback.isUndefined())
         return true;
 
-    JSAutoCompartment ac(cx, &sScriptedInterruptCallback.toObject());
+    JSAutoCompartment ac(cx, &callback.toObject());
     RootedValue rv(cx);
-    RootedValue callback(cx, sScriptedInterruptCallback);
     if (!JS_CallFunctionValue(cx, JS::NullPtr(), callback, JS::HandleValueArray::empty(), &rv) ||
         !rv.isBoolean())
     {
         NS_WARNING("Scripted interrupt callback failed! Terminating script.");
         JS_ClearPendingException(cx);
         return false;
     }
 
     return rv.toBoolean();
 }
 
 static bool
 SetInterruptCallback(JSContext *cx, unsigned argc, jsval *vp)
 {
+    MOZ_ASSERT(!sScriptedInterruptCallback.empty());
+
     // Sanity-check args.
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "Wrong number of arguments");
         return false;
     }
 
     // Allow callers to remove the interrupt callback by passing undefined.
     if (args[0].isUndefined()) {
-        sScriptedInterruptCallback = UndefinedValue();
+        sScriptedInterruptCallback.ref() = UndefinedValue();
         return true;
     }
 
     // Otherwise, we should have a callable object.
     if (!args[0].isObject() || !JS_ObjectIsCallable(cx, &args[0].toObject())) {
         JS_ReportError(cx, "Argument must be callable");
         return false;
     }
 
-    sScriptedInterruptCallback = args[0];
+    sScriptedInterruptCallback.ref() = args[0];
 
     return true;
 }
 
 static bool
 SimulateActivityCallback(JSContext *cx, unsigned argc, jsval *vp)
 {
     // Sanity-check args.
@@ -793,34 +797,29 @@ env_setProperty(JSContext *cx, HandleObj
     return true;
 }
 
 static bool
 env_enumerate(JSContext *cx, HandleObject obj)
 {
     static bool reflected;
     char **evp, *name, *value;
-    JSString *valstr;
+    RootedString valstr(cx);
     bool ok;
 
     if (reflected)
         return true;
 
     for (evp = (char **)JS_GetPrivate(obj); (name = *evp) != nullptr; evp++) {
         value = strchr(name, '=');
         if (!value)
             continue;
         *value++ = '\0';
         valstr = JS_NewStringCopyZ(cx, value);
-        if (!valstr) {
-            ok = false;
-        } else {
-            ok = JS_DefineProperty(cx, obj, name, STRING_TO_JSVAL(valstr),
-                                   nullptr, nullptr, JSPROP_ENUMERATE);
-        }
+        ok = valstr ? JS_DefineProperty(cx, obj, name, valstr, JSPROP_ENUMERATE) : false;
         value[-1] = '=';
         if (!ok)
             return false;
     }
 
     reflected = true;
     return true;
 }
@@ -1085,20 +1084,18 @@ ProcessArgs(JSContext *cx, JS::Handle<JS
 
     /*
      * Create arguments early and define it to root it, so it's safe from any
      * GC calls nested below, and so it is available to -f <file> arguments.
      */
     argsObj = JS_NewArrayObject(cx, 0);
     if (!argsObj)
         return 1;
-    if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj),
-                           nullptr, nullptr, 0)) {
+    if (!JS_DefineProperty(cx, obj, "arguments", argsObj, 0))
         return 1;
-    }
 
     for (size_t j = 0, length = argc - i; j < length; j++) {
         JSString *str = JS_NewStringCopyZ(cx, argv[i++]);
         if (!str)
             return 1;
         if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str),
                               nullptr, nullptr, JSPROP_ENUMERATE)) {
             return 1;
@@ -1466,16 +1463,17 @@ XRE_XPCShellMain(int argc, char **argv, 
             return 1;
         }
 
         rtsvc->RegisterContextCallback(ContextCallback);
 
         // Override the default XPConnect interrupt callback. We could store the
         // old one and restore it before shutting down, but there's not really a
         // reason to bother.
+        sScriptedInterruptCallback.construct(rt, UndefinedValue());
         JS_SetInterruptCallback(rt, XPCShellInterruptCallback);
 
         cx = JS_NewContext(rt, 8192);
         if (!cx) {
             printf("JS_NewContext failed!\n");
             return 1;
         }
 
@@ -1575,22 +1573,20 @@ XRE_XPCShellMain(int argc, char **argv, 
             }
 
             JS_SetPrivate(envobj, envp);
 
             nsAutoString workingDirectory;
             if (GetCurrentWorkingDirectory(workingDirectory))
                 gWorkingDirectory = &workingDirectory;
 
-            JS_DefineProperty(cx, glob, "__LOCATION__", JSVAL_VOID,
-                              GetLocationProperty, nullptr, 0);
+            JS_DefineProperty(cx, glob, "__LOCATION__", JS::UndefinedHandleValue, 0,
+                              GetLocationProperty, nullptr);
 
-            JS_AddValueRoot(cx, &sScriptedInterruptCallback);
             result = ProcessArgs(cx, glob, argv, argc, &dirprovider);
-            JS_RemoveValueRoot(cx, &sScriptedInterruptCallback);
 
             JS_DropPrincipals(rt, gJSPrincipals);
             JS_SetAllNonReservedSlotsToUndefined(cx, glob);
             JS_GC(rt);
         }
         pusher.Pop();
         JS_GC(rt);
         JS_DestroyContext(cx);
@@ -1598,16 +1594,18 @@ XRE_XPCShellMain(int argc, char **argv, 
 
     if (!XRE_ShutdownTestShell())
         NS_ERROR("problem shutting down testshell");
 
     // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
     rv = NS_ShutdownXPCOM( nullptr );
     MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
 
+    sScriptedInterruptCallback.destroyIfConstructed();
+
 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
     // test of late call and release (see above)
     JSContext* bogusCX;
     bogus->Peek(&bogusCX);
     bogus = nullptr;
 #endif
 
     appDir = nullptr;
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -2114,17 +2114,17 @@ CallMethodHelper::ConvertIndependentPara
     if (paramInfo.IsIndirect())
         dp->SetIndirect();
 
     // The JSVal proper is always stored within the 'val' union and passed
     // indirectly, regardless of in/out-ness.
     if (type_tag == nsXPTType::T_JSVAL) {
         // Root the value.
         dp->val.j = JSVAL_VOID;
-        if (!JS_AddValueRoot(mCallContext, &dp->val.j))
+        if (!js::AddRawValueRoot(mCallContext, &dp->val.j, "XPCWrappedNative::CallMethod param"))
             return false;
     }
 
     // Flag cleanup for anything that isn't self-contained.
     if (!type.IsArithmetic())
         dp->SetValNeedsCleanup();
 
     // Even if there's nothing to convert, we still need to examine the
@@ -2308,17 +2308,17 @@ CallMethodHelper::CleanupParam(nsXPTCMin
 
     // Pointers may sometimes be null even if cleanup was requested. Combine
     // the null checking for all the different types into one check here.
     if (type.TagPart() != nsXPTType::T_JSVAL && param.val.p == nullptr)
         return;
 
     switch (type.TagPart()) {
         case nsXPTType::T_JSVAL:
-            JS_RemoveValueRoot(mCallContext, (jsval*)&param.val);
+            js::RemoveRawValueRoot(mCallContext, (jsval*)&param.val);
             break;
         case nsXPTType::T_INTERFACE:
         case nsXPTType::T_INTERFACE_IS:
             ((nsISupports*)param.val.p)->Release();
             break;
         case nsXPTType::T_ASTRING:
         case nsXPTType::T_DOMSTRING:
             nsXPConnect::GetRuntimeInstance()->DeleteShortLivedString((nsString*)param.val.p);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -592,17 +592,17 @@ private:
     bool mDoingFinalization;
     XPCRootSetElem *mVariantRoots;
     XPCRootSetElem *mWrappedJSRoots;
     XPCRootSetElem *mObjectHolderRoots;
     nsTArray<xpcGCCallback> extraGCCallbacks;
     nsTArray<xpcContextCallback> extraContextCallbacks;
     nsRefPtr<WatchdogManager> mWatchdogManager;
     JS::GCSliceCallback mPrevGCSliceCallback;
-    JSObject* mJunkScope;
+    JS::PersistentRootedObject mJunkScope;
     nsRefPtr<AsyncFreeSnowWhite> mAsyncSnowWhiteFreer;
 
     mozilla::TimeStamp mSlowScriptCheckpoint;
 
 #define XPCCCX_STRING_CACHE_SIZE 2
 
     mozilla::Maybe<nsString> mScratchStrings[XPCCCX_STRING_CACHE_SIZE];
 
@@ -2763,17 +2763,17 @@ void PopJSContextNoScriptContext();
 } /* namespace xpc */
 
 class XPCJSContextStack
 {
 public:
     XPCJSContextStack(XPCJSRuntime *aRuntime)
       : mRuntime(aRuntime)
       , mSafeJSContext(nullptr)
-      , mSafeJSContextGlobal(nullptr)
+      , mSafeJSContextGlobal(aRuntime->Runtime(), nullptr)
     { }
 
     virtual ~XPCJSContextStack();
 
     uint32_t Count()
     {
         return mStack.Length();
     }
@@ -2799,17 +2799,17 @@ private:
     // We make these private so that stack manipulation can only happen
     // through one of the above friends.
     JSContext *Pop();
     bool Push(JSContext *cx);
 
     AutoInfallibleTArray<XPCJSContextInfo, 16> mStack;
     XPCJSRuntime* mRuntime;
     JSContext*  mSafeJSContext;
-    JSObject* mSafeJSContextGlobal;
+    JS::PersistentRootedObject mSafeJSContextGlobal;
 };
 
 /***************************************************************************/
 // 'Components' object implementations. nsXPCComponentsBase has the
 // less-privileged stuff that we're willing to expose to XBL.
 
 class nsXPCComponentsBase : public nsIXPCComponentsBase
 {
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 support-files =
   bug503926.xul
   file_bug618176.xul
+  file_bug996069.html
   file_evalInSandbox.html
   file_expandosharing.jsm
   outoflinexulscript.js
   subscript.js
   utf8_subscript.js
 
 [test_APIExposer.xul]
 [test_bug361111.xul]
@@ -46,16 +47,17 @@ support-files =
 [test_bug812415.xul]
 [test_bug853283.xul]
 [test_bug853571.xul]
 [test_bug858101.xul]
 [test_bug860494.xul]
 [test_bug866823.xul]
 [test_bug895340.xul]
 [test_bug932906.xul]
+[test_bug996069.xul]
 [test_xrayToJS.xul]
 [test_chrometoSource.xul]
 [test_cloneInto.xul]
 [test_cows.xul]
 [test_documentdomain.xul]
 [test_doublewrappedcompartments.xul]
 [test_evalInSandbox.xul]
 [test_evalInWindow.xul]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/file_bug996069.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head></head>
+<body>
+  <script>
+    if (window.opener && window.opener.finishTest) {
+      window.opener.finishTest();
+    }
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/test_bug996069.xul
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=996069
+-->
+<window title="Mozilla Bug 996069"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=996069"
+     target="_blank">Mozilla Bug 996069</a>
+  </body>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+  const Cu = Components.utils;
+  /** Test for Bug 996069 **/
+  SimpleTest.waitForExplicitFinish();
+
+  function loaded() {
+    var ifr = document.getElementById("ifr").contentWindow;
+    var sb = new Cu.Sandbox([ifr],
+                            { sandboxPrototype: ifr });
+
+    ifr.wrappedJSObject.finishTest = function() {
+      // If we got here we did not hit the NS_ReleaseAssert...
+      ok(true, "nsExpandedPrincipal should not be inherited by content windows");
+
+      // But let's be sure that the new window does not have nsEP
+      newWin.wrappedJSObject.obj = Cu.evalInSandbox("var obj = { foo: 'bar' }; obj", sb);
+      try {
+        newWin.eval("obj.foo");
+        ok(false, "newWin should not have access to object from a scope with nsExpandedPrincipal");
+      } catch (e) {
+        ok(/Permission denied/.exec(e.message), "newWin should not have access to object from a scope with nsExpandedPrincipal");
+      }
+      newWin.close();
+      SimpleTest.finish();
+    };
+
+    var newWin = Cu.evalInSandbox(
+      "window.open('http://example.org/chrome/js/xpconnect/tests/chrome/file_bug996069.html');",
+      sb);
+  }
+
+  ]]>
+  </script>
+  <iframe id="ifr" onload="loaded();" type="content" src="http://example.org/chrome/js/xpconnect/tests/chrome/file_bug996069.html" />
+</window>
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -682,17 +682,25 @@ RestyleManager::ProcessRestyledFrames(ns
       NS_ASSERTION(frame, "This shouldn't happen");
 
       if ((frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
           (frame->GetStateBits() & NS_FRAME_IS_NONDISPLAY)) {
         // frame does not maintain overflow rects, so avoid calling
         // FinishAndStoreOverflow on it:
         hint = NS_SubtractHint(hint,
                  NS_CombineHint(nsChangeHint_UpdateOverflow,
-                                nsChangeHint_ChildrenOnlyTransform));
+                   NS_CombineHint(nsChangeHint_ChildrenOnlyTransform,
+                                  nsChangeHint_UpdatePostTransformOverflow)));
+      }
+
+      if (!(frame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED)) {
+        // Frame can not be transformed, and thus a change in transform will
+        // have no effect and we should not use the
+        // nsChangeHint_UpdatePostTransformOverflow hint.
+        hint = NS_SubtractHint(hint, nsChangeHint_UpdatePostTransformOverflow);
       }
 
       if (hint & nsChangeHint_UpdateEffects) {
         for (nsIFrame *cont = frame; cont;
              cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
           nsSVGEffects::UpdateEffects(cont);
         }
       }
@@ -710,17 +718,20 @@ RestyleManager::ProcessRestyledFrames(ns
         // It is possible for this to fall back to a reflow
         if (!RecomputePosition(frame)) {
           didReflowThisFrame = true;
         }
       }
       NS_ASSERTION(!(hint & nsChangeHint_ChildrenOnlyTransform) ||
                    (hint & nsChangeHint_UpdateOverflow),
                    "nsChangeHint_UpdateOverflow should be passed too");
-      if ((hint & nsChangeHint_UpdateOverflow) && !didReflowThisFrame) {
+      if (!didReflowThisFrame &&
+          (hint & (nsChangeHint_UpdateOverflow |
+                   nsChangeHint_UpdatePostTransformOverflow))) {
+        OverflowChangedTracker::ChangeKind changeKind;
         if (hint & nsChangeHint_ChildrenOnlyTransform) {
           // The overflow areas of the child frames need to be updated:
           nsIFrame* hintFrame = GetFrameForChildrenOnlyTransformHint(frame);
           nsIFrame* childFrame = hintFrame->GetFirstPrincipalChild();
           NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame),
                        "SVG frames should not have continuations "
                        "or ib-split siblings");
           NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(hintFrame),
@@ -728,32 +739,41 @@ RestyleManager::ProcessRestyledFrames(ns
                        "or ib-split siblings");
           for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
             NS_ABORT_IF_FALSE(childFrame->IsFrameOfType(nsIFrame::eSVG),
                               "Not expecting non-SVG children");
             // If |childFrame| is dirty or has dirty children, we don't bother
             // updating overflows since that will happen when it's reflowed.
             if (!(childFrame->GetStateBits() &
                   (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
-              mOverflowChangedTracker.AddFrame(childFrame);
+              mOverflowChangedTracker.AddFrame(childFrame,
+                           OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED);
             }
             NS_ASSERTION(!nsLayoutUtils::GetNextContinuationOrIBSplitSibling(childFrame),
                          "SVG frames should not have continuations "
                          "or ib-split siblings");
             NS_ASSERTION(childFrame->GetParent() == hintFrame,
                          "SVG child frame not expected to have different parent");
           }
         }
         // If |frame| is dirty or has dirty children, we don't bother updating
         // overflows since that will happen when it's reflowed.
         if (!(frame->GetStateBits() &
               (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN))) {
+          // If we have both nsChangeHint_UpdateOverflow and
+          // nsChangeHint_UpdatePostTransformOverflow, CHILDREN_AND_PARENT_CHANGED
+          // is selected as it is stronger.
+          if (hint & nsChangeHint_UpdateOverflow) {
+            changeKind = OverflowChangedTracker::CHILDREN_AND_PARENT_CHANGED;
+          } else {
+            changeKind = OverflowChangedTracker::TRANSFORM_CHANGED;
+          }
           for (nsIFrame *cont = frame; cont; cont =
                  nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-            mOverflowChangedTracker.AddFrame(cont);
+            mOverflowChangedTracker.AddFrame(cont, changeKind);
           }
         }
       }
       if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) {
         mPresContext->PresShell()->SynthesizeMouseMove(false);
         didUpdateCursor = true;
       }
     }
--- a/layout/base/RestyleTracker.h
+++ b/layout/base/RestyleTracker.h
@@ -23,16 +23,36 @@ class RestyleManager;
 /** 
  * Helper class that collects a list of frames that need
  * UpdateOverflow() called on them, and coalesces them
  * to avoid walking up the same ancestor tree multiple times.
  */
 class OverflowChangedTracker
 {
 public:
+  enum ChangeKind {
+    /**
+     * The frame was explicitly added as a result of
+     * nsChangeHint_UpdatePostTransformOverflow and hence may have had a style
+     * change that changes its geometry relative to parent, without reflowing.
+     */
+    TRANSFORM_CHANGED,
+    /**
+     * The overflow areas of children have changed
+     * and we need to call UpdateOverflow on the frame.
+     */
+    CHILDREN_CHANGED,
+    /**
+     * The overflow areas of children have changed
+     * and we need to call UpdateOverflow on the frame.
+     * Also call UpdateOverflow on the parent even if the
+     * overflow areas of the frame does not change.
+     */
+    CHILDREN_AND_PARENT_CHANGED
+  };
 
   OverflowChangedTracker() :
     mSubtreeRoot(nullptr)
   {}
 
   ~OverflowChangedTracker()
   {
     NS_ASSERTION(mEntryList.empty(), "Need to flush before destroying!");
@@ -44,24 +64,28 @@ public:
    *
    * If there are pre-transform overflow areas stored for this
    * frame, then we will call FinishAndStoreOverflow with those
    * areas instead of UpdateOverflow().
    *
    * If the overflow area changes, then UpdateOverflow will also
    * be called on the parent.
    */
-  void AddFrame(nsIFrame* aFrame) {
+  void AddFrame(nsIFrame* aFrame, ChangeKind aChangeKind) {
     uint32_t depth = aFrame->GetDepthInFrameTree();
-    if (mEntryList.empty() ||
-        !mEntryList.find(Entry(aFrame, depth))) {
-      // All frames in mEntryList at this stage have STYLE_CHANGED so we don't
-      // need to worry about setting the STYLE_CHANGED flag if 'find'
-      // returns true.
-      mEntryList.insert(new Entry(aFrame, depth, STYLE_CHANGED));
+    Entry *entry = nullptr;
+    if (!mEntryList.empty()) {
+      entry = mEntryList.find(Entry(aFrame, depth));
+    }
+    if (entry == nullptr) {
+      // Add new entry.
+      mEntryList.insert(new Entry(aFrame, depth, aChangeKind));
+    } else {
+      // Update the existing entry if the new value is stronger.
+      entry->mChangeKind = std::max(entry->mChangeKind, aChangeKind);
     }
   }
 
   /**
    * Remove a frame.
    */
   void RemoveFrame(nsIFrame* aFrame) {
     if (mEntryList.empty()) {
@@ -89,78 +113,81 @@ public:
    * Start from those deepest in the frame tree and works upwards. This stops 
    * us from processing the same frame twice.
    */
   void Flush() {
     while (!mEntryList.empty()) {
       Entry *entry = mEntryList.removeMin();
       nsIFrame *frame = entry->mFrame;
 
-      bool overflowChanged;
-      if (entry->mFlags & CHILDREN_CHANGED) {
+      bool overflowChanged = false;
+      if (entry->mChangeKind == CHILDREN_AND_PARENT_CHANGED) {
         // Need to union the overflow areas of the children.
+        // Always update the parent, even if the overflow does not change.
+        frame->UpdateOverflow();
+        overflowChanged = true;
+      } else if (entry->mChangeKind == CHILDREN_CHANGED) {
+        // Need to union the overflow areas of the children.
+        // Only update the parent if the overflow changes.
         overflowChanged = frame->UpdateOverflow();
       } else {
-        nsOverflowAreas* pre = static_cast<nsOverflowAreas*>
-          (frame->Properties().Get(frame->PreTransformOverflowAreasProperty()));
-        if (pre) {
-          // Since we have the pre-transform-overflow-areas, we can take a
-          // faster path that doesn't require unioning the overflow areas
-          // of our children.
+        // Take a faster path that doesn't require unioning the overflow areas
+        // of our children.
+
+#ifdef DEBUG
+        bool hasInitialOverflowPropertyApplied = false;
+        frame->Properties().Get(nsIFrame::DebugInitialOverflowPropertyApplied(),
+                                 &hasInitialOverflowPropertyApplied);
+        NS_ASSERTION(hasInitialOverflowPropertyApplied,
+                     "InitialOverflowProperty must be set first.");
+#endif
+
+        nsOverflowAreas* overflow = 
+          static_cast<nsOverflowAreas*>(frame->Properties().Get(nsIFrame::InitialOverflowProperty()));
+        if (overflow) {
           // FinishAndStoreOverflow will change the overflow areas passed in,
           // so make a copy.
-          nsOverflowAreas overflowAreas = *pre;
-          frame->FinishAndStoreOverflow(overflowAreas, frame->GetSize());
-          // We can't tell if the overflow changed, so be conservative
-          overflowChanged = true;
+          nsOverflowAreas overflowCopy = *overflow;
+          frame->FinishAndStoreOverflow(overflowCopy, frame->GetSize());
         } else {
-          // We can't take the faster path here. Do it the hard way.
-          overflowChanged = frame->UpdateOverflow();
+          nsRect bounds(nsPoint(0, 0), frame->GetSize());
+          nsOverflowAreas boundsOverflow;
+          boundsOverflow.SetAllTo(bounds);
+          frame->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
         }
+
+        // We can't tell if the overflow changed, so be conservative
+        overflowChanged = true;
       }
 
       // If the frame style changed (e.g. positioning offsets)
       // then we need to update the parent with the overflow areas of its
       // children.
-      if (overflowChanged || (entry->mFlags & STYLE_CHANGED)) {
+      if (overflowChanged) {
         nsIFrame *parent = frame->GetParent();
         if (parent && parent != mSubtreeRoot) {
           Entry* parentEntry = mEntryList.find(Entry(parent, entry->mDepth - 1));
           if (parentEntry) {
-            parentEntry->mFlags |= CHILDREN_CHANGED;
+            parentEntry->mChangeKind = CHILDREN_CHANGED;
           } else {
             mEntryList.insert(new Entry(parent, entry->mDepth - 1, CHILDREN_CHANGED));
           }
         }
       }
       delete entry;
     }
   }
   
 private:
-  enum {
-    /**
-     * Set if the overflow areas of children have changed so we need to call
-     * UpdateOverflow on the frame.
-     */
-    CHILDREN_CHANGED = 0x01,
-    /**
-     * True if the frame was explicitly added and hence may have had a style
-     * change that changes its geometry relative to parent, without reflowing.
-     * In this case we must update overflow on the frame's parent even if
-     * this frame's overflow did not change.
-     */
-    STYLE_CHANGED = 0x02
-  };
   struct Entry : SplayTreeNode<Entry>
   {
-    Entry(nsIFrame* aFrame, uint32_t aDepth, uint8_t aFlags = 0)
+    Entry(nsIFrame* aFrame, uint32_t aDepth, ChangeKind aChangeKind = CHILDREN_CHANGED)
       : mFrame(aFrame)
       , mDepth(aDepth)
-      , mFlags(aFlags)
+      , mChangeKind(aChangeKind)
     {}
 
     bool operator==(const Entry& aOther) const
     {
       return mFrame == aOther.mFrame;
     }
  
     /**
@@ -184,17 +211,17 @@ private:
       } else {
         return 1;
       }
     }
 
     nsIFrame* mFrame;
     /* Depth in the frame tree */
     uint32_t mDepth;
-    uint8_t mFlags;
+    ChangeKind mChangeKind;
   };
 
   /* A list of frames to process, sorted by their depth in the frame tree */
   SplayTree<Entry, Entry> mEntryList;
 
   /* Don't update overflow of this frame or its ancestors. */
   const nsIFrame* mSubtreeRoot;
 };
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -67,61 +67,67 @@ enum nsChangeHint {
   /**
    * Change requires frame change (e.g., display:).
    * This subsumes all the above. Reconstructs all frame descendants,
    * including following placeholders to out-of-flows.
    */
   nsChangeHint_ReconstructFrame = 0x400,
 
   /**
-   * The frame's effect on its ancestors' overflow areas has changed,
-   * either through a change in its transform or a change in its position.
+   * The frame's overflow area has changed, either through a change in its
+   * transform or a change in its position. Does not update any descendant
+   * frames.
+   */
+  nsChangeHint_UpdateOverflow = 0x800,
+
+  /**
+   * The frame's overflow area has changed, through a change in its transform.
    * Does not update any descendant frames.
    */
-  nsChangeHint_UpdateOverflow = 0x800,
+  nsChangeHint_UpdatePostTransformOverflow = 0x1000,
 
   /**
    * The children-only transform of an SVG frame changed, requiring the
    * overflow rects of the frame's immediate children to be updated.
    */
-  nsChangeHint_ChildrenOnlyTransform = 0x1000,
+  nsChangeHint_ChildrenOnlyTransform = 0x2000,
 
   /**
    * The frame's offsets have changed, while its dimensions might have
    * changed as well.  This hint is used for positioned frames if their
    * offset changes.  If we decide that the dimensions are likely to
    * change, this will trigger a reflow.
    *
    * Note that this should probably be used in combination with
    * nsChangeHint_UpdateOverflow in order to get the overflow areas of
    * the ancestors updated as well.
    */
-  nsChangeHint_RecomputePosition = 0x2000,
+  nsChangeHint_RecomputePosition = 0x4000,
 
   /**
    * Behaves like ReconstructFrame, but only if the frame has descendants
    * that are absolutely or fixed position. Use this hint when a style change
    * has changed whether the frame is a container for fixed-pos or abs-pos
    * elements, but reframing is otherwise not needed.
    */
-  nsChangeHint_AddOrRemoveTransform = 0x4000,
+  nsChangeHint_AddOrRemoveTransform = 0x8000,
 
   /**
    * This change hint has *no* change handling behavior.  However, it
    * exists to be a non-inherited hint, because when the border-style
    * changes, and it's inherited by a child, that might require a reflow
    * due to the border-width change on the child.
    */
-  nsChangeHint_BorderStyleNoneChange = 0x8000,
+  nsChangeHint_BorderStyleNoneChange = 0x10000,
 
   /**
    * SVG textPath needs to be recomputed because the path has changed.
    * This means that the glyph positions of the text need to be recomputed.
    */
-  nsChangeHint_UpdateTextPath = 0x10000
+  nsChangeHint_UpdateTextPath = 0x20000
 
   // IMPORTANT NOTE: When adding new hints, consider whether you need to
   // add them to NS_HintsNotHandledForDescendantsIn() below.
 };
 
 // Redefine these operators to return nothing. This will catch any use
 // of these operators on hints. We should not be using these operators
 // on nsChangeHints
@@ -167,29 +173,31 @@ inline bool NS_IsHintSubset(nsChangeHint
  */
 
 // The most hints that NS_HintsNotHandledForDescendantsIn could possibly return:
 #define nsChangeHint_Hints_NotHandledForDescendants nsChangeHint( \
           nsChangeHint_UpdateTransformLayer | \
           nsChangeHint_UpdateEffects | \
           nsChangeHint_UpdateOpacityLayer | \
           nsChangeHint_UpdateOverflow | \
+          nsChangeHint_UpdatePostTransformOverflow | \
           nsChangeHint_ChildrenOnlyTransform | \
           nsChangeHint_RecomputePosition | \
           nsChangeHint_AddOrRemoveTransform | \
           nsChangeHint_BorderStyleNoneChange | \
           nsChangeHint_NeedReflow | \
           nsChangeHint_ClearAncestorIntrinsics)
 
 inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) {
   nsChangeHint result = nsChangeHint(aChangeHint & (
     nsChangeHint_UpdateTransformLayer |
     nsChangeHint_UpdateEffects |
     nsChangeHint_UpdateOpacityLayer |
     nsChangeHint_UpdateOverflow |
+    nsChangeHint_UpdatePostTransformOverflow |
     nsChangeHint_ChildrenOnlyTransform |
     nsChangeHint_RecomputePosition |
     nsChangeHint_AddOrRemoveTransform |
     nsChangeHint_BorderStyleNoneChange));
 
   if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aChangeHint) &&
       NS_IsHintSubset(nsChangeHint_NeedReflow, aChangeHint)) {
     // If NeedDirtyReflow is *not* set, then NeedReflow is a
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4461,21 +4461,21 @@ nsLayoutUtils::GetFirstLinePosition(cons
       LinePosition kidPosition;
       if (GetFirstLinePosition(kid, &kidPosition)) {
         *aResult = kidPosition + kid->GetNormalPosition().y;
         return true;
       }
     } else {
       // XXX Is this the right test?  We have some bogus empty lines
       // floating around, but IsEmpty is perhaps too weak.
-      if (line->GetHeight() != 0 || !line->IsEmpty()) {
-        nscoord top = line->mBounds.y;
+      if (line->BSize() != 0 || !line->IsEmpty()) {
+        nscoord top = line->BStart();
         aResult->mTop = top;
         aResult->mBaseline = top + line->GetAscent();
-        aResult->mBottom = top + line->GetHeight();
+        aResult->mBottom = top + line->BSize();
         return true;
       }
     }
   }
   return false;
 }
 
 /* static */ bool
@@ -4500,18 +4500,18 @@ nsLayoutUtils::GetLastLineBaseline(const
         // Use the bottom of the scroll frame.
         // XXX CSS2.1 really doesn't say what to do here.
         *aResult = kid->GetNormalPosition().y + kid->GetRect().height;
         return true;
       }
     } else {
       // XXX Is this the right test?  We have some bogus empty lines
       // floating around, but IsEmpty is perhaps too weak.
-      if (line->GetHeight() != 0 || !line->IsEmpty()) {
-        *aResult = line->mBounds.y + line->GetAscent();
+      if (line->BSize() != 0 || !line->IsEmpty()) {
+        *aResult = line->BStart() + line->GetAscent();
         return true;
       }
     }
   }
   return false;
 }
 
 static nscoord
@@ -4526,17 +4526,17 @@ CalculateBlockContentBottom(nsBlockFrame
        line != line_end; ++line) {
     if (line->IsBlock()) {
       nsIFrame* child = line->mFirstChild;
       nscoord offset = child->GetNormalPosition().y;
       contentBottom = std::max(contentBottom,
                         nsLayoutUtils::CalculateContentBottom(child) + offset);
     }
     else {
-      contentBottom = std::max(contentBottom, line->mBounds.YMost());
+      contentBottom = std::max(contentBottom, line->BEnd());
     }
   }
   return contentBottom;
 }
 
 /* static */ nscoord
 nsLayoutUtils::CalculateContentBottom(nsIFrame* aFrame)
 {
--- a/layout/generic/StickyScrollContainer.cpp
+++ b/layout/generic/StickyScrollContainer.cpp
@@ -366,19 +366,22 @@ StickyScrollContainer::UpdatePositions(n
     if (aSubtreeRoot) {
       // Reflowing the scroll frame, so recompute offsets.
       ComputeStickyOffsets(f);
     }
     // mFrames will only contain first continuations, because we filter in
     // nsIFrame::Init.
     PositionContinuations(f);
 
-    for (nsIFrame* cont = f; cont;
-         cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
-      oct.AddFrame(cont);
+    f = f->GetParent();
+    if (f != aSubtreeRoot) {
+      for (nsIFrame* cont = f; cont;
+           cont = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(cont)) {
+        oct.AddFrame(cont, OverflowChangedTracker::CHILDREN_CHANGED);
+      }
     }
   }
   oct.Flush();
 }
 
 void
 StickyScrollContainer::ScrollPositionWillChange(nscoord aX, nscoord aY)
 {
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -710,33 +710,33 @@ TextOverflow::CreateMarkers(const nsLine
                             bool             aCreateLeft,
                             bool             aCreateRight,
                             const nsRect&    aInsideMarkersArea)
 {
   if (aCreateLeft) {
     DisplayListClipState::AutoSaveRestore clipState(mBuilder);
 
     nsRect markerRect = nsRect(aInsideMarkersArea.x - mLeft.mIntrinsicWidth,
-                               aLine->mBounds.y,
-                               mLeft.mIntrinsicWidth, aLine->mBounds.height);
+                               aLine->BStart(),
+                               mLeft.mIntrinsicWidth, aLine->BSize());
     markerRect += mBuilder->ToReferenceFrame(mBlock);
     ClipMarker(mContentArea + mBuilder->ToReferenceFrame(mBlock),
                markerRect, clipState);
     nsDisplayItem* marker = new (mBuilder)
       nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
                                   aLine->GetAscent(), mLeft.mStyle, 0);
     mMarkerList.AppendNewToTop(marker);
   }
 
   if (aCreateRight) {
     DisplayListClipState::AutoSaveRestore clipState(mBuilder);
 
     nsRect markerRect = nsRect(aInsideMarkersArea.XMost(),
-                               aLine->mBounds.y,
-                               mRight.mIntrinsicWidth, aLine->mBounds.height);
+                               aLine->BStart(),
+                               mRight.mIntrinsicWidth, aLine->BSize());
     markerRect += mBuilder->ToReferenceFrame(mBlock);
     ClipMarker(mContentArea + mBuilder->ToReferenceFrame(mBlock),
                markerRect, clipState);
     nsDisplayItem* marker = new (mBuilder)
       nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
                                   aLine->GetAscent(), mRight.mStyle, 1);
     mMarkerList.AppendNewToTop(marker);
   }
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -834,16 +834,34 @@ public:
   }
 
   bool IsEmpty() const
   {
     return (mMargin.left == 0 && mMargin.top == 0 &&
             mMargin.right == 0 && mMargin.bottom == 0);
   }
 
+  LogicalMargin operator+(const LogicalMargin& aMargin) {
+    CHECK_WRITING_MODE(aMargin.GetWritingMode());
+    return LogicalMargin(GetWritingMode(),
+                         BStart() + aMargin.BStart(),
+                         IEnd() + aMargin.IEnd(),
+                         BEnd() + aMargin.BEnd(),
+                         IStart() + aMargin.IStart());
+  }
+
+  LogicalMargin operator-(const LogicalMargin& aMargin) {
+    CHECK_WRITING_MODE(aMargin.GetWritingMode());
+    return LogicalMargin(GetWritingMode(),
+                         BStart() - aMargin.BStart(),
+                         IEnd() - aMargin.IEnd(),
+                         BEnd() - aMargin.BEnd(),
+                         IStart() - aMargin.IStart());
+  }
+
 private:
   friend class LogicalRect;
 
   LogicalMargin() MOZ_DELETE;
 
 #ifdef DEBUG
   WritingMode GetWritingMode() const { return mWritingMode; }
 #else
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1125,17 +1125,17 @@ nsBlockFrame::Reflow(nsPresContext*     
   //
   // There are exactly two places a bullet can be placed: near the
   // first or second line. It's only placed on the second line in a
   // rare case: an empty first line followed by a second line that
   // contains a block (example: <LI>\n<P>... ). This is where
   // the second case can happen.
   if (HasOutsideBullet() && !mLines.empty() &&
       (mLines.front()->IsBlock() ||
-       (0 == mLines.front()->mBounds.height &&
+       (0 == mLines.front()->BSize() &&
         mLines.front() != mLines.back() &&
         mLines.begin().next()->IsBlock()))) {
     // Reflow the bullet
     nsHTMLReflowMetrics metrics(aReflowState);
     // XXX Use the entire line when we fix bug 25888.
     nsLayoutUtils::LinePosition position;
     bool havePosition = nsLayoutUtils::GetFirstLinePosition(this, &position);
     nscoord lineTop = havePosition ? position.mTop
@@ -1308,17 +1308,17 @@ nsBlockFrame::CheckForCollapsedBottomMar
   line_iterator begin = begin_lines();
   line_iterator line = end_lines();
 
   while (true) {
     if (begin == line) {
       return false;
     }
     --line;
-    if (line->mBounds.height != 0 || !line->CachedIsEmpty()) {
+    if (line->BSize() != 0 || !line->CachedIsEmpty()) {
       return false;
     }
     if (line->HasClearance()) {
       return true;
     }
   }
   // not reached
 }
@@ -1531,17 +1531,17 @@ nsBlockFrame::UpdateOverflow()
 
   // We need to update the overflow areas of lines manually, as they
   // get cached and re-used otherwise. Lines aren't exposed as normal
   // frame children, so calling UnionChildOverflow alone will end up
   // using the old cached values.
   for (line_iterator line = begin_lines(), line_end = end_lines();
        line != line_end;
        ++line) {
-    nsRect bounds = line->mBounds;
+    nsRect bounds = line->GetPhysicalBounds();
     nsOverflowAreas lineAreas(bounds, bounds);
 
     int32_t n = line->GetChildCount();
     for (nsIFrame* lineFrame = line->mFirstChild;
          n > 0; lineFrame = lineFrame->GetNextSibling(), --n) {
       ConsiderChildOverflow(lineAreas, lineFrame);
     }
 
@@ -1644,42 +1644,32 @@ IsAlignedLeft(uint8_t aAlignment,
           (NS_STYLE_TEXT_ALIGN_END == aAlignment &&
            NS_STYLE_DIRECTION_RTL == aDirection)) &&
          !(NS_STYLE_UNICODE_BIDI_PLAINTEXT & aUnicodeBidi));
 }
 
 void
 nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
 {
-  const nsStyleText* styleText = StyleText();
-  const nsStyleTextReset* styleTextReset = StyleTextReset();
   // See if we can try and avoid marking all the lines as dirty
   bool tryAndSkipLines =
-    // The block must be LTR (bug 806284)
-    StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR &&
-    // The text must be left-aligned.
-    IsAlignedLeft(styleText->mTextAlign, 
-                  aState.mReflowState.mStyleVisibility->mDirection,
-                  styleTextReset->mUnicodeBidi,
-                  this) &&
     // The left content-edge must be a constant distance from the left
     // border-edge.
     !StylePadding()->mPadding.GetLeft().HasPercent();
 
 #ifdef DEBUG
   if (gDisableResizeOpt) {
     tryAndSkipLines = false;
   }
   if (gNoisyReflow) {
     if (!tryAndSkipLines) {
       IndentBy(stdout, gNoiseIndent);
       ListTag(stdout);
-      printf(": marking all lines dirty: availWidth=%d textAlign=%d\n",
-             aState.mReflowState.AvailableWidth(),
-             styleText->mTextAlign);
+      printf(": marking all lines dirty: availWidth=%d\n",
+             aState.mReflowState.AvailableWidth());
     }
   }
 #endif
 
   if (tryAndSkipLines) {
     nscoord newAvailWidth = aState.mReflowState.ComputedPhysicalBorderPadding().left +
                             aState.mReflowState.ComputedWidth();
     NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aState.mReflowState.ComputedPhysicalBorderPadding().left &&
@@ -1689,59 +1679,51 @@ nsBlockFrame::PrepareResizeReflow(nsBloc
 #ifdef DEBUG
     if (gNoisyReflow) {
       IndentBy(stdout, gNoiseIndent);
       ListTag(stdout);
       printf(": trying to avoid marking all lines dirty\n");
     }
 #endif
 
-    // The last line might not be aligned left even if the rest of the block is
-    bool skipLastLine = NS_STYLE_TEXT_ALIGN_AUTO == styleText->mTextAlignLast ||
-      IsAlignedLeft(styleText->mTextAlignLast,
-                    aState.mReflowState.mStyleVisibility->mDirection,
-                    styleTextReset->mUnicodeBidi,
-                    this);
-
     for (line_iterator line = begin_lines(), line_end = end_lines();
          line != line_end;
          ++line)
     {
       // We let child blocks make their own decisions the same
       // way we are here.
       bool isLastLine = line == mLines.back() && !GetNextInFlow();
       if (line->IsBlock() ||
           line->HasFloats() ||
           (!isLastLine && !line->HasBreakAfter()) ||
-          ((isLastLine || !line->IsLineWrapped()) && !skipLastLine) ||
+          ((isLastLine || !line->IsLineWrapped())) ||
           line->ResizeReflowOptimizationDisabled() ||
           line->IsImpactedByFloat() ||
-          (line->mBounds.XMost() > newAvailWidth)) {
+          (line->IEnd() > newAvailWidth)) {
         line->MarkDirty();
       }
 
 #ifdef REALLY_NOISY_REFLOW
       if (!line->IsBlock()) {
         printf("PrepareResizeReflow thinks line %p is %simpacted by floats\n", 
                line.get(), line->IsImpactedByFloat() ? "" : "not ");
       }
 #endif
 #ifdef DEBUG
       if (gNoisyReflow && !line->IsDirty()) {
         IndentBy(stdout, gNoiseIndent + 1);
-        printf("skipped: line=%p next=%p %s %s%s%s%s breakTypeBefore/After=%d/%d xmost=%d\n",
+        printf("skipped: line=%p next=%p %s %s%s%s breakTypeBefore/After=%d/%d xmost=%d\n",
            static_cast<void*>(line.get()),
            static_cast<void*>((line.next() != end_lines() ? line.next().get() : nullptr)),
            line->IsBlock() ? "block" : "inline",
            line->HasBreakAfter() ? "has-break-after " : "",
            line->HasFloats() ? "has-floats " : "",
            line->IsImpactedByFloat() ? "impacted " : "",
-           skipLastLine ? "last-line-left-aligned " : "",
            line->GetBreakTypeBefore(), line->GetBreakTypeAfter(),
-           line->mBounds.XMost());
+           line->IEnd());
       }
 #endif
     }
   }
   else {
     // Mark everything dirty
     for (line_iterator line = begin_lines(), line_end = end_lines();
          line != line_end;
@@ -1779,18 +1761,18 @@ nsBlockFrame::PropagateFloatDamage(nsBlo
   // be any float damage
   if (!floatManager->HasAnyFloats())
     return;
 
   // Check the damage region recorded in the float damage.
   if (floatManager->HasFloatDamage()) {
     // Need to check mBounds *and* mCombinedArea to find intersections 
     // with aLine's floats
-    nscoord lineYA = aLine->mBounds.y + aDeltaY;
-    nscoord lineYB = lineYA + aLine->mBounds.height;
+    nscoord lineYA = aLine->BStart() + aDeltaY;
+    nscoord lineYB = lineYA + aLine->BSize();
     // Scrollable overflow should be sufficient for things that affect
     // layout.
     nsRect overflow = aLine->GetOverflowArea(eScrollableOverflow);
     nscoord lineYCombinedA = overflow.y + aDeltaY;
     nscoord lineYCombinedB = lineYCombinedA + overflow.height;
     if (floatManager->IntersectsDamage(lineYA, lineYB) ||
         floatManager->IntersectsDamage(lineYCombinedA, lineYCombinedB)) {
       aLine->MarkDirty();
@@ -1804,18 +1786,18 @@ nsBlockFrame::PropagateFloatDamage(nsBlo
       // Unconditionally reflow sliding blocks; we only really need to reflow
       // if there's a float impacting this block, but the current float manager
       // makes it difficult to check that.  Therefore, we let the child block
       // decide what it needs to reflow.
       aLine->MarkDirty();
     } else {
       bool wasImpactedByFloat = aLine->IsImpactedByFloat();
       nsFlowAreaRect floatAvailableSpace =
-        aState.GetFloatAvailableSpaceForHeight(aLine->mBounds.y + aDeltaY,
-                                               aLine->mBounds.height,
+        aState.GetFloatAvailableSpaceForHeight(aLine->BStart() + aDeltaY,
+                                               aLine->BSize(),
                                                nullptr);
 
 #ifdef REALLY_NOISY_REFLOW
     printf("nsBlockFrame::PropagateFloatDamage %p was = %d, is=%d\n", 
            this, wasImpactedByFloat, floatAvailableSpace.mHasFloats);
 #endif
 
       // Mark the line dirty if it was or is affected by a float
@@ -1860,18 +1842,18 @@ static void DumpLine(const nsBlockReflow
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsRect ovis(aLine->GetVisualOverflowArea());
     nsRect oscr(aLine->GetScrollableOverflowArea());
     nsBlockFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent + aDeltaIndent);
     printf("line=%p mY=%d dirty=%s oldBounds={%d,%d,%d,%d} oldoverflow-vis={%d,%d,%d,%d} oldoverflow-scr={%d,%d,%d,%d} deltaY=%d mPrevBottomMargin=%d childCount=%d\n",
            static_cast<void*>(aLine), aState.mY,
            aLine->IsDirty() ? "yes" : "no",
-           aLine->mBounds.x, aLine->mBounds.y,
-           aLine->mBounds.width, aLine->mBounds.height,
+           aLine->IStart(), aLine->BStart(),
+           aLine->ISize(), aLine->BSize(),
            ovis.x, ovis.y, ovis.width, ovis.height,
            oscr.x, oscr.y, oscr.width, oscr.height,
            aDeltaY, aState.mPrevBottomMargin.get(), aLine->GetChildCount());
   }
 #endif
 }
 
 /**
@@ -1968,44 +1950,44 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
       
       if (line->HasClearance()) {
         // Reflow the line if it might not have clearance anymore.
         if (newY == curY
             // aState.mY is the clearance point which should be the
             // top border-edge of the block frame. If sliding the
             // block by deltaY isn't going to put it in the predicted
             // position, then we'd better reflow the line.
-            || newY != line->mBounds.y + deltaY) {
+            || newY != line->BStart() + deltaY) {
           line->MarkDirty();
         }
       } else {
         // Reflow the line if the line might have clearance now.
         if (curY != newY) {
           line->MarkDirty();
         }
       }
     }
 
     // We might have to reflow a line that is after a clearing BR.
     if (inlineFloatBreakType != NS_STYLE_CLEAR_NONE) {
       aState.mY = aState.ClearFloats(aState.mY, inlineFloatBreakType);
-      if (aState.mY != line->mBounds.y + deltaY) {
+      if (aState.mY != line->BStart() + deltaY) {
         // SlideLine is not going to put the line where the clearance
         // put it. Reflow the line to be sure.
         line->MarkDirty();
       }
       inlineFloatBreakType = NS_STYLE_CLEAR_NONE;
     }
 
     bool previousMarginWasDirty = line->IsPreviousMarginDirty();
     if (previousMarginWasDirty) {
       // If the previous margin is dirty, reflow the current line
       line->MarkDirty();
       line->ClearPreviousMarginDirty();
-    } else if (line->mBounds.YMost() + deltaY > aState.mBottomEdge) {
+    } else if (line->BEnd() + deltaY > aState.mBottomEdge) {
       // Lines that aren't dirty but get slid past our height constraint must
       // be reflowed.
       line->MarkDirty();
     }
 
     // If we have a constrained height (i.e., breaking columns/pages),
     // and the distance to the bottom might have changed, then we need
     // to reflow any line that might have floats in it, both because the
@@ -2022,16 +2004,37 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
     }
 
     if (!line->IsDirty()) {
       // See if there's any reflow damage that requires that we mark the
       // line dirty.
       PropagateFloatDamage(aState, line, deltaY);
     }
 
+    // If the container width has changed reset the container width. If the
+    // line's writing mode is not ltr, or if the line is not left-aligned, also
+    // mark the line dirty.
+    if (aState.mContainerWidth != line->mContainerWidth) {
+      line->mContainerWidth = aState.mContainerWidth;
+
+      bool isLastLine = line == mLines.back() &&
+                        !GetNextInFlow() &&
+                        NS_STYLE_TEXT_ALIGN_AUTO == StyleText()->mTextAlignLast;
+      uint8_t align = isLastLine ?
+        StyleText()->mTextAlign : StyleText()->mTextAlignLast;
+
+      if (line->mWritingMode.IsVertical() ||
+          !line->mWritingMode.IsBidiLTR() ||
+          !IsAlignedLeft(align,
+                         aState.mReflowState.mStyleVisibility->mDirection,
+                         StyleTextReset()->mUnicodeBidi, this)) {
+        line->MarkDirty();
+      }
+    }
+
     if (needToRecoverState && line->IsDirty()) {
       // We need to reconstruct the bottom margin only if we didn't
       // reflow the previous line and we do need to reflow (or repair
       // the top position of) the next line.
       aState.ReconstructMarginAbove(line);
     }
 
     bool reflowedPrevLine = !needToRecoverState;
@@ -2055,24 +2058,24 @@ nsBlockFrame::ReflowDirtyLines(nsBlockRe
     // dangling frame pointers! Ugh! This reflow of the line may be
     // incorrect because we skipped reflowing previous lines (e.g., floats
     // may be placed incorrectly), but that's OK because we'll mark the
     // line dirty below under "if (aState.mReflowState.mDiscoveredClearance..."
     if (line->IsDirty() && (line->HasFloats() || !willReflowAgain)) {
       lastLineMovedUp = true;
 
       bool maybeReflowingForFirstTime =
-        line->mBounds.x == 0 && line->mBounds.y == 0 &&
-        line->mBounds.width == 0 && line->mBounds.height == 0;
-
-      // Compute the dirty lines "before" YMost, after factoring in