Merge m-c to b2g-inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 16 Apr 2014 22:54:15 -0400
changeset 179417 f1f58acc81549b859c6846aacfca32c6527253a2
parent 179416 bd03b3245bed5a2cea84486447d85f5cfae40ee0 (current diff)
parent 179345 e71ed4135461b57a9c7f35995e4e1f1dc5f0e8bf (diff)
child 179418 93c6643c9eb3028d0d6144fe39c311d8683bc41f
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
Merge m-c to b2g-inbound.
browser/base/content/aboutaccounts/fonts/clearsans-regular.woff
browser/base/content/aboutaccounts/fonts/firasans-light.woff
browser/base/content/aboutaccounts/fonts/firasans-regular.woff
browser/components/customizableui/test/browser_996364_defaultCollapsed.js
browser/themes/linux/devtools/ruleview.css
browser/themes/osx/devtools/ruleview.css
browser/themes/shared/ClearSans-Regular.ttf
browser/themes/windows/devtools/ruleview.css
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/chrome/content/devtools.js
+++ b/b2g/chrome/content/devtools.js
@@ -2,34 +2,34 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 'use strict';
 
 const DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD';
 
 XPCOMUtils.defineLazyGetter(this, 'devtools', function() {
-  const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+  const {devtools} = Cu.import('resource://gre/modules/devtools/Loader.jsm', {});
   return devtools;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() {
   return Cu.import('resource://gre/modules/devtools/dbg-client.jsm', {}).DebuggerClient;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() {
-  return devtools.require("devtools/toolkit/webconsole/utils").Utils;
+  return devtools.require('devtools/toolkit/webconsole/utils').Utils;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() {
-  return devtools.require("devtools/server/actors/eventlooplag").EventLoopLagFront;
+  return devtools.require('devtools/server/actors/eventlooplag').EventLoopLagFront;
 });
 
 XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() {
-  return devtools.require("devtools/server/actors/memory").MemoryFront;
+  return devtools.require('devtools/server/actors/memory').MemoryFront;
 });
 
 
 /**
  * The Developer HUD is an on-device developer tool that displays widgets,
  * showing visual debug information about apps. Each widget corresponds to a
  * metric as tracked by a metric watcher (e.g. consoleWatcher).
  */
@@ -42,17 +42,17 @@ let developerHUD = {
   _watchers: [],
   _logging: true,
 
   /**
    * This method registers a metric watcher that will watch one or more metrics
    * on app frames that are being tracked. A watcher must implement the
    * `trackTarget(target)` and `untrackTarget(target)` methods, register
    * observed metrics with `target.register(metric)`, and keep them up-to-date
-   * with `target.update(metric, value, message)` when necessary.
+   * with `target.update(metric, message)` when necessary.
    */
   registerWatcher: function dwp_registerWatcher(watcher) {
     this._watchers.unshift(watcher);
   },
 
   init: function dwp_init() {
     if (this._client)
       return;
@@ -205,25 +205,34 @@ Target.prototype = {
   register: function target_register(metric) {
     this.metrics.set(metric, 0);
   },
 
   /**
    * Modify one of a target's metrics, and send out an event to notify relevant
    * parties (e.g. the developer HUD, automated tests, etc).
    */
-  update: function target_update(metric, value = 0, message) {
+  update: function target_update(metric, message) {
+    if (!metric.name) {
+      throw new Error('Missing metric.name');
+    }
+
+    if (!metric.value) {
+      metric.value = 0;
+    }
+
     let metrics = this.metrics;
-    metrics.set(metric, value);
+    if (metrics) {
+      metrics.set(metric.name, metric.value);
+    }
 
     let data = {
       metrics: [], // FIXME(Bug 982066) Remove this field.
       manifest: this.frame.appManifestURL,
       metric: metric,
-      value: value,
       message: message
     };
 
     // FIXME(Bug 982066) Remove this loop.
     if (metrics && metrics.size > 0) {
       for (let name of metrics.keys()) {
         data.metrics.push({name: name, value: metrics.get(name)});
       }
@@ -235,25 +244,27 @@ Target.prototype = {
     this._send(data);
   },
 
   /**
    * Nicer way to call update() when the metric value is a number that needs
    * to be incremented.
    */
   bump: function target_bump(metric, message) {
-    this.update(metric, this.metrics.get(metric) + 1, message);
+    metric.value = (this.metrics.get(metric.name) || 0) + 1;
+    this.update(metric, message);
   },
 
   /**
    * Void a metric value and make sure it isn't displayed on the front-end
    * anymore.
    */
   clear: function target_clear(metric) {
-    this.update(metric, 0);
+    metric.value = 0;
+    this.update(metric);
   },
 
   /**
    * Tear everything down, including the front-end by sending a message without
    * widgets.
    */
   destroy: function target_destroy() {
     delete this.metrics;
@@ -302,17 +313,17 @@ let consoleWatcher = {
       SettingsListener.observe('hud.' + metric, watching[metric], watch => {
         // Watch or unwatch the metric.
         if (watching[metric] = watch) {
           return;
         }
 
         // If unwatched, remove any existing widgets for that metric.
         for (let target of this._targets.values()) {
-          target.clear(metric);
+          target.clear({name: metric});
         }
       });
     }
 
     client.addListener('logMessage', this.consoleListener);
     client.addListener('pageError', this.consoleListener);
     client.addListener('consoleAPICall', this.consoleListener);
     client.addListener('reflowActivity', this.consoleListener);
@@ -340,72 +351,76 @@ let consoleWatcher = {
       listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity']
     }, (res) => { });
 
     this._targets.delete(target.actor.consoleActor);
   },
 
   consoleListener: function cw_consoleListener(type, packet) {
     let target = this._targets.get(packet.from);
-    let metric;
+    let metric = {};
     let output = '';
 
     switch (packet.type) {
 
       case 'pageError':
         let pageError = packet.pageError;
 
         if (pageError.warning || pageError.strict) {
-          metric = 'warnings';
+          metric.name = 'warnings';
           output += 'warning (';
         } else {
-          metric = 'errors';
+          metric.name = 'errors';
           output += 'error (';
         }
 
         if (this._security.indexOf(pageError.category) > -1) {
-          metric = 'security';
+          metric.name = 'security';
         }
 
         let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError;
         output += category + '): "' + (errorMessage.initial || errorMessage) +
           '" in ' + sourceName + ':' + lineNumber + ':' + columnNumber;
         break;
 
       case 'consoleAPICall':
         switch (packet.message.level) {
 
           case 'error':
-            metric = 'errors';
+            metric.name = 'errors';
             output += 'error (console)';
             break;
 
           case 'warn':
-            metric = 'warnings';
+            metric.name = 'warnings';
             output += 'warning (console)';
             break;
 
           default:
             return;
         }
         break;
 
       case 'reflowActivity':
-        metric = 'reflows';
+        metric.name = 'reflows';
 
-        let {start, end, sourceURL} = packet;
+        let {start, end, sourceURL, interruptible} = packet;
+        metric.interruptible = interruptible;
         let duration = Math.round((end - start) * 100) / 100;
         output += 'reflow: ' + duration + 'ms';
         if (sourceURL) {
           output += ' ' + this.formatSourceURL(packet);
         }
         break;
+
+      default:
+        return;
     }
 
-    if (!this._watching[metric]) {
+    if (!this._watching[metric.name]) {
       return;
     }
 
     target.bump(metric, output);
   },
 
   formatSourceURL: function cw_formatSourceURL(packet) {
     // Abbreviate source URL
@@ -441,29 +456,29 @@ let eventLoopLagWatcher = {
 
     // Toggle the state of existing fronts.
     let fronts = this._fronts;
     for (let target of fronts.keys()) {
       if (value) {
         fronts.get(target).start();
       } else {
         fronts.get(target).stop();
-        target.clear('jank');
+        target.clear({name: 'jank'});
       }
     }
   },
 
   trackTarget: function(target) {
     target.register('jank');
 
     let front = new EventLoopLagFront(this._client, target.actor);
     this._fronts.set(target, front);
 
     front.on('event-loop-lag', time => {
-      target.update('jank', time, 'jank: ' + time + 'ms');
+      target.update({name: 'jank', value: time}, 'jank: ' + time + 'ms');
     });
 
     if (this._active) {
       front.start();
     }
   },
 
   untrackTarget: function(target) {
@@ -509,17 +524,17 @@ let memoryWatcher = {
     SettingsListener.observe('hud.appmemory', false, enabled => {
       if (this._active = enabled) {
         for (let target of this._fronts.keys()) {
           this.measure(target);
         }
       } else {
         for (let target of this._fronts.keys()) {
           clearTimeout(this._timers.get(target));
-          target.clear('memory');
+          target.clear({name: 'memory'});
         }
       }
     });
   },
 
   measure: function mw_measure(target) {
 
     // TODO Also track USS (bug #976024).
@@ -545,17 +560,17 @@ let memoryWatcher = {
       if (watch.style) {
         total += parseInt(data.styleSize);
       }
       if (watch.other) {
         total += parseInt(data.otherSize);
       }
       // TODO Also count images size (bug #976007).
 
-      target.update('memory', total);
+      target.update({name: 'memory', value: total});
       let duration = parseInt(data.jsMilliseconds) + parseInt(data.nonJSMilliseconds);
       let timer = setTimeout(() => this.measure(target), 100 * duration);
       this._timers.set(target, timer);
     }, (err) => {
       console.error(err);
     });
   },
 
--- a/browser/base/content/aboutaccounts/fonts.css
+++ b/browser/base/content/aboutaccounts/fonts.css
@@ -1,25 +1,24 @@
 @font-face {
   font-family: 'Fira Sans';
   font-style: normal;
   font-weight: 400;
   src: local('Fira Sans'),
        local('FiraSans'),
-       url('fonts/firasans-regular.woff') format('woff');
+       url('../fonts/FiraSans-Regular.woff') format('woff');
 }
 @font-face {
   font-family: 'Fira Sans';
   font-style: normal;
   font-weight: 300;
   src: local('Fira Sans Light'),
        local('FiraSansLight'),
-       url('fonts/firasans-light.woff') format('woff');
+       url('../fonts/FiraSans-Light.woff') format('woff');
 }
 @font-face {
   font-family: 'Clear Sans';
   font-style: normal;
   font-weight: 400;
   src: local('Clear Sans'),
        local('ClearSans'),
-       url('fonts/clearsans-regular.woff') format('woff');
+       url('../fonts/ClearSans-Regular.woff') format('woff');
 }
-
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -58,16 +58,20 @@ var StarUI = {
   // nsIDOMEventListener
   handleEvent: function SU_handleEvent(aEvent) {
     switch (aEvent.type) {
       case "popuphidden":
         if (aEvent.originalTarget == this.panel) {
           if (!this._element("editBookmarkPanelContent").hidden)
             this.quitEditMode();
 
+          if (this._anchorToolbarButton) {
+            this._anchorToolbarButton.removeAttribute("open");
+            this._anchorToolbarButton = null;
+          }
           this._restoreCommandsState();
           this._itemId = -1;
           if (this._batching) {
             PlacesUtils.transactionManager.endBatch(false);
             this._batching = false;
           }
 
           switch (this._actionOnHide) {
@@ -181,16 +185,31 @@ var StarUI = {
     this._element("editBookmarkPanelRemoveButton").label = label;
 
     // unset the unstarred state, if set
     this._element("editBookmarkPanelStarIcon").removeAttribute("unstarred");
 
     this._itemId = aItemId !== undefined ? aItemId : this._itemId;
     this.beginBatch();
 
+    if (aAnchorElement) {
+      // Set the open=true attribute if the anchor is a
+      // descendent of a toolbarbutton.
+      let parent = aAnchorElement.parentNode;
+      while (parent) {
+        if (parent.localName == "toolbarbutton") {
+          break;
+        }
+        parent = parent.parentNode;
+      }
+      if (parent) {
+        this._anchorToolbarButton = parent;
+        parent.setAttribute("open", "true");
+      }
+    }
     this.panel.openPopup(aAnchorElement, aPosition);
 
     gEditItemOverlay.initPanel(this._itemId,
                                { hiddenRows: ["description", "location",
                                               "loadInSidebar", "keyword"] });
   },
 
   panelShown:
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -232,20 +232,16 @@ let gSyncUI = {
     ));
 
     let notification = new Weave.Notification(
       title, description, null, Weave.Notifications.PRIORITY_WARNING, buttons);
     Weave.Notifications.replaceTitle(notification);
   },
 
   _getAppName: function () {
-    try {
-      let syncStrings = new StringBundle("chrome://browser/locale/sync.properties");
-      return syncStrings.getFormattedString("sync.defaultAccountApplication", [brandName]);
-    } catch (ex) {}
     let brand = new StringBundle("chrome://branding/locale/brand.properties");
     return brand.get("brandShortName");
   },
 
   onEOLNotice: function (data) {
     let code = data.code;
     let kind = (code == "hard-eol") ? "error" : "warning";
     let url = data.url || gSyncUI.DEFAULT_EOL_URL;
rename from browser/base/content/aboutaccounts/fonts/clearsans-regular.woff
rename to browser/base/content/fonts/ClearSans-Regular.woff
rename from browser/base/content/aboutaccounts/fonts/firasans-light.woff
rename to browser/base/content/fonts/FiraSans-Light.woff
rename from browser/base/content/aboutaccounts/fonts/firasans-regular.woff
rename to browser/base/content/fonts/FiraSans-Regular.woff
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -51,19 +51,16 @@ browser.jar:
         content/browser/abouthealthreport/abouthealth.css     (content/abouthealthreport/abouthealth.css)
 #endif
         content/browser/aboutaccounts/aboutaccounts.xhtml                     (content/aboutaccounts/aboutaccounts.xhtml)
         content/browser/aboutaccounts/aboutaccounts.js                        (content/aboutaccounts/aboutaccounts.js)
         content/browser/aboutaccounts/aboutaccounts.css                       (content/aboutaccounts/aboutaccounts.css)
         content/browser/aboutaccounts/main.css                                (content/aboutaccounts/main.css)
         content/browser/aboutaccounts/normalize.css                           (content/aboutaccounts/normalize.css)
         content/browser/aboutaccounts/fonts.css                               (content/aboutaccounts/fonts.css)
-        content/browser/aboutaccounts/fonts/clearsans-regular.woff            (content/aboutaccounts/fonts/clearsans-regular.woff)
-        content/browser/aboutaccounts/fonts/firasans-light.woff               (content/aboutaccounts/fonts/firasans-light.woff)
-        content/browser/aboutaccounts/fonts/firasans-regular.woff             (content/aboutaccounts/fonts/firasans-regular.woff)
         content/browser/aboutaccounts/images/fox.png                          (content/aboutaccounts/images/fox.png)
         content/browser/aboutaccounts/images/graphic_sync_intro.png           (content/aboutaccounts/images/graphic_sync_intro.png)
         content/browser/aboutaccounts/images/graphic_sync_intro@2x.png        (content/aboutaccounts/images/graphic_sync_intro@2x.png)
 
         content/browser/certerror/aboutCertError.xhtml     (content/aboutcerterror/aboutCertError.xhtml)
         content/browser/certerror/aboutCertError.css       (content/aboutcerterror/aboutCertError.css)
 
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
@@ -72,16 +69,19 @@ browser.jar:
         content/browser/aboutTabCrashed.js            (content/aboutTabCrashed.js)
         content/browser/aboutTabCrashed.xhtml         (content/aboutTabCrashed.xhtml)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
 *       content/browser/chatWindow.xul                (content/chatWindow.xul)
         content/browser/content.js                    (content/content.js)
+        content/browser/fonts/ClearSans-Regular.woff  (content/fonts/ClearSans-Regular.woff)
+        content/browser/fonts/FiraSans-Regular.woff   (content/fonts/FiraSans-Regular.woff)
+        content/browser/fonts/FiraSans-Light.woff     (content/fonts/FiraSans-Light.woff)
         content/browser/newtab/newTab.xul             (content/newtab/newTab.xul)
 *       content/browser/newtab/newTab.js              (content/newtab/newTab.js)
         content/browser/newtab/newTab.css             (content/newtab/newTab.css)
         content/browser/newtab/preloaderContent.js    (content/newtab/preloaderContent.js)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
         content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
         content/browser/pageinfo/pageInfo.css         (content/pageinfo/pageInfo.css)
         content/browser/pageinfo/pageInfo.xml         (content/pageinfo/pageInfo.xml)
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -292,21 +292,22 @@ let CustomizableUIInternal = {
 
   registerArea: function(aName, aProperties, aInternalCaller) {
     if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) {
       throw new Error("Invalid area name");
     }
 
     let areaIsKnown = gAreas.has(aName);
     let props = areaIsKnown ? gAreas.get(aName) : new Map();
-    if (areaIsKnown && aProperties["type"] &&
-        props.get("type") != aProperties["type"]) {
-      throw new Error("An area cannot change types");
-    }
+    const kImmutableProperties = new Set(["type", "legacy", "overflowable"]);
     for (let key in aProperties) {
+      if (areaIsKnown && kImmutableProperties.has(key) &&
+          props.get(key) != aProperties[key]) {
+        throw new Error("An area cannot change the property for '" + key + "'");
+      }
       //XXXgijs for special items, we need to make sure they have an appropriate ID
       // so we aren't perpetually in a non-default state:
       if (key == "defaultPlacements" && Array.isArray(aProperties[key])) {
         props.set(key, aProperties[key].map(x => this.isSpecialWidget(x) ? this.ensureSpecialWidgetId(x) : x ));
       } else {
         props.set(key, aProperties[key]);
       }
     }
@@ -3453,18 +3454,18 @@ function WidgetSingleWrapper(aWidget, aN
   this.node = aNode;
   this.provider = CustomizableUI.PROVIDER_API;
 
   const kGlobalProps = ["id", "type"];
   for (let prop of kGlobalProps) {
     this[prop] = aWidget[prop];
   }
 
-  const nodeProps = ["label", "tooltiptext"];
-  for (let prop of nodeProps) {
+  const kNodeProps = ["label", "tooltiptext"];
+  for (let prop of kNodeProps) {
     let propertyName = prop;
     // Look at the node for these, instead of the widget data, to ensure the
     // wrapper always reflects this live instance.
     this.__defineGetter__(propertyName,
                           function() aNode.getAttribute(propertyName));
   }
 
   this.__defineGetter__("disabled", function() aNode.disabled);
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -100,11 +100,11 @@ skip-if = os == "linux"
 [browser_985815_propagate_setToolbarVisibility.js]
 [browser_981305_separator_insertion.js]
 [browser_987177_destroyWidget_xul.js]
 [browser_987177_xul_wrapper_updating.js]
 [browser_987492_window_api.js]
 [browser_992747_toggle_noncustomizable_toolbar.js]
 [browser_993322_widget_notoolbar.js]
 [browser_995164_registerArea_during_customize_mode.js]
-[browser_996364_defaultCollapsed.js]
+[browser_996364_registerArea_different_properties.js]
 [browser_bootstrapped_custom_toolbar.js]
 [browser_panel_toggle.js]
--- a/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
+++ b/browser/components/customizableui/test/browser_995164_registerArea_during_customize_mode.js
@@ -53,43 +53,62 @@ add_task(function*() {
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
 
   let otherWin = yield openAndLoadWindow({}, true);
   let otherTB = otherWin.document.createElementNS(kNSXUL, "toolbar");
   otherTB.id = TOOLBARID;
   otherTB.setAttribute("customizable", "true");
+  let wasInformedCorrectlyOfAreaAppearing = false;
+  let listener = {
+    onAreaNodeRegistered: function(aArea, aNode) {
+      if (aNode == otherTB) {
+        wasInformedCorrectlyOfAreaAppearing = true;
+      }
+    }
+  };
+  CustomizableUI.addListener(listener);
   otherWin.gNavToolbox.appendChild(otherTB);
+  ok(wasInformedCorrectlyOfAreaAppearing, "Should have been told area was registered.");
+  CustomizableUI.removeListener(listener);
+
   ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
 
   simulateItemDrag(syncButton, gNavToolbox.palette);
   ok(!CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved to the palette");
   ok(gNavToolbox.palette.querySelector("#sync-button"), "Sync button really is in palette.");
   ok(!otherTB.querySelector("#sync-button"), "Sync button is in palette in other window, too.");
 
   simulateItemDrag(syncButton, toolbar);
   ok(CustomizableUI.getPlacementOfWidget("sync-button"), "Button moved out of palette");
   is(CustomizableUI.getPlacementOfWidget("sync-button").area, TOOLBARID, "Button's back on toolbar");
   ok(toolbar.querySelector("#sync-button"), "Sync button really is on toolbar.");
   ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
 
   let wasInformedCorrectlyOfAreaDisappearing = false;
-  let listener = {
+  let windowClosed = null;
+  listener = {
     onAreaNodeUnregistered: function(aArea, aNode, aReason) {
       if (aArea == TOOLBARID) {
         is(aNode, otherTB, "Should be informed about other toolbar");
         is(aReason, CustomizableUI.REASON_WINDOW_CLOSED, "Reason should be correct.");
         wasInformedCorrectlyOfAreaDisappearing = (aReason === CustomizableUI.REASON_WINDOW_CLOSED);
       }
-    }
+    },
+    onWindowClosed: function(aWindow) {
+      if (aWindow == otherWin) {
+        windowClosed = aWindow;
+      }
+    },
   };
   CustomizableUI.addListener(listener);
   yield promiseWindowClosed(otherWin);
 
+  is(windowClosed, otherWin, "Window should have sent onWindowClosed notification.");
   ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
   CustomizableUI.removeListener(listener);
   // Closing the other window should not be counted against this window's customize mode:
   is(syncButton.parentNode.localName, "toolbarpaletteitem", "Sync button's parent node should still be a wrapper.");
   isnot(gCustomizeMode.areas.indexOf(toolbar), -1, "Toolbar should still be a customizable area for this customize mode instance.");
 
   yield gCustomizeMode.reset();
 
rename from browser/components/customizableui/test/browser_996364_defaultCollapsed.js
rename to browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
--- a/browser/components/customizableui/test/browser_996364_defaultCollapsed.js
+++ b/browser/components/customizableui/test/browser_996364_registerArea_different_properties.js
@@ -15,42 +15,98 @@ add_task(function() {
   }
 
   CustomizableUI.unregisterArea("area-996364", true);
 });
 
 add_task(function() {
   let exceptionThrown = false;
   try {
-    CustomizableUI.registerArea("area-996364-2", {"type": CustomizableUI.TYPE_TOOLBAR, "defaultCollapsed": "false"});
+    CustomizableUI.registerArea("area-996364-2", {type: CustomizableUI.TYPE_TOOLBAR, defaultCollapsed: "false"});
   } catch (ex) {
     exceptionThrown = true;
   }
   ok(exceptionThrown, "defaultCollapsed is not allowed as an external property");
 
   // No need to unregister the area because registration fails.
 });
 
 add_task(function() {
   let exceptionThrown;
   try {
-    CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_TOOLBAR});
-    CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_MENU_PANEL});
+    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_TOOLBAR});
+    CustomizableUI.registerArea("area-996364-3", {type: CustomizableUI.TYPE_MENU_PANEL});
   } catch (ex) {
     exceptionThrown = ex;
   }
   ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
 
   CustomizableUI.unregisterArea("area-996364-3", true);
 });
 
 add_task(function() {
   let exceptionThrown;
   try {
-    CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_MENU_PANEL});
-    CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_TOOLBAR});
+    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_MENU_PANEL});
+    CustomizableUI.registerArea("area-996364-4", {type: CustomizableUI.TYPE_TOOLBAR});
   } catch (ex) {
     exceptionThrown = ex;
   }
   ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
 
   CustomizableUI.unregisterArea("area-996364-4", true);
 });
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-1", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+    CustomizableUI.registerArea("area-996899-1", { anchor: "home-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(!exceptionThrown, "Changing anchors shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-1", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: [] });
+    CustomizableUI.registerArea("area-996899-2", { anchor: "PanelUI-menu-button",
+                                                   type: CustomizableUI.TYPE_MENU_PANEL,
+                                                   defaultPlacements: ["feed-button"] });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(!exceptionThrown, "Changing defaultPlacements shouldn't throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-2", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-3", { legacy: true });
+    CustomizableUI.registerArea("area-996899-3", { legacy: false });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Changing 'legacy' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-3", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996899-4", { overflowable: true });
+    CustomizableUI.registerArea("area-996899-4", { overflowable: false });
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Changing 'overflowable' should throw an exception: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+  CustomizableUI.unregisterArea("area-996899-4", true);
+});
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -673,18 +673,16 @@ let SessionStoreInternal = {
             this.restoreTabContent(tab);
           }
         }
         break;
       default:
         debug("received unknown message '" + aMessage.name + "'");
         break;
     }
-
-    this._clearRestoringWindows();
   },
 
   /**
    * Record telemetry measurements stored in an object.
    * @param telemetry
    *        {histogramID: value, ...} An object mapping histogramIDs to the
    *        value to be recorded for that ID,
    */
@@ -3395,16 +3393,25 @@ let SessionStoreInternal = {
            !!this._closedWindows[normalWindowIndex].isPopup)
       normalWindowIndex++;
     if (normalWindowIndex >= this._max_windows_undo)
       spliceTo = normalWindowIndex + 1;
 #endif
     this._closedWindows.splice(spliceTo, this._closedWindows.length);
   },
 
+  /**
+   * Clears the set of windows that are "resurrected" before writing to disk to
+   * make closing windows one after the other until shutdown work as expected.
+   *
+   * This function should only be called when we are sure that there has been
+   * a user action that indicates the browser is actively being used and all
+   * windows that have been closed before are not part of a series of closing
+   * windows.
+   */
   _clearRestoringWindows: function ssi_clearRestoringWindows() {
     for (let i = 0; i < this._closedWindows.length; i++) {
       delete this._closedWindows[i]._shouldRestore;
     }
   },
 
   /**
    * Reset state to prepare for a new session state to be restored.
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
@@ -110,35 +110,37 @@ function test_3() {
             waitForTabLoad(aWindow, "http://www.example.com/", function() {
 
               let curState = JSON.parse(ss.getBrowserState());
               is(curState.windows.length, 4, "Browser has opened 4 windows");
               is(curState.windows[2].isPrivate, true, "Window 2 is private");
               is(curState.selectedWindow, 4, "Last window opened is the one selected");
 
               waitForWindowClose(normalWindow, function() {
-                // Load another tab before checking the written state so that
+                // Pin and unpin a tab before checking the written state so that
                 // the list of restoring windows gets cleared. Otherwise the
                 // window we just closed would be marked as not closed.
-                waitForTabLoad(aWindow, "http://www.example.com/", function() {
-                  forceWriteState(function(state) {
-                    is(state.windows.length, 2,
-                       "sessionstore state: 2 windows in data being written to disk");
-                    is(state.selectedWindow, 2,
-                       "Selected window is updated to match one of the saved windows");
-                    state.windows.forEach(function(win) {
-                      is(!win.isPrivate, true, "Saved window is not private");
-                    });
-                    is(state._closedWindows.length, 1,
-                       "sessionstore state: 1 closed window in data being written to disk");
-                    state._closedWindows.forEach(function(win) {
-                      is(!win.isPrivate, true, "Closed window is not private");
-                    });
-                    runNextTest();
+                let tab = aWindow.gBrowser.tabs[0];
+                aWindow.gBrowser.pinTab(tab);
+                aWindow.gBrowser.unpinTab(tab);
+
+                forceWriteState(function(state) {
+                  is(state.windows.length, 2,
+                     "sessionstore state: 2 windows in data being written to disk");
+                  is(state.selectedWindow, 2,
+                     "Selected window is updated to match one of the saved windows");
+                  state.windows.forEach(function(win) {
+                    is(!win.isPrivate, true, "Saved window is not private");
                   });
+                  is(state._closedWindows.length, 1,
+                     "sessionstore state: 1 closed window in data being written to disk");
+                  state._closedWindows.forEach(function(win) {
+                    is(!win.isPrivate, true, "Closed window is not private");
+                  });
+                  runNextTest();
                 });
               });
             });
           });
         });
       });
     });
   });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/chrome.manifest
@@ -0,0 +1,1 @@
+content browser_dbg_addon4 .
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul.js"/>
+  <label value="test.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/test2.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul2.js"/>
+  <label value="test2.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon4/testxul2.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/chrome.manifest
@@ -0,0 +1,1 @@
+content browser_dbg_addon5 .
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul.js"/>
+  <label value="test.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/test2.xul
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <script type="text/javascript" src="testxul2.js"/>
+  <label value="test2.xul"/>
+</window>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/addon-source/browser_dbg_addon5/testxul2.js
@@ -0,0 +1,4 @@
+// Define something in here or the script may get collected
+window.addEventListener("unload", function() {
+  window.foo = "bar";
+});
index a654b7e011b029859b2be10071d13ecb4e9e78eb..31c5331b69dee6d15183647bb598f90195ff1c2a
GIT binary patch
literal 2918
zc$^FHW@Zs#U}E54@a?a132>Y;EtQdhA)J|kfrmkcAt^t<q`0Igu|O}YI5dQlfq7H8
zaWKPto8Zz4ZU#n{Z$PC$-3$y@Cpr2n8}hWi|E#^naw~^w_Yuw`iJ^QYTiY*n8G8vE
z^PW1Qe4A19NWHr3mDHn$xcZ)?J$?GKy6g?(pEJ=POmZyCq+2xv3|!ueFl#jC35cc6
zUDRIuD)!7W#)jTk1xahuOQhak2)-XI=6vU7qDXsSw)}*Xax>+{_;N1)SQS{&GDGy|
zvC1jJGmbicIN90L+OBTVEcul=^^DeX-{Rm+*F7X%WV0pJ@*dv!TEvmp>8IiUaHG=R
zeTJ^dLc-Z+tuiHBxvJOfkX`&%b4p86_=)n3LNlUY-hP=`>ail==+^)9cY7>zjy2G%
z^b*%=Z~2pT)31DU#rqkjoA%6oU+kB5F=eKH;Ju38-qmvjuY^W+yXo%UFuCk(iT;V}
ziFadn3uwr1H~r{cvYCBH)VbBpTQ`W+P3C^^;5t{FQeBbS|8E<+7X996^LKB9??s32
zKbv_&+E&jg6WMM5Ilj;6)xJX?ZNE+S_Ii9_9%BGXR4ImKelP%re-aY|12-_LGV_W{
z5_59&ic-?xF{L&GBc@6xoy}`D5NLUC)9RWxwS)64D~rn1MRHnSFNN)OQ?uv{{jX51
zxy3*JIHUTKwfXb@rj;Kr+V_gpeSV1avJ^qRXN5bonicAA+9*X&T*lGQ;M-Psz4Y_D
zx^-U|^)HzmEo_>sa_Os`QM{0cyr(fYbBWct8G(i$xxSvYP+#XLblltL=t*1dw-zm*
zculR(N^Qti2wExDwc)Cfbd2O=Hjd{L6(+r1$@tpJ_teT05wT%WrERZrV`aB3SvNIi
z-9e{kRT+Kf*L>$)=so-9)nmKaRRp)xY_6T~R`TXvD>nBpU%KXn-Yv?SbK3D<kR~ge
zNv78Y-O>ZDpF{*|7ks#2GUqMFkC~UlB~0aoraY48x%NL*D)8Ww-vUo%-gwPuS|a~-
zw{eBwvDOdkdu4v6H%VI@|0X>3AU|rL7vFpOq8k{B3xJpd80aOb#U;S3k&7?HO-~)<
zYH|>9d-&JpXur4ky<2L!T&1BJHy3qq%$6)s*lTo;sr#O-VAQ<B?uur2InMrl5qp>8
z4nuP9<*5<Oi5|&;Ht+eDPb`SusTaf`HL=ch$=<a`_O5xh?P*@ejq6v=-#9bv-Zf+0
z#jJ`dOTVPByj*#L|G3G{sn7qK-JcrqSSaPpLDPSeS1$Yg^VlnPRL?x#Y9$Es3@6kx
zMr8O#=(ecWHVvhuS!lj71p4OiUx}K#9Df*IuQ89B(`vA!P-Fi0cJmWEukP~}X>eN-
zFF5nTmLJoN?`*rn%h^8bm*nl6mu|BzOWmY!WXY77JqguX-G>Wj-(U6FPP<I>+76eQ
zd>2jsf_<|L**7&|%`Wdc!@V~F9mvRt6g3s4IbhH1o^Klr!f2lH?LR2gWWeL{zQ$F(
zTzaon!~Gz`OI{f>)uKMUUR(5W+Rd~3a&Dcr+FThpZ9)>edUcEUeUrE0b{%;>k2<gX
z@cGWiHvh6u`jLs3uNs~bQEIxFyO3{6*ipw6_9+7SD`#|dUTO@F%~~@h>G>DFGv}7s
zJaW1H#zph-iz#Z0miE2UoXndP{N(I9|F(UG%cd%}yZ+C&y>t4lmc+@!;i7AQe^YGO
z&$C<m>U$ac%<}pjueR>^{(3e)s-GWN+<U(b=nrN_<QOFE=}SOQ14{sqr@y{nu=9S}
zzeOl&S*O^)<=amkjZQQFoq9R$`pmQ4n_5JyEp95u{9cx6|H-i=S;&9MvGiT#20!Mc
z?NaEQlh+rxOhB+FkGpii7A-y{>jf=8rgyEJp&?swb?GrL%`(6LjW=&jai5bhd#*;R
z%-l;ZTdoA!rfzb~>DqJi>&Xk|$F>+f+3@21+V<+5v8>9KKUOR%{huSx^n-Wf?!emf
zA19an{=*u!`RLxn`+JZIzv}2_m+4!|e-#7$(h9^}P>%z>4XdRzSJ(!tt-$cP?rBH9
zCIbQ13$^|qFN><U@j2XidCvPvnU}hz@iHEP<UQ6pG5hx<9++#yop^EPnhib)jtku`
zuxYCwIhKD|#%{(5fvsU(ZYSUBcz)0Jc)4-njmhH53$OhQUDftP|HNvS<f-e9UuXP3
zA+)f$zV(^=_t);_3`p^X=4@_+vyEWx)&aU%YtXox3+QeJa60>@-!NSk$Od74pu3YZ
zit=+)^>P#QGSh%wz?a&R^Ycnl^GXzwit@{gQ;XtLlG5W7Q&RHtOceCE0=yZS<d|_a
zKO`7H0LW!n(g<RqHbz(>MHHHK=q94plE@~m22v<>CUFL$)&R%`DgYggs1JxU4YdeH
zHtj9cG$Ue-!z=@ljoZz_fK(!~LZXX+X{e<OvT5sC8Ia2w!p33dS!Cl@urZ+IU{**D
z#^*eY%!F)SJUatw)?$TZEvyFOO6AA~igPevrg>bxW@Tdl$0jGkWuVEm93UP5@Gl)6
index 2c18f6da191746c1a7c658087fbce264a410e5a6..16991f7a06aeaf2bb32a045d7c925f1d41372d9e
GIT binary patch
literal 2933
zc$~$Sc{o)2AIA@47)!QmD$M;w%D#@|+Vk8&*SHz{&?U<lV~eqjtt8pEvSfsiY(t_&
z_Fa~&C4<P;Ey<d23nBMt`8C6@ZqM(Z-#pLvnRA}!ocDRZ&iniMd=3T;Vc-Gi0T|$B
z7=R+N|Dl4X0{~M90I&fFz{b_plj!Mzb(3}?8vmOafMjPY8PR2^8hQD$0(1=Tz)Qiq
z0ige~roNCITj;{FM4?hC>~LowYeZ84V#<jl7j91yw&Np3>XbpmBeqT`=XXYh!V&G=
z9i7W7bAyo8l=5eegC287SqucMBgVuSG4!JXk{!xg9IyJSlYfT*{QZA6n?0I3GM1TF
zmnRukaj!{~J$pc1AVCeOA&D3yFB)gRfyqfMU0N0uk&O<2mhclVD~G-tqx=k0N3!vW
z)Jd}K?RaE_@&HnA<o?~+mz*Qq>6mNxaaw2naZ#;@ga@vA^&(l|?@qd_Xb&5SGPm4{
zTd+ASTi#nvq0Gc#GNVp!Y52tJg;!Y{E|H{9u`{pr7pK3rTO5;1f}T+sf0fpi)sD2v
zs#)aYH&qeJzgfKZl9@MFWd7>3W!&wis%mdRj5^`;^Q0*|4!6=Y({LxO)Q0fBhQ{0Q
z8q~&w-iLV{Tx$h)=Di<XYF6OuWhVZ7HdCc}QSX4sdIY}DKlFv)oJbO>HB$|Op^3^s
z5Pn_*eE-q(0Kf`H<wziUVx66(J#6j%laxgAuB5y!cM|T)a%!!tu}I8`L&HlfI75#e
z?$gR8JS{Mvu!ihCk9wDrx%r+?L@p<GPL=q&t2UdbGl6F+n76aktofcJpG>EyxaB}>
zn-|HVndyS^g9?{nM?aN*yIA|>HAEio!{X*13mXl1oKe=?p_rbv<@;&v@g_4e(hQ4`
z;v=<9de{0B28({pKPg|WP{U{siPu%U6TzRoWSL0B2g2fyXRXHk;a0Fr4r))M6eFuj
zyPO?L$2oONtE>Wp=ic_x`#AT!%|s^+t%UgiJn@C+h(t`bQ?VK{YUE8bud@=Ohaz!y
zpoFXIY-L_>SudaDe#0bdzR5te7-n>YwYUD)0}(^=zWJvc%Nc?y7c0ZeDi|H4Vh|=<
zp$9PS{eBsh)eXj2w#yVu{d5BwD;pA^v^0^ye7*td9bnGuzas<U*vqMC@TFb{7Yxk6
z6HoL6E5+q|0Vs4dvIHID(f)H&wIvq4Z|teC6pNR!=ulP!ES1+&pcXksA3dhVWp=Ge
zNATz<tb23HViYz4;4V=TPeQQAaR#aj9C`6>=9SWh0AKuht(@AT=Gwx^vX_L2!6$u>
z2D`3|4aiGnLj@1z{$<NBeWQ)z!I8?uSDQ!26HmV2w(V+E_>gdeyuQ{t!$b@7qEwmd
z3k>sT807yz!#xbwEfYOxb9D!e97xl&x&PcKYy+4rR5VKqmCbP%%~%OnY^&_AL-SnF
z&avW3c~-KTBtKF%vWGeR>U-Ydq26IA8DA{WoI^^vXzeE+-Q=D+Ua+h#;SC?CK&7xh
zR@nSVL#C!VXA+Eh9chX#1`X2DQAOkH<@^z*Iz!FKGD~eI%<r*{+(EKzsD*P{B0l`J
z$`{5B<$84;QiRRk%ocepUK#4HbAH;XeD93Gl{gzF5x)@h_>p;2^$3FA^T@tcy%l!G
z42qt8b3CPAu7l@b&|{ZOc9KbprY#eR)AdGjRAg_UsfAM^$>!Bx>|GDZs?Slwb11PF
zQzYT6+?W}$ggrJ!6WzD;!|LS7iGtx;Tdry&o%7=R+nY?`MeFYbFVwSDOY|=wG#q^b
zDrQP6R%TN<Xqlh=GPY0#azN;)6QqXTUb~@tLFkYL)otjvQ-C`9Wo!wz898$AhrIHR
z7IQnrbv(uLNlJHgaR`sfFGE77*2#_<OPZcIZvC8A`zjyV)ik>*ftWNxi~*UG>mq^G
z>w1Ye`$3iKA*)GIH<Cqv_U+GY)fMwTu@yKpMAAufNKF^TBhq_OC4B~J_+m}xsG6a-
z?LCUECCG_8Qwv4mew7wbp);%bSzcSt2k2M#+^sh7f3%q3y}ki8xz|#Q9j~GL3hrwj
zj7lo;c~1mcLczuI863p^GPH#9)r=7NyU3+FHQ9q?IiWrN`im6!A#L_!BhwGjecrkv
zV)A4*PF#(O<f-}^Y(qMd75g})@Q$9fW~O!zql8Fvt7{WNJ-Lmu)Feu~eO~gnmD9(k
z@5T=%>=ViySTimNn~-U{iNYn`dhmp9E6&(GI3RRVXJuB$2l#5+eTQw<ueOn2eD4K4
z=kDI7|0mxppl{&gK1(>RD)TdVyuCO;-#7;kR~Njr3zpz$2O@lLx8Ym~o_K<%fQ^T%
z4-xNSWou(^g|)SHB`63;vtZD4^#6i<>uY2`u>Av1ft<kYBie5h=%*I7<8eC`X@@4Y
z;!W_6W`zEjAngR87L)-^f1L+ErbgR>sns?<t08|>Zg&r)mg`^us5&C_Q(XU`M%!Je
z)#{)Cb+7qnx!pBOEmzJ6&{Qz=Qw4uVZ+9_K>k*g$+R}o4Dy{!2_^n+|Ehr2FcJKLb
TQ9~Jlk7+Uk6j1phZ2RnQ9pEq>
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js
+++ b/browser/devtools/debugger/test/browser_dbg_addon-modules-unpacked.js
@@ -3,46 +3,59 @@
 
 // Make sure the add-on actor can see loaded JS Modules from an add-on
 
 const ADDON_URL = EXAMPLE_URL + "addon5.xpi";
 
 function test() {
   Task.spawn(function () {
     let addon = yield addAddon(ADDON_URL);
+    let tab1 = yield addTab("chrome://browser_dbg_addon5/content/test.xul");
+
     let addonDebugger = yield initAddonDebugger(ADDON_URL);
 
     is(addonDebugger.title, "Debugger - Test unpacked add-on with JS Modules", "Saw the right toolbox title.");
 
     // Check the inital list of sources is correct
     let groups = yield addonDebugger.getSourceGroups();
     is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
 
     let sources = groups[0].sources;
-    is(sources.length, 2, "Should be two sources");
-    ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
-    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
-    is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
-    is(sources[1].label, "test.jsm", "correct label for addon code")
-
-    // Load a new module and check it appears in the list of sources
-    Cu.import("resource://browser_dbg_addon5/test2.jsm", {});
-
-    groups = yield addonDebugger.getSourceGroups();
-    is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
-
-    sources = groups[0].sources;
     is(sources.length, 3, "Should be three sources");
     ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
     is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
     is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
     is(sources[1].label, "test.jsm", "correct label for addon code")
-    is(sources[2].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code")
-    is(sources[2].label, "test2.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+
+    // Load a new module and tab and check they appear in the list of sources
+    Cu.import("resource://browser_dbg_addon5/test2.jsm", {});
+    let tab2 = yield addTab("chrome://browser_dbg_addon5/content/test2.xul");
+
+    groups = yield addonDebugger.getSourceGroups();
+    is(groups[0].name, "browser_dbg_addon5@tests.mozilla.org", "Add-on code should be the first group");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
+
+    sources = groups[0].sources;
+    is(sources.length, 5, "Should be five sources");
+    ok(sources[0].url.endsWith("/browser_dbg_addon5@tests.mozilla.org/bootstrap.js"), "correct url for bootstrap code")
+    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
+    is(sources[1].url, "resource://browser_dbg_addon5/test.jsm", "correct url for addon code")
+    is(sources[1].label, "test.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon5/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+    is(sources[3].url, "resource://browser_dbg_addon5/test2.jsm", "correct url for addon code")
+    is(sources[3].label, "test2.jsm", "correct label for addon code")
+    is(sources[4].url, "chrome://browser_dbg_addon5/content/testxul2.js", "correct url for addon tab code")
+    is(sources[4].label, "testxul2.js", "correct label for addon tab code")
 
     Cu.unload("resource://browser_dbg_addon5/test2.jsm");
     yield addonDebugger.destroy();
+    yield removeTab(tab1);
+    yield removeTab(tab2);
     yield removeAddon(addon);
     finish();
   });
 }
--- a/browser/devtools/debugger/test/browser_dbg_addon-modules.js
+++ b/browser/devtools/debugger/test/browser_dbg_addon-modules.js
@@ -3,46 +3,59 @@
 
 // Make sure the add-on actor can see loaded JS Modules from an add-on
 
 const ADDON_URL = EXAMPLE_URL + "addon4.xpi";
 
 function test() {
   Task.spawn(function () {
     let addon = yield addAddon(ADDON_URL);
+    let tab1 = yield addTab("chrome://browser_dbg_addon4/content/test.xul");
+
     let addonDebugger = yield initAddonDebugger(ADDON_URL);
 
     is(addonDebugger.title, "Debugger - Test add-on with JS Modules", "Saw the right toolbox title.");
 
     // Check the inital list of sources is correct
     let groups = yield addonDebugger.getSourceGroups();
     is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
 
     let sources = groups[0].sources;
-    is(sources.length, 2, "Should be two sources");
-    ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
-    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
-    is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
-    is(sources[1].label, "test.jsm", "correct label for addon code")
-
-    // Load a new module and check it appears in the list of sources
-    Cu.import("resource://browser_dbg_addon4/test2.jsm", {});
-
-    groups = yield addonDebugger.getSourceGroups();
-    is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
-    is(groups.length, 1, "Should be only one group.");
-
-    sources = groups[0].sources;
     is(sources.length, 3, "Should be three sources");
     ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
     is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
     is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
     is(sources[1].label, "test.jsm", "correct label for addon code")
-    is(sources[2].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code")
-    is(sources[2].label, "test2.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+
+    // Load a new module and tab and check they appear in the list of sources
+    Cu.import("resource://browser_dbg_addon4/test2.jsm", {});
+    let tab2 = yield addTab("chrome://browser_dbg_addon4/content/test2.xul");
+
+    groups = yield addonDebugger.getSourceGroups();
+    is(groups[0].name, "browser_dbg_addon4@tests.mozilla.org", "Add-on code should be the first group");
+    is(groups[1].name, "chrome://global", "XUL code should be the second group");
+    is(groups.length, 2, "Should be only two groups.");
+
+    sources = groups[0].sources;
+    is(sources.length, 5, "Should be five sources");
+    ok(sources[0].url.endsWith("/browser_dbg_addon4@tests.mozilla.org.xpi!/bootstrap.js"), "correct url for bootstrap code")
+    is(sources[0].label, "bootstrap.js", "correct label for bootstrap code")
+    is(sources[1].url, "resource://browser_dbg_addon4/test.jsm", "correct url for addon code")
+    is(sources[1].label, "test.jsm", "correct label for addon code")
+    is(sources[2].url, "chrome://browser_dbg_addon4/content/testxul.js", "correct url for addon tab code")
+    is(sources[2].label, "testxul.js", "correct label for addon tab code")
+    is(sources[3].url, "resource://browser_dbg_addon4/test2.jsm", "correct url for addon code")
+    is(sources[3].label, "test2.jsm", "correct label for addon code")
+    is(sources[4].url, "chrome://browser_dbg_addon4/content/testxul2.js", "correct url for addon tab code")
+    is(sources[4].label, "testxul2.js", "correct label for addon tab code")
 
     Cu.unload("resource://browser_dbg_addon4/test2.jsm");
     yield addonDebugger.destroy();
+    yield removeTab(tab1);
+    yield removeTab(tab2);
     yield removeAddon(addon);
     finish();
   });
 }
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -113,17 +113,21 @@ function addAddon(aUrl) {
 
   let deferred = promise.defer();
 
   AddonManager.getInstallForURL(aUrl, aInstaller => {
     aInstaller.install();
     let listener = {
       onInstallEnded: function(aAddon, aAddonInstall) {
         aInstaller.removeListener(listener);
-        deferred.resolve(aAddonInstall);
+
+        // Wait for add-on's startup scripts to execute. See bug 997408
+        executeSoon(function() {
+          deferred.resolve(aAddonInstall);
+        });
       }
     };
     aInstaller.addListener(listener);
   }, "application/x-xpinstall");
 
   return deferred.promise;
 }
 
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -608,16 +608,17 @@ toolbarbutton[sdk-button="true"][cui-are
   width: 32px;
 }
 
 #nav-bar #PanelUI-menu-button {
   -moz-padding-start: 7px;
   -moz-padding-end: 5px;
 }
 
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-badge-container > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):hover > .toolbarbutton-icon {
   background-color: hsla(0,0%,100%,.3);
   background-image: linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.2));
   border: 1px solid rgb(154,154,154);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
@@ -626,33 +627,34 @@ toolbarbutton[sdk-button="true"][cui-are
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   margin-top: 4px;
   margin-bottom: 4px;
 }
 
-:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open="true"]) > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container > .toolbarbutton-icon,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
   background-color: rgba(154,154,154,.5);
   background-image: linear-gradient(hsla(0,0%,100%,.7), hsla(0,0%,100%,.4));
   border: 1px solid rgb(154,154,154);
   box-shadow: 0 1px 1px hsla(0,0%,0%,.1) inset,
               0 0 1px hsla(0,0%,0%,.3) inset;
   transition-duration: 10ms;
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
   background-color: rgba(90%,90%,90%,.4);
   transition: background-color 150ms;
 }
 
+:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button[open],
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button:hover:active,
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover:active {
   padding: 3px;
 }
 
 :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before {
   content: "";
   display: -moz-box;
deleted file mode 100644
--- a/browser/themes/linux/devtools/ruleview.css
+++ /dev/null
@@ -1,150 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-.ruleview {
-  height: 100%;
-}
-
-.ruleview-rule-source {
-  -moz-padding-start: 5px;
-  cursor: pointer;
-  text-align: right;
-  float: right;
-  -moz-user-select: none;
-}
-
-.ruleview-header {
-  border-top-width: 1px;
-  border-bottom-width: 1px;
-  border-top-style: solid;
-  border-bottom-style: solid;
-  padding: 1px 4px;
-  margin-top: 4px;
-  -moz-user-select: none;
-  word-wrap: break-word;
-}
-
-.ruleview-rule-source:hover {
-  text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
-  padding: 2px 4px;
-}
-
-#noResults {
-  font: message-box;
-  color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
-  border-top-width: 1px;
-  border-top-style: dotted;
-}
-
-.ruleview-warning {
-  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  -moz-margin-start: 5px;
-  display: inline-block;
-  vertical-align: top;
-  width: 13px;
-  height: 12px;
-}
-
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
-  cursor: text;
-  padding-right: 20px;
-}
-
-.ruleview-propertylist {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
-  visibility: hidden;
-}
-
-.ruleview-expander {
-  display: inline-block;
-}
-
-.ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
-  -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
-  text-decoration: inherit;
-}
-
-.ruleview-computedlist {
-  list-style: none;
-  padding: 0;
-}
-
-.ruleview-computed {
-  -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
-  border-radius: 50%;
-  width: 1em;
-  height: 1em;
-  vertical-align: text-top;
-  -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
-  text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
-  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
-  border: 1px solid #CCC;
-  padding: 0;
-}
-
-.ruleview-property {
-  border-left: 2px solid transparent;
-  clear: right;
-}
-
-.ruleview-property  > * {
-  vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
-  border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
-  border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
-  border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
-  word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
-  color: #888;
-}
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -100,17 +100,16 @@ browser.jar:
   skin/classic/browser/feeds/feedIcon.png             (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png           (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png        (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png      (feeds/feedIcon16.png)
   skin/classic/browser/feeds/subscribe.css            (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css         (feeds/subscribe-ui.css)
-  skin/classic/browser/fonts/ClearSans-Regular.ttf    (../shared/ClearSans-Regular.ttf)
   skin/classic/browser/newtab/newTab.css              (newtab/newTab.css)
   skin/classic/browser/newtab/controls.png            (../shared/newtab/controls.png)
   skin/classic/browser/places/bookmarksMenu.png       (places/bookmarksMenu.png)
   skin/classic/browser/places/bookmarksToolbar.png    (places/bookmarksToolbar.png)
   skin/classic/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel.png)
   skin/classic/browser/places/bookmarks-notification-finish.png  (places/bookmarks-notification-finish.png)
   skin/classic/browser/places/bookmarks-menu-arrow.png           (places/bookmarks-menu-arrow.png)
   skin/classic/browser/places/calendar.png            (places/calendar.png)
@@ -196,17 +195,17 @@ browser.jar:
   skin/classic/browser/devtools/command-scratchpad@2x.png     (../shared/devtools/images/command-scratchpad@2x.png)
   skin/classic/browser/devtools/command-tilt.png              (../shared/devtools/images/command-tilt.png)
   skin/classic/browser/devtools/command-tilt@2x.png           (../shared/devtools/images/command-tilt@2x.png)
   skin/classic/browser/devtools/command-pick.png              (../shared/devtools/images/command-pick.png)
   skin/classic/browser/devtools/command-pick@2x.png           (../shared/devtools/images/command-pick@2x.png)
   skin/classic/browser/devtools/command-console.png           (../shared/devtools/images/command-console.png)
   skin/classic/browser/devtools/command-console@2x.png        (../shared/devtools/images/command-console@2x.png)
   skin/classic/browser/devtools/alerticon-warning.png (devtools/alerticon-warning.png)
-  skin/classic/browser/devtools/ruleview.css          (devtools/ruleview.css)
+* skin/classic/browser/devtools/ruleview.css          (../shared/devtools/ruleview.css)
 * skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
   skin/classic/browser/devtools/commandline.css              (devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css       (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png       (devtools/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png  (devtools/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-debug-location.png (devtools/editor-debug-location.png)
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -507,31 +507,33 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   transition-duration: 250ms;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],#back-button,#forward-button)) {
   padding: 0 4px;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover,
+toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbaritem-combined-buttons:hover > .toolbarbutton-combined {
   border-color: hsla(0,0%,0%,.2);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.5),
               0 1px 0 hsla(0,0%,100%,.5) inset;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],[open],#back-button,#forward-button)):hover,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover] > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover > .toolbarbutton-menubutton-dropmarker {
   background: hsla(0,0%,100%,.1) linear-gradient(hsla(0,0%,100%,.3), hsla(0,0%,100%,.1)) padding-box;
 }
 
 toolbar .toolbarbutton-1:not(:-moz-any([type="menu-button"],[disabled],#back-button,#forward-button)):-moz-any(:hover:active,[open],[checked]),
+toolbar .toolbarbutton-1[type="menu-button"]:not([disabled]) > .toolbarbutton-menubutton-button[open],
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open]))[buttonover]:active > .toolbarbutton-menubutton-button,
 toolbar .toolbarbutton-1[type="menu-button"]:not(:-moz-any([disabled],[open],[buttonover])):hover:active > .toolbarbutton-menubutton-dropmarker,
 toolbar .toolbarbutton-1[type="menu-button"][open]:not([disabled]) > .toolbarbutton-menubutton-dropmarker {
   background: hsla(0,0%,0%,.02) linear-gradient(hsla(0,0%,0%,.12), hsla(0,0%,0%,0)) border-box;
   border-color: hsla(0,0%,0%,.3);
   box-shadow: 0 1px 0 hsla(0,0%,100%,.5),
               0 1px 0 hsla(0,0%,0%,.05) inset,
               0 1px 1px hsla(0,0%,0%,.2) inset;
deleted file mode 100644
--- a/browser/themes/osx/devtools/ruleview.css
+++ /dev/null
@@ -1,154 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-.ruleview {
-  height: 100%;
-}
-
-.ruleview-rule-source {
-  -moz-padding-start: 5px;
-  cursor: pointer;
-  text-align: right;
-  float: right;
-  -moz-user-select: none;
-}
-
-.ruleview-header {
-  border-top-width: 1px;
-  border-bottom-width: 1px;
-  border-top-style: solid;
-  border-bottom-style: solid;
-  padding: 1px 4px;
-  -moz-user-select: none;
-  word-wrap: break-word;
-}
-
-.ruleview-rule-pseudo-element {
-  padding-left:20px;
-  border-left: solid 10px;
-}
-
-.ruleview-rule-source:hover {
-  text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
-  padding: 2px 4px;
-}
-
-#noResults {
-  font: message-box;
-  color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
-  border-top-width: 1px;
-  border-top-style: dotted;
-}
-
-.ruleview-warning {
-  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  -moz-margin-start: 5px;
-  display: inline-block;
-  vertical-align: top;
-  width: 13px;
-  height: 12px;
-}
-
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
-  cursor: text;
-  padding-right: 20px;
-}
-
-.ruleview-propertylist {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
-  visibility: hidden;
-}
-
-.ruleview-expander {
-  display: inline-block;
-}
-
-.ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
-  -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
-  text-decoration: inherit;
-}
-
-.ruleview-computedlist {
-  list-style: none;
-  padding: 0;
-}
-
-.ruleview-computed {
-  -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
-  border-radius: 50%;
-  width: 1em;
-  height: 1em;
-  vertical-align: text-top;
-  -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
-  text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
-  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
-  border: 1px solid #CCC;
-  padding: 0;
-}
-
-.ruleview-property {
-  border-left: 2px solid transparent;
-  clear: right;
-}
-
-.ruleview-property  > * {
-  vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
-  border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
-  border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
-  border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
-  word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
-  color: #888;
-}
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -164,17 +164,16 @@ browser.jar:
   skin/classic/browser/feeds/subscribe.css                  (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css               (feeds/subscribe-ui.css)
   skin/classic/browser/feeds/feedIcon.png                   (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png                 (feeds/feedIcon16.png)
   skin/classic/browser/feeds/videoFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/videoFeedIcon16.png            (feeds/feedIcon16.png)
   skin/classic/browser/feeds/audioFeedIcon.png              (feeds/feedIcon.png)
   skin/classic/browser/feeds/audioFeedIcon16.png            (feeds/feedIcon16.png)
-  skin/classic/browser/fonts/ClearSans-Regular.ttf          (../shared/ClearSans-Regular.ttf)
   skin/classic/browser/newtab/newTab.css                    (newtab/newTab.css)
   skin/classic/browser/newtab/controls.png                  (../shared/newtab/controls.png)
   skin/classic/browser/newtab/controls@2x.png               (newtab/controls@2x.png)
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/places/allBookmarks.png              (places/allBookmarks.png)
 * skin/classic/browser/places/places.css                    (places/places.css)
@@ -317,17 +316,17 @@ browser.jar:
   skin/classic/browser/devtools/command-scratchpad@2x.png     (../shared/devtools/images/command-scratchpad@2x.png)
   skin/classic/browser/devtools/command-tilt.png              (../shared/devtools/images/command-tilt.png)
   skin/classic/browser/devtools/command-tilt@2x.png           (../shared/devtools/images/command-tilt@2x.png)
   skin/classic/browser/devtools/command-pick.png              (../shared/devtools/images/command-pick.png)
   skin/classic/browser/devtools/command-pick@2x.png           (../shared/devtools/images/command-pick@2x.png)
   skin/classic/browser/devtools/command-console.png           (../shared/devtools/images/command-console.png)
   skin/classic/browser/devtools/command-console@2x.png        (../shared/devtools/images/command-console@2x.png)
   skin/classic/browser/devtools/alerticon-warning.png       (devtools/alerticon-warning.png)
-  skin/classic/browser/devtools/ruleview.css                (devtools/ruleview.css)
+* skin/classic/browser/devtools/ruleview.css                (../shared/devtools/ruleview.css)
   skin/classic/browser/devtools/commandline.css             (devtools/commandline.css)
   skin/classic/browser/devtools/markup-view.css             (../shared/devtools/markup-view.css)
   skin/classic/browser/devtools/editor-error.png             (devtools/editor-error.png)
   skin/classic/browser/devtools/editor-breakpoint.png        (devtools/editor-breakpoint.png)
   skin/classic/browser/devtools/editor-debug-location.png    (devtools/editor-debug-location.png)
 * skin/classic/browser/devtools/webconsole.css                  (devtools/webconsole.css)
   skin/classic/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
   skin/classic/browser/devtools/webconsole.png                  (devtools/webconsole.png)
deleted file mode 100644
index fe686f8d2a1343973005977cf21b00b8a388d56a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/devtools/ruleview.css
@@ -0,0 +1,161 @@
+/* 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/. */
+
+.ruleview {
+  height: 100%;
+}
+
+.ruleview-rule-source {
+  -moz-padding-start: 5px;
+  cursor: pointer;
+  text-align: right;
+  float: right;
+  -moz-user-select: none;
+}
+
+.ruleview-header {
+  border-top-width: 1px;
+  border-bottom-width: 1px;
+  border-top-style: solid;
+  border-bottom-style: solid;
+  padding: 1px 4px;
+  -moz-user-select: none;
+  word-wrap: break-word;
+%ifndef XP_MACOSX
+  margin-top: 4px;
+%endif
+}
+
+.ruleview-rule-pseudo-element {
+  padding-left:20px;
+  border-left: solid 10px;
+}
+
+.ruleview-rule-source:hover {
+  text-decoration: underline;
+}
+
+.ruleview-rule,
+#noResults {
+  padding: 2px 4px;
+}
+
+#noResults {
+  font: message-box;
+  color: GrayText;
+}
+
+.ruleview-rule + .ruleview-rule {
+  border-top-width: 1px;
+  border-top-style: dotted;
+}
+
+.ruleview-warning {
+  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
+  -moz-margin-start: 5px;
+  display: inline-block;
+  vertical-align: top;
+  width: 13px;
+  height: 12px;
+}
+
+.ruleview-ruleopen {
+  -moz-padding-end: 5px;
+}
+
+.ruleview-ruleclose {
+  cursor: text;
+  padding-right: 20px;
+}
+
+.ruleview-propertylist {
+  list-style: none;
+  padding: 0;
+  margin: 0;
+}
+
+.ruleview-rule:not(:hover) .ruleview-enableproperty {
+  visibility: hidden;
+}
+
+.ruleview-expander {
+  display: inline-block;
+}
+
+.ruleview-newproperty {
+  /* (enable checkbox width: 12px) + (expander width: 15px) */
+  -moz-margin-start: 27px;
+}
+
+.ruleview-namecontainer,
+.ruleview-propertycontainer,
+.ruleview-propertyname,
+.ruleview-propertyvalue {
+  text-decoration: inherit;
+}
+
+.ruleview-computedlist {
+  list-style: none;
+  padding: 0;
+}
+
+.ruleview-computed {
+  -moz-margin-start: 35px;
+}
+
+.ruleview-colorswatch {
+  border-radius: 50%;
+  width: 1em;
+  height: 1em;
+  vertical-align: text-top;
+  -moz-margin-end: 5px;
+}
+
+.ruleview-overridden {
+  text-decoration: line-through;
+}
+
+.theme-light .ruleview-overridden {
+  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
+}
+
+.styleinspector-propertyeditor {
+  border: 1px solid #CCC;
+  padding: 0;
+}
+
+.ruleview-property {
+  border-left: 3px solid transparent;
+  clear: right;
+}
+
+.ruleview-property  > * {
+  vertical-align: middle;
+}
+
+.theme-dark .ruleview-property[dirty] {
+  border-left-color: #70bf53; /* Green */
+}
+
+.theme-light .ruleview-property[dirty] {
+  border-left-color: #2cbb0f; /* Green */
+}
+
+.ruleview-namecontainer > .ruleview-propertyname,
+.ruleview-propertycontainer > .ruleview-propertyvalue {
+  border-bottom: 1px dashed transparent;
+}
+
+.ruleview-namecontainer:hover > .ruleview-propertyname,
+.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
+  border-bottom-color: hsl(0,0%,50%);
+}
+
+.ruleview-selector {
+  word-wrap: break-word;
+}
+
+.ruleview-selector-separator, .ruleview-selector-unmatched {
+  color: #888;
+}
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -2,17 +2,17 @@
 /* - This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this file,
    - You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 @namespace html "http://www.w3.org/1999/xhtml";
 
 @font-face {
   font-family: "Clear Sans";
-  src: url("chrome://browser/skin/fonts/ClearSans-Regular.ttf");
+  src: url("chrome://browser/content/fonts/ClearSans-Regular.woff") format('woff');
 }
 
 page {
   -moz-appearance: none;
   background-image: linear-gradient(#FFFFFF, #EDEDED 100px);
 }
 
 caption {
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -725,16 +725,17 @@ toolbarbutton[sdk-button="true"][cui-are
   background-repeat: no-repeat;
   background-size: 1px 16px;
 }
 
 @conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
   border-color: hsla(210,4%,10%,.1);
 }
 
+#nav-bar .toolbarbutton-1:not([disabled=true]) > .toolbarbutton-menubutton-button[open] + .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
 @conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
   background-color: hsla(210,4%,10%,.08);
@@ -794,17 +795,17 @@ toolbarbutton[sdk-button="true"][cui-are
     background-color: hsla(210,48%,96%,.75);
     box-shadow: 0 0 1px hsla(210,54%,20%,.03),
                 0 0 2px hsla(210,54%,20%,.1);
   }
 %ifdef WINDOWS_AERO
 }
 %endif
 
-#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
+#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):-moz-any(:hover:active, [open]) > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
 #nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
   background-color: hsla(210,4%,10%,.12);
   border-top-color: hsla(210,4%,10%,.2);
   box-shadow: 0 1px 0 0 hsla(210,4%,10%,.1) inset;
   transition-duration: 10ms;
deleted file mode 100644
--- a/browser/themes/windows/devtools/ruleview.css
+++ /dev/null
@@ -1,150 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-.ruleview {
-  height: 100%;
-}
-
-.ruleview-rule-source {
-  -moz-padding-start: 5px;
-  cursor: pointer;
-  text-align: right;
-  float: right;
-  -moz-user-select: none;
-}
-
-.ruleview-header {
-  border-top-width: 1px;
-  border-bottom-width: 1px;
-  border-top-style: solid;
-  border-bottom-style: solid;
-  padding: 1px 4px;
-  margin-top: 4px;
-  -moz-user-select: none;
-  word-wrap: break-word;
-}
-
-.ruleview-rule-source:hover {
-  text-decoration: underline;
-}
-
-.ruleview-rule,
-#noResults {
-  padding: 2px 4px;
-}
-
-#noResults {
-  font: message-box;
-  color: GrayText;
-}
-
-.ruleview-rule + .ruleview-rule {
-  border-top-width: 1px;
-  border-top-style: dotted;
-}
-
-.ruleview-warning {
-  background: url("chrome://browser/skin/devtools/alerticon-warning.png");
-  -moz-margin-start: 5px;
-  display: inline-block;
-  vertical-align: top;
-  width: 13px;
-  height: 12px;
-}
-
-.ruleview-ruleopen {
-  -moz-padding-end: 5px;
-}
-
-.ruleview-ruleclose {
-  cursor: text;
-  padding-right: 20px;
-}
-
-.ruleview-propertylist {
-  list-style: none;
-  padding: 0;
-  margin: 0;
-}
-
-.ruleview-rule:not(:hover) .ruleview-enableproperty {
-  visibility: hidden;
-}
-
-.ruleview-expander {
-  display: inline-block;
-}
-
-.ruleview-newproperty {
-  /* (enable checkbox width: 12px) + (expander width: 15px) */
-  -moz-margin-start: 27px;
-}
-
-.ruleview-namecontainer,
-.ruleview-propertycontainer,
-.ruleview-propertyname,
-.ruleview-propertyvalue {
-  text-decoration: inherit;
-}
-
-.ruleview-computedlist {
-  list-style: none;
-  padding: 0;
-}
-
-.ruleview-computed {
-  -moz-margin-start: 35px;
-}
-
-.ruleview-colorswatch {
-  border-radius: 50%;
-  width: 1em;
-  height: 1em;
-  vertical-align: text-top;
-  -moz-margin-end: 5px;
-}
-
-.ruleview-overridden {
-  text-decoration: line-through;
-}
-
-.theme-light .ruleview-overridden {
-  -moz-text-decoration-color: #667380; /*  Content (Text) - Dark Grey */
-}
-
-.styleinspector-propertyeditor {
-  border: 1px solid #CCC;
-  padding: 0;
-}
-
-.ruleview-property {
-  border-left: 2px solid transparent;
-  clear: right;
-}
-
-.ruleview-property  > * {
-  vertical-align: middle;
-}
-
-.ruleview-property[dirty] {
-  border-left-color: #68E268;
-}
-
-.ruleview-namecontainer > .ruleview-propertyname,
-.ruleview-propertycontainer > .ruleview-propertyvalue {
-  border-bottom: 1px dashed transparent;
-}
-
-.ruleview-namecontainer:hover > .ruleview-propertyname,
-.ruleview-propertycontainer:hover > .ruleview-propertyvalue {
-  border-bottom-color: hsl(0,0%,50%);
-}
-
-.ruleview-selector {
-  word-wrap: break-word;
-}
-
-.ruleview-selector-separator, .ruleview-selector-unmatched {
-  color: #888;
-}
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -121,17 +121,16 @@ browser.jar:
         skin/classic/browser/feeds/feedIcon.png                      (feeds/feedIcon.png)
         skin/classic/browser/feeds/feedIcon16.png                    (feeds/feedIcon16.png)
         skin/classic/browser/feeds/audioFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/audioFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/videoFeedIcon.png                 (feeds/feedIcon.png)
         skin/classic/browser/feeds/videoFeedIcon16.png               (feeds/feedIcon16.png)
         skin/classic/browser/feeds/subscribe.css                     (feeds/subscribe.css)
         skin/classic/browser/feeds/subscribe-ui.css                  (feeds/subscribe-ui.css)
-        skin/classic/browser/fonts/ClearSans-Regular.ttf             (../shared/ClearSans-Regular.ttf)
         skin/classic/browser/newtab/newTab.css                       (newtab/newTab.css)
         skin/classic/browser/newtab/controls.png                     (../shared/newtab/controls.png)
         skin/classic/browser/places/places.css                       (places/places.css)
 *       skin/classic/browser/places/organizer.css                    (places/organizer.css)
         skin/classic/browser/places/bookmark.png                     (places/bookmark.png)
         skin/classic/browser/places/query.png                        (places/query.png)
         skin/classic/browser/places/bookmarksMenu.png                (places/bookmarksMenu.png)
         skin/classic/browser/places/bookmarksToolbar.png             (places/bookmarksToolbar.png)
@@ -221,17 +220,17 @@ browser.jar:
 *       skin/classic/browser/devtools/dark-theme.css                (../shared/devtools/dark-theme.css)
 *       skin/classic/browser/devtools/light-theme.css               (../shared/devtools/light-theme.css)
         skin/classic/browser/devtools/filters.svg                   (../shared/devtools/filters.svg)
         skin/classic/browser/devtools/controls.png                  (../shared/devtools/images/controls.png)
         skin/classic/browser/devtools/controls@2x.png               (../shared/devtools/images/controls@2x.png)
 *       skin/classic/browser/devtools/widgets.css                   (devtools/widgets.css)
         skin/classic/browser/devtools/commandline-icon.png          (devtools/commandline-icon.png)
         skin/classic/browser/devtools/alerticon-warning.png         (devtools/alerticon-warning.png)
-        skin/classic/browser/devtools/ruleview.css                  (devtools/ruleview.css)
+*       skin/classic/browser/devtools/ruleview.css                  (../shared/devtools/ruleview.css)
         skin/classic/browser/devtools/commandline.css               (devtools/commandline.css)
         skin/classic/browser/devtools/command-paintflashing.png     (../shared/devtools/images/command-paintflashing.png)
         skin/classic/browser/devtools/command-paintflashing@2x.png  (../shared/devtools/images/command-paintflashing@2x.png)
         skin/classic/browser/devtools/command-responsivemode.png    (../shared/devtools/images/command-responsivemode.png)
         skin/classic/browser/devtools/command-responsivemode@2x.png (../shared/devtools/images/command-responsivemode@2x.png)
         skin/classic/browser/devtools/command-scratchpad.png        (../shared/devtools/images/command-scratchpad.png)
         skin/classic/browser/devtools/command-scratchpad@2x.png     (../shared/devtools/images/command-scratchpad@2x.png)
         skin/classic/browser/devtools/command-tilt.png              (../shared/devtools/images/command-tilt.png)
@@ -486,17 +485,16 @@ browser.jar:
         skin/classic/aero/browser/feeds/feedIcon.png                 (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/feedIcon16.png               (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/audioFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon.png            (feeds/feedIcon-aero.png)
         skin/classic/aero/browser/feeds/videoFeedIcon16.png          (feeds/feedIcon16-aero.png)
         skin/classic/aero/browser/feeds/subscribe.css                (feeds/subscribe.css)
         skin/classic/aero/browser/feeds/subscribe-ui.css             (feeds/subscribe-ui.css)
-        skin/classic/aero/browser/fonts/ClearSans-Regular.ttf        (../shared/ClearSans-Regular.ttf)
         skin/classic/aero/browser/newtab/newTab.css                  (newtab/newTab.css)
         skin/classic/aero/browser/newtab/controls.png                (../shared/newtab/controls.png)
 *       skin/classic/aero/browser/places/places.css                  (places/places-aero.css)
 *       skin/classic/aero/browser/places/organizer.css               (places/organizer-aero.css)
         skin/classic/aero/browser/places/bookmark.png                (places/bookmark-aero.png)
         skin/classic/aero/browser/places/query.png                   (places/query-aero.png)
         skin/classic/aero/browser/places/bookmarksMenu.png           (places/bookmarksMenu-aero.png)
         skin/classic/aero/browser/places/bookmarksToolbar.png        (places/bookmarksToolbar-aero.png)
@@ -597,17 +595,17 @@ browser.jar:
         skin/classic/aero/browser/devtools/command-scratchpad@2x.png (../shared/devtools/images/command-scratchpad@2x.png)
         skin/classic/aero/browser/devtools/command-tilt.png          (../shared/devtools/images/command-tilt.png)
         skin/classic/aero/browser/devtools/command-tilt@2x.png       (../shared/devtools/images/command-tilt@2x.png)
         skin/classic/aero/browser/devtools/command-pick.png          (../shared/devtools/images/command-pick.png)
         skin/classic/aero/browser/devtools/command-pick@2x.png       (../shared/devtools/images/command-pick@2x.png)
         skin/classic/aero/browser/devtools/command-console.png       (../shared/devtools/images/command-console.png)
         skin/classic/aero/browser/devtools/command-console@2x.png    (../shared/devtools/images/command-console@2x.png)
         skin/classic/aero/browser/devtools/alerticon-warning.png     (devtools/alerticon-warning.png)
-        skin/classic/aero/browser/devtools/ruleview.css              (devtools/ruleview.css)
+*       skin/classic/aero/browser/devtools/ruleview.css              (../shared/devtools/ruleview.css)
         skin/classic/aero/browser/devtools/commandline.css           (devtools/commandline.css)
         skin/classic/aero/browser/devtools/markup-view.css           (../shared/devtools/markup-view.css)
         skin/classic/aero/browser/devtools/editor-error.png           (devtools/editor-error.png)
         skin/classic/aero/browser/devtools/editor-breakpoint.png      (devtools/editor-breakpoint.png)
         skin/classic/aero/browser/devtools/editor-debug-location.png  (devtools/editor-debug-location.png)
 *       skin/classic/aero/browser/devtools/webconsole.css                  (devtools/webconsole.css)
         skin/classic/aero/browser/devtools/webconsole_networkpanel.css     (devtools/webconsole_networkpanel.css)
         skin/classic/aero/browser/devtools/webconsole.png                  (devtools/webconsole.png)
--- 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/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/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2028,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:
@@ -2070,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
@@ -2684,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,
@@ -3185,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;
@@ -3209,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;
 }
 
@@ -3371,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/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/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/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/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;