Merge m-c to inbound on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 26 Feb 2014 18:31:11 -0800
changeset 171219 75e7fb569d74a41e863d6e1c69b2199aa79dbcf5
parent 171194 782acfe6edfdd423376d514179764fccbc8c3803 (diff)
parent 171218 de2ce8226ca8b1852486da1b7d861ab46caed020 (current diff)
child 171220 f8054c8163298a17c57b3407dd1a0928f707c623
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge m-c to inbound on a CLOSED TREE
b2g/config/emulator-ics/sources.xml
b2g/config/emulator-jb/sources.xml
b2g/config/emulator/sources.xml
b2g/config/gaia.json
b2g/config/hamachi/sources.xml
b2g/config/helix/sources.xml
b2g/config/inari/sources.xml
b2g/config/leo/sources.xml
b2g/config/mako/sources.xml
b2g/config/wasabi/sources.xml
gfx/layers/client/ClientCanvasLayer.h
gfx/layers/client/TextureClient.cpp
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -12,17 +12,17 @@
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 #include "OuterDocAccessible.h"
 
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsISelectionPrivate.h"
-#include "nsTraceRefcntImpl.h"
+#include "nsTraceRefcnt.h"
 #include "nsIWebProgress.h"
 #include "prenv.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIURI.h"
 #include "mozilla/dom/Element.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
@@ -795,17 +795,17 @@ logging::DOMEvent(const char* aDescr, ns
   logging::MsgEnd();
 }
 
 void
 logging::Stack()
 {
   if (IsEnabled(eStack)) {
     printf("  stack: \n");
-    nsTraceRefcntImpl::WalkTheStack(stdout);
+    nsTraceRefcnt::WalkTheStack(stdout);
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // namespace logging:: initialization
 
 bool
 logging::IsEnabled(uint32_t aModules)
--- a/accessible/src/jsat/Utils.jsm
+++ b/accessible/src/jsat/Utils.jsm
@@ -428,16 +428,25 @@ this.Logger = {
     if (aEvent.eventType == Events.STATE_CHANGE) {
       let event = aEvent.QueryInterface(Ci.nsIAccessibleStateChangeEvent);
       let stateStrings = event.isExtraState ?
         Utils.AccRetrieval.getStringStates(0, event.state) :
         Utils.AccRetrieval.getStringStates(event.state, 0);
       str += ' (' + stateStrings.item(0) + ')';
     }
 
+    if (aEvent.eventType == Events.VIRTUALCURSOR_CHANGED) {
+      let event = aEvent.QueryInterface(
+        Ci.nsIAccessibleVirtualCursorChangeEvent);
+      let pivot = aEvent.accessible.QueryInterface(
+        Ci.nsIAccessibleDocument).virtualCursor;
+      str += ' (' + this.accessibleToString(event.oldAccessible) + ' -> ' +
+	this.accessibleToString(pivot.position) + ')';
+    }
+
     return str;
   },
 
   statesToString: function statesToString(aAccessible) {
     return Utils.getState(aAccessible).toString();
   },
 
   dumpTree: function dumpTree(aLogLevel, aRootAccessible) {
--- a/accessible/src/jsat/content-script.js
+++ b/accessible/src/jsat/content-script.js
@@ -395,16 +395,18 @@ addMessageListener(
     addMessageListener('AccessFu:MoveCaret', moveCaret);
     addMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
     addMessageListener('AccessFu:ClearCursor', clearCursor);
 
     if (!eventManager) {
       eventManager = new EventManager(this);
     }
     eventManager.start();
+
+    sendAsyncMessage('AccessFu:ContentStarted');
   });
 
 addMessageListener(
   'AccessFu:Stop',
   function(m) {
     Logger.debug('AccessFu:Stop');
 
     removeMessageListener('AccessFu:MoveToPoint', moveToPoint);
--- a/accessible/tests/mochitest/jsat/a11y.ini
+++ b/accessible/tests/mochitest/jsat/a11y.ini
@@ -1,13 +1,15 @@
 [DEFAULT]
 support-files =
   jsatcommon.js
   output.js
   doc_traversal.html
+  doc_content_integration.html
 
 [test_alive.html]
+[test_content_integration.html]
 [test_explicit_names.html]
 [test_landmarks.html]
 [test_live_regions.html]
 [test_output.html]
 [test_tables.html]
 [test_traversal.html]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/doc_content_integration.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Traversal Rule test document</title>
+  <meta charset="utf-8" />
+  <script>
+    var frameContents = '<html>' +
+      '<head><title>such app</title></head>' +
+      '<body>' +
+      '<h1>wow</h1>' +
+      '<label><input type="checkbox">many option</label>' +
+      '</body>' +
+      '</html>';
+
+  </script>
+  <style>
+    #windows > iframe {
+      width: 320px;
+      height: 480px;
+    }
+  </style>
+
+</head>
+<body>
+  <div>Phone status bar</div>
+  <div id="windows"></div>
+  <button>Home</button>
+</body>
+</html>
--- a/accessible/tests/mochitest/jsat/jsatcommon.js
+++ b/accessible/tests/mochitest/jsat/jsatcommon.js
@@ -150,8 +150,122 @@ var AccessFuTest = {
       }
     };
 
     // Invoke the whole thing.
     SpecialPowers.setIntPref("accessibility.accessfu.activate", 1);
     SpecialPowers.setIntPref("accessibility.accessfu.notify_output", 1);
   }
 };
+
+function AccessFuContentTest(aFuncResultPairs) {
+  this.queue = aFuncResultPairs;
+}
+
+AccessFuContentTest.prototype = {
+  currentPair: null,
+
+  start: function(aFinishedCallback) {
+    this.finishedCallback = aFinishedCallback;
+    var self = this;
+
+    // Get top content message manager, and set it up.
+    this.mms = [Utils.getMessageManager(currentBrowser())];
+    this.setupMessageManager(this.mms[0], function () {
+      // Get child message managers and set them up
+      var frames = currentTabDocument().querySelectorAll('iframe');
+      var toSetup = 0;
+      for (var i = 0; i < frames.length; i++ ) {
+        var mm = Utils.getMessageManager(frames[i]);
+        if (mm) {
+          toSetup++;
+          self.mms.push(mm);
+          self.setupMessageManager(mm, function () {
+            if (--toSetup === 0) {
+              // All message managers are loaded and ready to go.
+              self.pump();
+            }
+          });
+        }
+      }
+    });
+  },
+
+  setupMessageManager:  function (aMessageManager, aCallback) {
+    function contentScript() {
+      addMessageListener('AccessFuTest:Focus', function (aMessage) {
+        var elem = content.document.querySelector(aMessage.json.selector);
+        if (elem) {
+          if (aMessage.json.blur) {
+            elem.blur();
+          } else {
+            elem.focus();
+          }
+        }
+      });
+    }
+
+    aMessageManager.addMessageListener('AccessFu:Present', this);
+    aMessageManager.addMessageListener('AccessFu:Ready', function (aMessage) {
+      aMessageManager.addMessageListener('AccessFu:ContentStarted', aCallback);
+      aMessageManager.sendAsyncMessage('AccessFu:Start', { buildApp: 'browser' });
+    });
+
+    aMessageManager.loadFrameScript(
+      'chrome://global/content/accessibility/content-script.js', false);
+    aMessageManager.loadFrameScript(
+      'data:,(' + contentScript.toString() + ')();', false);
+  },
+
+  pump: function() {
+    this.currentPair = this.queue.shift();
+
+    if (this.currentPair) {
+      if (this.currentPair[0] instanceof Function) {
+        this.currentPair[0](this.mms[0]);
+      } else {
+        this.mms[0].sendAsyncMessage(this.currentPair[0].name,
+                                     this.currentPair[0].json);
+      }
+    } else if (this.finishedCallback) {
+      for (var mm of this.mms) {
+	mm.sendAsyncMessage('AccessFu:Stop');
+      }
+      this.finishedCallback();
+    }
+  },
+
+  receiveMessage: function(aMessage) {
+    if (!this.currentPair) {
+      return;
+    }
+
+    var expected = this.currentPair[1];
+
+    if (expected) {
+      if (expected.speak !== undefined) {
+        var speech = this.extractUtterance(aMessage.json);
+        if (!speech) {
+          // Probably a visual highlight adjustment after a scroll.
+          return;
+        }
+        var checkFunc = SimpleTest[expected.speak_checkFunc] || is;
+        checkFunc(speech, expected.speak);
+      }
+    }
+
+    this.pump();
+  },
+
+  extractUtterance: function(aData) {
+    for (var output of aData) {
+      if (output && output.type === 'Speech') {
+        for (var action of output.details.actions) {
+          if (action && action.method == 'speak') {
+            return action.data;
+          }
+        }
+      }
+    }
+
+    return null;
+  }
+};
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/jsat/test_content_integration.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Tests AccessFu content integration</title>
+  <meta charset="utf-8" />
+  <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="chrome://mochikit/content/chrome-harness.js">
+  </script>
+
+  <script type="application/javascript" src="../common.js"></script>
+  <script type="application/javascript" src="../browser.js"></script>
+  <script type="application/javascript" src="../events.js"></script>
+  <script type="application/javascript" src="../role.js"></script>
+  <script type="application/javascript" src="../states.js"></script>
+  <script type="application/javascript" src="../layout.js"></script>
+  <script type="application/javascript" src="jsatcommon.js"></script>
+
+  <script type="application/javascript">
+    function doTest() {
+      var doc = currentTabDocument();
+      var iframe = doc.createElement("iframe");
+      iframe.mozbrowser = true;
+      iframe.addEventListener("mozbrowserloadend", function () {
+        var simpleMoveNext = { name: 'AccessFu:MoveCursor',
+                               json: { action: 'moveNext',
+                                       rule: 'Simple',
+                                       inputType: 'gesture',
+                                       origin: 'top' }
+                             };
+
+        var simpleMovePrevious = { name: 'AccessFu:MoveCursor',
+                                   json: { action: 'movePrevious',
+                                           rule: 'Simple',
+                                           inputType: 'gesture',
+                                           origin: 'top' }
+                                 };
+
+        var activateCurrent = { name: 'AccessFu:Activate',
+                                json: { origin: 'top' } };
+
+        var simpleMoveLast = { name: 'AccessFu:MoveCursor',
+                               json: { action: 'moveLast',
+                                       rule: 'Simple',
+                                       inputType: 'gesture',
+                                       origin: 'top' }
+                             };
+
+        var simpleMoveFirst = { name: 'AccessFu:MoveCursor',
+                                json: { action: 'moveFirst',
+                                        rule: 'Simple',
+                                        inputType: 'gesture',
+                                        origin: 'top' }
+                              };
+
+        var clearCursor = { name: 'AccessFu:ClearCursor',
+                            json: { origin: 'top' }
+                          };
+
+        function focusFunc(aSelector, aBlur) {
+         return function (mm) {
+          mm.sendAsyncMessage(
+            'AccessFuTest:Focus', { selector: aSelector, blur: aBlur });
+          };
+        }
+
+        var contentTest = new AccessFuContentTest(
+          [
+            // Simple traversal forward
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+           [simpleMoveNext,
+            { speak: 'wow heading level 1 such app' }],
+           [simpleMoveNext,
+            { speak: 'many option not checked check button' }],
+            // check checkbox
+           [activateCurrent,
+            { speak: 'checked' }],
+            [null,
+             { speak: 'checked', speak_checkFunc: 'todo_isnot' }],
+            // uncheck checkbox
+           [simpleMoveNext,
+            { speak: 'Home button' }],
+
+            // Simple traversal backward
+           [simpleMovePrevious,
+            { speak: 'many option checked check button such app' }],
+           [activateCurrent,
+            { speak: 'unchecked' }],
+           [null,
+            { speak: 'unchecked', speak_checkFunc: 'todo_isnot' }],
+           [simpleMovePrevious,
+            { speak: 'wow heading level 1' }],
+           [simpleMovePrevious,
+            { speak: 'Phone status bar' }],
+
+            // Moving to the absolute last item from an embedded document fails.
+            // Bug 972035.
+            [simpleMoveNext,
+            { speak: 'wow heading level 1 such app' }],
+            // Move from an inner frame to the last element in the parent doc
+            [simpleMoveLast,
+             { speak: 'Home button', speak_checkFunc: 'todo_is' }],
+
+            [clearCursor, null], // Reset cursors
+
+            // Moving to the absolute first item from an embedded document fails.
+            // Bug 972035.
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+            [simpleMoveNext,
+             { speak: 'wow heading level 1 such app' }],
+            [simpleMoveNext,
+             { speak: 'many option not checked check button' }],
+            [simpleMoveFirst,
+             { speak: 'Phone status bar', speak_checkFunc: 'todo_is' }],
+
+            // Reset cursors
+            [clearCursor, null],
+
+            // Move cursor with focus in outside document
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+            [ focusFunc('button', false), { speak: 'Home button' }],
+
+            // Blur button and reset cursor
+            [focusFunc('button', true), null],
+            [clearCursor, null],
+
+            // Set focus on element outside of embedded frame while cursor is in frame
+            [simpleMoveNext,
+            { speak: 'Phone status bar Traversal Rule test document' }],
+            [simpleMoveNext,
+             { speak: 'wow heading level 1 such app' }],
+            [focusFunc('button', false), { speak: 'Home button' }]
+
+            // XXX: Set focus on iframe itself.
+            // XXX: Set focus on element in iframe when cursor is outside of it.
+            // XXX: Set focus on element in iframe when cursor is in iframe.
+        ]);
+
+        contentTest.start(function () {
+          closeBrowserWindow();
+          SimpleTest.finish();
+        });
+
+      });
+      iframe.src = 'data:text/html;charset=utf-8,' + doc.defaultView.frameContents;
+      doc.querySelector('#windows').appendChild(iframe);
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addLoadEvent(
+      function () {
+        openBrowserWindow(
+          function () {
+            SpecialPowers.pushPrefEnv({
+              "set": [
+                // TODO: remove this as part of bug 820712
+                ["network.disable.ipc.security", true],
+
+
+                ["dom.ipc.browser_frames.oop_by_default", true],
+                ["dom.mozBrowserFramesEnabled", true],
+                ["browser.pagethumbnails.capturing_disabled", true]
+              ]
+            }, doTest) },
+          getRootDirectory(window.location.href) + "doc_content_integration.html");
+        });
+  </script>
+</head>
+<body id="body">
+
+  <a target="_blank"
+     title="Add tests for OOP message handling and general integration"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=972047">Mozilla Bug 933808</a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+</body>
+</html>
--- a/b2g/app/Makefile.in
+++ b/b2g/app/Makefile.in
@@ -21,17 +21,16 @@ LIBS += \
   $(MOZ_ZLIB_LIBS) \
   $(NULL)
 ifeq ($(ANDROID_VERSION),$(findstring $(ANDROID_VERSION),17 18 19))
 LIBS += \
   -lgui \
   -lsuspend \
   $(NULL)
 endif
-OS_LDFLAGS += -Wl,--export-dynamic
 endif
 
 STL_FLAGS=
 
 LIBS += $(JEMALLOC_LIBS)
 
 LIBS += \
   $(XPCOM_STANDALONE_GLUE_LDOPTS) \
--- a/b2g/app/moz.build
+++ b/b2g/app/moz.build
@@ -34,8 +34,10 @@ LOCAL_INCLUDES += [
     '/xpcom/base',
     '/xpcom/build',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     LOCAL_INCLUDES += [
         '/widget/gonk/libdisplay',
     ]
+
+    LDFLAGS += ['-Wl,--export-dynamic']
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "remote": "", 
         "branch": "", 
         "revision": ""
     }, 
-    "revision": "34d0fa6b3f36fd1a56419726546c9344a4b6222a", 
+    "revision": "8bb0cf53956e54999a5f876434207216d9d8982a", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="548965a5866aa38b5f44c336b3a7fb723164e277"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -21,16 +21,17 @@ MOZ_SAFE_BROWSING=
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_METRICS=1
 MOZ_CAPTIVEDETECT=1
 
 MOZ_WEBSMS_BACKEND=1
 MOZ_DISABLE_CRYPTOLEGACY=1
 MOZ_APP_STATIC_INI=1
 NSS_NO_LIBPKIX=1
+MOZ_NO_EV_CERTS=1
 MOZ_DISABLE_EXPORT_JS=1
 
 if test "$OS_TARGET" = "Android"; then
 MOZ_CAPTURE=1
 MOZ_RAW=1
 MOZ_AUDIO_CHANNEL_MANAGER=1
 fi
 
--- a/browser/components/customizableui/src/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/src/CustomizableWidgets.jsm
@@ -673,45 +673,40 @@ const CustomizableWidgets = [{
       containerElem.addEventListener("command", this.onCommand, false);
 
       let list = this.charsetInfo[aSection];
 
       for (let item of list) {
         let elem = aDocument.createElementNS(kNSXUL, "toolbarbutton");
         elem.setAttribute("label", item.label);
         elem.setAttribute("type", "checkbox");
-        elem.section = aSection == "detectors" ? "detectors" : "charsets";
-        elem.value = item.id;
+        elem.section = aSection;
+        elem.value = item.value;
         elem.setAttribute("class", "subviewbutton");
         containerElem.appendChild(elem);
       }
     },
     updateCurrentCharset: function(aDocument) {
       let content = aDocument.defaultView.content;
       let currentCharset = content && content.document && content.document.characterSet;
-      if (currentCharset) {
-        currentCharset = aDocument.defaultView.FoldCharset(currentCharset);
-      }
-      currentCharset = currentCharset ? ("charset." + currentCharset) : "";
+      currentCharset = CharsetMenu.foldCharset(currentCharset);
 
       let pinnedContainer = aDocument.getElementById("PanelUI-characterEncodingView-pinned");
       let charsetContainer = aDocument.getElementById("PanelUI-characterEncodingView-charsets");
       let elements = [...(pinnedContainer.childNodes), ...(charsetContainer.childNodes)];
 
       this._updateElements(elements, currentCharset);
     },
     updateCurrentDetector: function(aDocument) {
       let detectorContainer = aDocument.getElementById("PanelUI-characterEncodingView-autodetect");
-      let detectorEnum = CharsetManager.GetCharsetDetectorList();
       let currentDetector;
       try {
         currentDetector = Services.prefs.getComplexValue(
           "intl.charset.detector", Ci.nsIPrefLocalizedString).data;
       } catch (e) {}
-      currentDetector = "chardet." + (currentDetector || "off");
 
       this._updateElements(detectorContainer.childNodes, currentDetector);
     },
     _updateElements: function(aElements, aCurrentItem) {
       if (!aElements.length) {
         return;
       }
       let disabled = this.maybeDisableMenu(aElements[0].ownerDocument);
@@ -757,23 +752,18 @@ const CustomizableWidgets = [{
 
       let window = node.ownerDocument.defaultView;
       let section = node.section;
       let value = node.value;
 
       // The behavior as implemented here is directly based off of the
       // `MultiplexHandler()` method in browser.js.
       if (section != "detectors") {
-        let charset = value.substring(value.indexOf('charset.') + 'charset.'.length);
-        window.BrowserSetForcedCharacterSet(charset);
+        window.BrowserSetForcedCharacterSet(value);
       } else {
-        value = value.replace(/^chardet\./, "");
-        if (value == "off") {
-          value = "";
-        }
         // Set the detector pref.
         try {
           let str = Cc["@mozilla.org/supports-string;1"]
                       .createInstance(Ci.nsISupportsString);
           str.data = value;
           Services.prefs.setComplexValue("intl.charset.detector", Ci.nsISupportsString, str);
         } catch (e) {
           Cu.reportError("Failed to set the intl.charset.detector preference.");
--- a/config/config.mk
+++ b/config/config.mk
@@ -476,17 +476,17 @@ INCLUDES = \
   $(NSPR_CFLAGS) $(NSS_CFLAGS) \
   $(OS_INCLUDES) \
   $(NULL)
 
 include $(topsrcdir)/config/static-checking-config.mk
 
 CFLAGS		= $(OS_CPPFLAGS) $(OS_CFLAGS)
 CXXFLAGS	= $(OS_CPPFLAGS) $(OS_CXXFLAGS)
-LDFLAGS		= $(OS_LDFLAGS) $(MOZ_FIX_LINK_PATHS)
+LDFLAGS		= $(OS_LDFLAGS) $(MOZBUILD_LDFLAGS) $(MOZ_FIX_LINK_PATHS)
 
 # Allow each module to override the *default* optimization settings
 # by setting MODULE_OPTIMIZE_FLAGS if the developer has not given
 # arguments to --enable-optimize
 ifdef MOZ_OPTIMIZE
 ifeq (1,$(MOZ_OPTIMIZE))
 ifdef MODULE_OPTIMIZE_FLAGS
 CFLAGS		+= $(MODULE_OPTIMIZE_FLAGS)
@@ -582,20 +582,20 @@ HOST_CMMFLAGS += -fobjc-exceptions
 OS_COMPILE_CMFLAGS += -fobjc-exceptions
 OS_COMPILE_CMMFLAGS += -fobjc-exceptions
 ifeq ($(MOZ_WIDGET_TOOLKIT),uikit)
 OS_COMPILE_CMFLAGS += -fobjc-abi-version=2 -fobjc-legacy-dispatch
 OS_COMPILE_CMMFLAGS += -fobjc-abi-version=2 -fobjc-legacy-dispatch
 endif
 endif
 
-COMPILE_CFLAGS	= $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CFLAGS) $(CFLAGS) $(EXTRA_COMPILE_FLAGS)
-COMPILE_CXXFLAGS = $(STL_FLAGS) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CXXFLAGS) $(CXXFLAGS) $(EXTRA_COMPILE_FLAGS)
-COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(EXTRA_COMPILE_FLAGS)
-COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CFLAGS	= $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CFLAGS) $(CFLAGS) $(MOZBUILD_CFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CXXFLAGS = $(STL_FLAGS) $(VISIBILITY_FLAGS) $(DEFINES) $(INCLUDES) $(DSO_CFLAGS) $(DSO_PIC_CFLAGS) $(RTL_FLAGS) $(OS_CPPFLAGS) $(OS_COMPILE_CXXFLAGS) $(CXXFLAGS) $(MOZBUILD_CXXFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CMFLAGS = $(OS_COMPILE_CMFLAGS) $(MOZBUILD_CMFLAGS) $(EXTRA_COMPILE_FLAGS)
+COMPILE_CMMFLAGS = $(OS_COMPILE_CMMFLAGS) $(MOZBUILD_CMMFLAGS) $(EXTRA_COMPILE_FLAGS)
 ASFLAGS += $(EXTRA_ASSEMBLER_FLAGS)
 
 ifndef CROSS_COMPILE
 HOST_CFLAGS += $(RTL_FLAGS)
 endif
 
 #
 # Name of the binary code directories
--- a/configure.in
+++ b/configure.in
@@ -1294,26 +1294,16 @@ if test "$GNU_CC"; then
     CFLAGS="$CFLAGS -std=gnu99"
     if test "${OS_ARCH}" != Darwin; then
         CFLAGS="$CFLAGS -fgnu89-inline"
     fi
     # FIXME: Let us build with strict aliasing. bug 414641.
     CFLAGS="$CFLAGS -fno-strict-aliasing"
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
-    DSO_LDOPTS='-shared'
-    if test "$GCC_USE_GNU_LD"; then
-        # Some tools like ASan use a runtime library that is only
-        # linked against executables, so we must allow undefined
-        # symbols for shared objects in some cases.
-        if test -z "$MOZ_NO_WLZDEFS"; then
-            # Don't allow undefined symbols in libraries
-            DSO_LDOPTS="$DSO_LDOPTS -Wl,-z,defs"
-        fi
-    fi
     WARNINGS_AS_ERRORS='-Werror'
     DSO_CFLAGS=''
     DSO_PIC_CFLAGS='-fPIC'
     ASFLAGS="$ASFLAGS -fPIC"
     AC_MSG_CHECKING([for --noexecstack option to as])
     _SAVE_CFLAGS=$CFLAGS
     CFLAGS="$CFLAGS -Wa,--noexecstack"
     AC_TRY_COMPILE(,,AC_MSG_RESULT([yes])
@@ -1338,16 +1328,24 @@ if test "$GNU_CC"; then
     AC_MSG_CHECKING([for --build-id option to ld])
     _SAVE_LDFLAGS=$LDFLAGS
     LDFLAGS="$LDFLAGS -Wl,--build-id"
     AC_TRY_LINK(,,AC_MSG_RESULT([yes])
                   [NSPR_LDFLAGS="$NSPR_LDFLAGS -Wl,--build-id"],
                   AC_MSG_RESULT([no])
                   LDFLAGS=$_SAVE_LDFLAGS)
 
+    AC_MSG_CHECKING([for --ignore-unresolved-symbol option to ld])
+    HAVE_LINKER_SUPPORT_IGNORE_UNRESOLVED=
+    _SAVE_LDFLAGS=$LDFLAGS
+    LDFLAGS="$LDFLAGS -Wl,--ignore-unresolved-symbol,environ"
+    AC_TRY_LINK(,,AC_MSG_RESULT([yes])
+                  [HAVE_LINKER_SUPPORT_IGNORE_UNRESOLVED=1],
+                  AC_MSG_RESULT([no]))
+    LDFLAGS=$_SAVE_LDFLAGS
 
     # Check for -mssse3 on $CC
     AC_MSG_CHECKING([if toolchain supports -mssse3 option])
     HAVE_TOOLCHAIN_SUPPORT_MSSSE3=
     _SAVE_CFLAGS=$CFLAGS
     CFLAGS="$CFLAGS -mssse3"
     AC_TRY_COMPILE([asm ("pmaddubsw %xmm2,%xmm3");],,AC_MSG_RESULT([yes])
                      [HAVE_TOOLCHAIN_SUPPORT_MSSSE3=1],
@@ -1373,16 +1371,38 @@ if test "$GNU_CC"; then
       AC_MSG_RESULT("$result")
       if test "$result" = "yes"; then
           HAVE_X86_AVX2=1
           AC_DEFINE(HAVE_X86_AVX2)
           AC_SUBST(HAVE_X86_AVX2)
       fi
     esac
 
+    DSO_LDOPTS='-shared'
+    if test "$GCC_USE_GNU_LD"; then
+        # Some tools like ASan use a runtime library that is only
+        # linked against executables, so we must allow undefined
+        # symbols for shared objects in some cases.
+        if test -z "$MOZ_NO_WLZDEFS"; then
+            # Don't allow undefined symbols in libraries
+            DSO_LDOPTS="$DSO_LDOPTS -Wl,-z,defs"
+
+            # BSDs need `environ' exposed for posix_spawn (bug 753046)
+            case "$OS_TARGET" in
+            DragonFly|FreeBSD|NetBSD|OpenBSD)
+                if test -n "$HAVE_LINKER_SUPPORT_IGNORE_UNRESOLVED"; then
+                    DSO_LDOPTS="$DSO_LDOPTS -Wl,--ignore-unresolved-symbol,environ"
+                else
+                    DSO_LDOPTS="$DSO_LDOPTS -Wl,--warn-unresolved-symbols"
+                fi
+                ;;
+            esac
+        fi
+    fi
+
     # Turn on GNU-specific warnings:
     # -Wall - turn on a lot of warnings
     # -Wpointer-arith - good to have
     # -Wdeclaration-after-statement - MSVC doesn't like these
     # -Werror=return-type - catches missing returns, zero false positives
     # -Werror=int-to-pointer-cast - catches cast to pointer from integer of different size
     # -Wtype-limits - catches overflow bugs, few false positives
     # -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
@@ -6266,16 +6286,24 @@ dnl ====================================
 dnl = Disable DOMCrypto
 dnl ========================================================
 if test -n "$MOZ_DISABLE_CRYPTOLEGACY"; then
     AC_DEFINE(MOZ_DISABLE_CRYPTOLEGACY)
 fi
 AC_SUBST(MOZ_DISABLE_CRYPTOLEGACY)
 
 dnl ========================================================
+dnl = Disable EV certificate verification
+dnl ========================================================
+if test -n "$MOZ_NO_EV_CERTS"; then
+    AC_DEFINE(MOZ_NO_EV_CERTS)
+fi
+AC_SUBST(MOZ_NO_EV_CERTS)
+
+dnl ========================================================
 dnl = Disable libpkix
 dnl ========================================================
 if test -n "$NSS_NO_LIBPKIX"; then
     AC_DEFINE(NSS_NO_LIBPKIX)
 fi
 AC_SUBST(NSS_NO_LIBPKIX)
 
 dnl ========================================================
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -1638,30 +1638,41 @@ public:
   // mAnimationController isn't yet initialized.
   virtual nsSMILAnimationController* GetAnimationController() = 0;
 
   // Makes the images on this document capable of having their animation
   // active or suspended. An Image will animate as long as at least one of its
   // owning Documents needs it to animate; otherwise it can suspend.
   virtual void SetImagesNeedAnimating(bool aAnimating) = 0;
 
+  enum SuppressionType {
+    eAnimationsOnly = 0x1,
+
+    // Note that suppressing events also suppresses animation frames, so
+    // there's no need to split out events in its own bitmask.
+    eEvents = 0x3,
+  };
+
   /**
    * Prevents user initiated events from being dispatched to the document and
    * subdocuments.
    */
-  virtual void SuppressEventHandling(uint32_t aIncrease = 1) = 0;
+  virtual void SuppressEventHandling(SuppressionType aWhat,
+                                     uint32_t aIncrease = 1) = 0;
 
   /**
    * Unsuppress event handling.
    * @param aFireEvents If true, delayed events (focus/blur) will be fired
    *                    asynchronously.
    */
-  virtual void UnsuppressEventHandlingAndFireEvents(bool aFireEvents) = 0;
+  virtual void UnsuppressEventHandlingAndFireEvents(SuppressionType aWhat,
+                                                    bool aFireEvents) = 0;
 
   uint32_t EventHandlingSuppressed() const { return mEventsSuppressed; }
+  uint32_t AnimationsPaused() const { return mAnimationsPaused; }
 
   bool IsEventHandlingEnabled() {
     return !EventHandlingSuppressed() && mScriptGlobalObject;
   }
 
   /**
    * Increment the number of external scripts being evaluated.
    */
@@ -2482,16 +2493,18 @@ protected:
 
   // If we're an external resource document, this will be non-null and will
   // point to our "display document": the one that all resource lookups should
   // go to.
   nsCOMPtr<nsIDocument> mDisplayDocument;
 
   uint32_t mEventsSuppressed;
 
+  uint32_t mAnimationsPaused;
+
   /**
    * The number number of external scripts (ones with the src attribute) that
    * have this document as their owner and that are being evaluated right now.
    */
   uint32_t mExternalScriptsBeingEvaluated;
 
   /**
    * The current frame request callback handle
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -9140,32 +9140,51 @@ nsIDocument::GetReadyState(nsAString& aR
   case READYSTATE_COMPLETE :
     aReadyState.Assign(NS_LITERAL_STRING("complete"));
     break;
   default:
     aReadyState.Assign(NS_LITERAL_STRING("uninitialized"));
   }
 }
 
+namespace {
+
+struct SuppressArgs
+{
+  nsIDocument::SuppressionType mWhat;
+  uint32_t mIncrease;
+};
+
+}
+
 static bool
 SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
 {
-  aDocument->SuppressEventHandling(*static_cast<uint32_t*>(aData));
+  SuppressArgs* args = static_cast<SuppressArgs*>(aData);
+  aDocument->SuppressEventHandling(args->mWhat, args->mIncrease);
   return true;
 }
 
 void
-nsDocument::SuppressEventHandling(uint32_t aIncrease)
-{
-  if (mEventsSuppressed == 0 && aIncrease != 0 && mPresShell &&
-      mScriptGlobalObject) {
+nsDocument::SuppressEventHandling(nsIDocument::SuppressionType aWhat,
+                                  uint32_t aIncrease)
+{
+  if (mEventsSuppressed == 0 && mAnimationsPaused == 0 &&
+      aIncrease != 0 && mPresShell && mScriptGlobalObject) {
     RevokeAnimationFrameNotifications();
   }
-  mEventsSuppressed += aIncrease;
-  EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
+
+  if (aWhat == eAnimationsOnly) {
+    mAnimationsPaused += aIncrease;
+  } else {
+    mEventsSuppressed += aIncrease;
+  }
+
+  SuppressArgs args = { aWhat, aIncrease };
+  EnumerateSubDocuments(SuppressEventHandlingInDocument, &args);
 }
 
 static void
 FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
                          bool aFireEvents)
 {
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (!fm)
@@ -9309,40 +9328,69 @@ public:
     FireOrClearDelayedEvents(mDocuments, true);
     return NS_OK;
   }
 
 private:
   nsTArray<nsCOMPtr<nsIDocument> > mDocuments;
 };
 
+namespace {
+
+struct UnsuppressArgs
+{
+  UnsuppressArgs(nsIDocument::SuppressionType aWhat)
+    : mWhat(aWhat)
+  {
+  }
+
+  nsIDocument::SuppressionType mWhat;
+  nsTArray<nsCOMPtr<nsIDocument>> mDocs;
+};
+
+}
+
 static bool
-GetAndUnsuppressSubDocuments(nsIDocument* aDocument, void* aData)
-{
-  uint32_t suppression = aDocument->EventHandlingSuppressed();
-  if (suppression > 0) {
+GetAndUnsuppressSubDocuments(nsIDocument* aDocument,
+                             void* aData)
+{
+  UnsuppressArgs* args = static_cast<UnsuppressArgs*>(aData);
+  if (args->mWhat != nsIDocument::eAnimationsOnly &&
+      aDocument->EventHandlingSuppressed() > 0) {
     static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression();
-  }
-  nsTArray<nsCOMPtr<nsIDocument> >* docs =
-    static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
-  docs->AppendElement(aDocument);
-  aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, docs);
+  } else if (args->mWhat == nsIDocument::eAnimationsOnly &&
+             aDocument->AnimationsPaused()) {
+    static_cast<nsDocument*>(aDocument)->ResumeAnimations();
+  }
+
+  if (args->mWhat != nsIDocument::eAnimationsOnly) {
+    // No need to remember documents if we only care about animation frames.
+    args->mDocs.AppendElement(aDocument);
+  }
+
+  aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, aData);
   return true;
 }
 
 void
-nsDocument::UnsuppressEventHandlingAndFireEvents(bool aFireEvents)
-{
-  nsTArray<nsCOMPtr<nsIDocument> > documents;
-  GetAndUnsuppressSubDocuments(this, &documents);
+nsDocument::UnsuppressEventHandlingAndFireEvents(nsIDocument::SuppressionType aWhat,
+                                                 bool aFireEvents)
+{
+  UnsuppressArgs args(aWhat);
+  GetAndUnsuppressSubDocuments(this, &args);
+
+  if (aWhat == nsIDocument::eAnimationsOnly) {
+    // No need to fire events if we only care about animations here.
+    return;
+  }
 
   if (aFireEvents) {
-    NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(documents));
+    NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(args.mDocs));
   } else {
-    FireOrClearDelayedEvents(documents, false);
+    FireOrClearDelayedEvents(args.mDocs, false);
   }
 }
 
 nsISupports*
 nsDocument::GetCurrentContentSink()
 {
   return mParser ? mParser->GetContentSink() : nullptr;
 }
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -975,25 +975,34 @@ public:
   nsTArray<nsCString> mHostObjectURIs;
 
   // Returns our (lazily-initialized) animation controller.
   // If HasAnimationController is true, this is guaranteed to return non-null.
   nsSMILAnimationController* GetAnimationController() MOZ_OVERRIDE;
 
   void SetImagesNeedAnimating(bool aAnimating) MOZ_OVERRIDE;
 
-  virtual void SuppressEventHandling(uint32_t aIncrease) MOZ_OVERRIDE;
+  virtual void SuppressEventHandling(SuppressionType aWhat,
+                                     uint32_t aIncrease) MOZ_OVERRIDE;
+
+  virtual void UnsuppressEventHandlingAndFireEvents(SuppressionType aWhat,
+                                                    bool aFireEvents) MOZ_OVERRIDE;
 
-  virtual void UnsuppressEventHandlingAndFireEvents(bool aFireEvents) MOZ_OVERRIDE;
-  
   void DecreaseEventSuppression() {
+    MOZ_ASSERT(mEventsSuppressed);
     --mEventsSuppressed;
     MaybeRescheduleAnimationFrameNotifications();
   }
 
+  void ResumeAnimations() {
+    MOZ_ASSERT(mAnimationsPaused);
+    --mAnimationsPaused;
+    MaybeRescheduleAnimationFrameNotifications();
+  }
+
   virtual nsIDocument* GetTemplateContentsOwner() MOZ_OVERRIDE;
 
   NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsDocument,
                                                                    nsIDocument)
 
   void DoNotifyPossibleTitleChange();
 
   nsExternalResourceMap& ExternalResourceMap()
--- a/content/base/src/nsTextFragment.h
+++ b/content/base/src/nsTextFragment.h
@@ -11,17 +11,17 @@
 #ifndef nsTextFragment_h___
 #define nsTextFragment_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "nsString.h"
 #include "nsReadableUtils.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 class nsString;
 class nsCString;
 
 // XXX should this normalize the code to keep a \u0000 at the end?
 
 // XXX nsTextFragmentPool?
 
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2867,17 +2867,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
     if (GetOwner()) {
       nsCOMPtr<nsIDOMWindow> topWindow;
       if (NS_SUCCEEDED(GetOwner()->GetTop(getter_AddRefs(topWindow)))) {
         nsCOMPtr<nsPIDOMWindow> suspendedWindow(do_QueryInterface(topWindow));
         if (suspendedWindow &&
             (suspendedWindow = suspendedWindow->GetCurrentInnerWindow())) {
           suspendedDoc = suspendedWindow->GetExtantDoc();
           if (suspendedDoc) {
-            suspendedDoc->SuppressEventHandling();
+            suspendedDoc->SuppressEventHandling(nsIDocument::eEvents);
           }
           suspendedWindow->SuspendTimeouts(1, false);
           resumeTimeoutRunnable = new nsResumeTimeoutsEvent(suspendedWindow);
         }
       }
     }
 
     ChangeState(XML_HTTP_REQUEST_SENT);
@@ -2891,17 +2891,18 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
         if (!NS_ProcessNextEvent(thread)) {
           rv = NS_ERROR_UNEXPECTED;
           break;
         }
       }
     }
 
     if (suspendedDoc) {
-      suspendedDoc->UnsuppressEventHandlingAndFireEvents(true);
+      suspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
+                                                         true);
     }
 
     if (resumeTimeoutRunnable) {
       NS_DispatchToCurrentThread(resumeTimeoutRunnable);
     }
   } else {
     // Now that we've successfully opened the channel, we can change state.  Note
     // that this needs to come after the AsyncOpen() and rv check, because this
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -10,17 +10,17 @@
 #include "nsIDOMCanvasRenderingContext2D.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TypedArray.h"
 #include <stdint.h>
 
 #include "nsCycleCollectionParticipant.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "js/GCAPI.h"
 
 namespace mozilla {
 namespace dom {
 
 class ImageData MOZ_FINAL : public nsISupports
 {
 public:
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3337,16 +3337,22 @@ WebGLContext::CompressedTexImage2D(GLenu
         return;
     }
 
     uint32_t byteLength = view.Length();
     if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) {
         return;
     }
 
+    if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0,
+                                  width, height, width, height, func))
+    {
+        return;
+    }
+
     MakeContextCurrent();
     gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
     WebGLTexture* tex = activeBoundTextureForTarget(target);
     MOZ_ASSERT(tex);
     tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
                       WebGLImageDataStatus::InitializedImageData);
 
     ReattachTextureToAnyFramebufferToWorkAroundBugs(tex, level);
@@ -3371,29 +3377,29 @@ WebGLContext::CompressedTexSubImage2D(GL
     {
         return;
     }
 
     WebGLTexture *tex = activeBoundTextureForTarget(target);
     MOZ_ASSERT(tex);
     WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
 
+    uint32_t byteLength = view.Length();
+    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
+        return;
+
     if (!ValidateCompTexImageSize(target, level, format,
                                   xoffset, yoffset,
                                   width, height,
                                   levelInfo.Width(), levelInfo.Height(),
                                   func))
     {
         return;
     }
 
-    uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
-        return;
-
     if (levelInfo.HasUninitializedImageData())
         tex->DoDeferredImageInitialization(target, level);
 
     MakeContextCurrent();
     gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
 }
 
 JS::Value
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -771,36 +771,64 @@ WebGLContext::ValidateCompTexImageSize(G
         if (yoffset % blockHeight != 0) {
             ErrorInvalidOperation("%s: yoffset must be multiple of %d",
                                   InfoFrom(func), blockHeight);
             return false;
         }
 
         /* The size must be a multiple of blockWidth and blockHeight,
          * or must be using offset+size that exactly hits the edge.
-         * Important for small mipmap levels. (s3tc extension appears
-         * to have changed and old code that checks 1x1, 2x2 doesn't
-         * appear necessary anymore)
+         * Important for small mipmap levels.
+         */
+        /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
+         * "When level equals zero width and height must be a multiple of 4. When
+         *  level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
+         *  If they are not an INVALID_OPERATION error is generated."
          */
-        if ((width % blockWidth != 0) &&
-            (xoffset + width != (GLint) levelWidth))
-        {
-            ErrorInvalidOperation("%s: width must be multiple of %d or "
-                                  "xoffset + width must be %d",
-                                  InfoFrom(func), blockWidth, levelWidth);
-            return false;
+        if (level == 0) {
+            if (width % blockWidth != 0) {
+                ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
+                                      InfoFrom(func), blockWidth);
+                return false;
+            }
+
+            if (height % blockHeight != 0) {
+                ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
+                                      InfoFrom(func), blockHeight);
+                return false;
+            }
+        }
+        else if (level > 0) {
+            if (width % blockWidth != 0 && width > 2) {
+                ErrorInvalidOperation("%s: width of level %d must be multiple"
+                                      " of %d or 0, 1, 2",
+                                      InfoFrom(func), level, blockWidth);
+                return false;
+            }
+
+            if (height % blockHeight != 0 && height > 2) {
+                ErrorInvalidOperation("%s: height of level %d must be multiple"
+                                      " of %d or 0, 1, 2",
+                                      InfoFrom(func), level, blockHeight);
+                return false;
+            }
         }
 
-        if ((height % blockHeight != 0) &&
-            (yoffset + height != (GLint) levelHeight))
-        {
-            ErrorInvalidOperation("%s: height must be multiple of %d or "
-                                  "yoffset + height must be %d",
-                                  InfoFrom(func), blockHeight, levelHeight);
-            return false;
+        if (IsSubFunc(func)) {
+            if ((xoffset % blockWidth) != 0) {
+                ErrorInvalidOperation("%s: xoffset must be multiple of %d",
+                                      InfoFrom(func), blockWidth);
+                return false;
+            }
+
+            if (yoffset % blockHeight != 0) {
+                ErrorInvalidOperation("%s: yoffset must be multiple of %d",
+                                      InfoFrom(func), blockHeight);
+                return false;
+            }
         }
     }
 
     switch (format) {
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
@@ -1148,20 +1176,36 @@ WebGLContext::ValidateTexImageFormatAndT
         validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
                       type == LOCAL_GL_UNSIGNED_INT);
         break;
 
     case LOCAL_GL_DEPTH_STENCIL:
         validCombo = (type == LOCAL_GL_UNSIGNED_INT_24_8);
         break;
 
+    case LOCAL_GL_ATC_RGB:
+    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
+    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
+    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
+    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
+    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        validCombo = (type == LOCAL_GL_UNSIGNED_BYTE);
+        break;
+
     default:
         // Only valid formats should be passed to the switch stmt.
-        MOZ_ASSERT("Invalid format");
-        return false;
+        MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
+        validCombo = false;
+        // Fall through to return an InvalidOperations. This will alert us to the
+        // unexpected case that needs fixing in builds without asserts.
     }
 
     if (!validCombo)
         ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
                               InfoFrom(func), NameFrom(format), NameFrom(type));
 
     return validCombo;
 }
--- a/content/media/AudioNodeStream.cpp
+++ b/content/media/AudioNodeStream.cpp
@@ -510,32 +510,42 @@ AudioNodeStream::FinishOutput()
     AudioSegment emptySegment;
     l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
                                 mSampleRate,
                                 track->GetSegment()->GetDuration(),
                                 MediaStreamListener::TRACK_EVENT_ENDED, emptySegment);
   }
 }
 
-TrackTicks
-AudioNodeStream::TicksFromDestinationTime(MediaStream* aDestination,
-                                          double aSeconds)
+double
+AudioNodeStream::TimeFromDestinationTime(AudioNodeStream* aDestination,
+                                         double aSeconds)
 {
-  MOZ_ASSERT(aDestination->AsAudioNodeStream() &&
-             aDestination->AsAudioNodeStream()->SampleRate() == SampleRate());
+  MOZ_ASSERT(aDestination->SampleRate() == SampleRate());
 
   double destinationSeconds = std::max(0.0, aSeconds);
   StreamTime streamTime = SecondsToMediaTime(destinationSeconds);
   // MediaTime does not have the resolution of double
   double offset = destinationSeconds - MediaTimeToSeconds(streamTime);
 
   GraphTime graphTime = aDestination->StreamTimeToGraphTime(streamTime);
   StreamTime thisStreamTime = GraphTimeToStreamTimeOptimistic(graphTime);
   double thisSeconds = MediaTimeToSeconds(thisStreamTime) + offset;
   MOZ_ASSERT(thisSeconds >= 0.0);
+  return thisSeconds;
+}
+
+TrackTicks
+AudioNodeStream::TicksFromDestinationTime(MediaStream* aDestination,
+                                          double aSeconds)
+{
+  AudioNodeStream* destination = aDestination->AsAudioNodeStream();
+  MOZ_ASSERT(destination);
+
+  double thisSeconds = TimeFromDestinationTime(destination, aSeconds);
   // Round to nearest
   TrackTicks ticks = thisSeconds * SampleRate() + 0.5;
   return ticks;
 }
 
 double
 AudioNodeStream::DestinationTimeFromTicks(AudioNodeStream* aDestination,
                                           TrackTicks aPosition)
--- a/content/media/AudioNodeStream.h
+++ b/content/media/AudioNodeStream.h
@@ -124,16 +124,22 @@ public:
     return true;
   }
 
   // Any thread
   AudioNodeEngine* Engine() { return mEngine; }
   TrackRate SampleRate() const { return mSampleRate; }
 
   /**
+   * Convert a time in seconds on the destination stream to seconds
+   * on this stream.
+   */
+  double TimeFromDestinationTime(AudioNodeStream* aDestination,
+                                 double aSeconds);
+  /**
    * Convert a time in seconds on the destination stream to TrackTicks
    * on this stream.
    */
   TrackTicks TicksFromDestinationTime(MediaStream* aDestination,
                                       double aSeconds);
   /**
    * Get the destination stream time in seconds corresponding to a position on
    * this stream.
--- a/content/media/mediasource/SourceBufferResource.cpp
+++ b/content/media/mediasource/SourceBufferResource.cpp
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceBufferResource.h"
 
 #include <string.h>
 #include <algorithm>
 
 #include "nsISeekableStream.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "prenv.h"
 #include "prlog.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaSourceLog;
 #define LOG(type, msg) PR_LOG(gMediaSourceLog, type, msg)
 #else
 #define LOG(type, msg)
--- a/content/media/ogg/OggCodecState.cpp
+++ b/content/media/ogg/OggCodecState.cpp
@@ -9,17 +9,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Endian.h"
 #include <stdint.h>
 
 #include "nsDebug.h"
 #include "MediaDecoderReader.h"
 #include "OggCodecState.h"
 #include "OggDecoder.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "VideoUtils.h"
 #include <algorithm>
 
 // On Android JellyBean, the hardware.h header redefines version_major and
 // version_minor, which breaks our build.  See:
 // https://bugzilla.mozilla.org/show_bug.cgi?id=912702#c6
 #ifdef MOZ_WIDGET_GONK
 #ifdef version_major
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -51,21 +51,22 @@ NS_IMPL_RELEASE_INHERITED(AudioBufferSou
  * AudioNodeStream::SetInt32Parameter).
  */
 class AudioBufferSourceNodeEngine : public AudioNodeEngine
 {
 public:
   explicit AudioBufferSourceNodeEngine(AudioNode* aNode,
                                        AudioDestinationNode* aDestination) :
     AudioNodeEngine(aNode),
-    mStart(0), mStop(TRACK_TICKS_MAX),
+    mStart(0.0), mBeginProcessing(0),
+    mStop(TRACK_TICKS_MAX),
     mResampler(nullptr), mRemainingResamplerTail(0),
     mBufferEnd(0),
     mLoopStart(0), mLoopEnd(0),
-    mBufferSampleRate(0), mBufferPosition(0), mChannels(0), mPlaybackRate(1.0f),
+    mBufferSampleRate(0), mBufferPosition(0), mChannels(0),
     mDopplerShift(1.0f),
     mDestination(static_cast<AudioNodeStream*>(aDestination->Stream())),
     mPlaybackRateTimeline(1.0f), mLoop(false)
   {}
 
   ~AudioBufferSourceNodeEngine()
   {
     if (mResampler) {
@@ -89,30 +90,36 @@ public:
       break;
     default:
       NS_ERROR("Bad AudioBufferSourceNodeEngine TimelineParameter");
     }
   }
   virtual void SetStreamTimeParameter(uint32_t aIndex, TrackTicks aParam)
   {
     switch (aIndex) {
-    case AudioBufferSourceNode::START: mStart = aParam; break;
     case AudioBufferSourceNode::STOP: mStop = aParam; break;
     default:
       NS_ERROR("Bad AudioBufferSourceNodeEngine StreamTimeParameter");
     }
   }
   virtual void SetDoubleParameter(uint32_t aIndex, double aParam)
   {
     switch (aIndex) {
-      case AudioBufferSourceNode::DOPPLERSHIFT:
-        mDopplerShift = aParam;
-        break;
-      default:
-        NS_ERROR("Bad AudioBufferSourceNodeEngine double parameter.");
+    case AudioBufferSourceNode::START:
+      MOZ_ASSERT(!mStart, "Another START?");
+      mStart = mSource->TimeFromDestinationTime(mDestination, aParam) *
+        mSource->SampleRate();
+      // Round to nearest
+      mBeginProcessing = mStart + 0.5;
+      break;
+    case AudioBufferSourceNode::DOPPLERSHIFT:
+      mDopplerShift = aParam > 0 && aParam == aParam ? aParam : 1.0;
+      break;
+    default:
+      NS_ERROR("Bad AudioBufferSourceNodeEngine double parameter.");
     };
   }
   virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam)
   {
     switch (aIndex) {
     case AudioBufferSourceNode::SAMPLE_RATE: mBufferSampleRate = aParam; break;
     case AudioBufferSourceNode::BUFFERSTART:
       if (mBufferPosition == 0) {
@@ -127,32 +134,70 @@ public:
       NS_ERROR("Bad AudioBufferSourceNodeEngine Int32Parameter");
     }
   }
   virtual void SetBuffer(already_AddRefed<ThreadSharedFloatArrayBufferList> aBuffer)
   {
     mBuffer = aBuffer;
   }
 
-  SpeexResamplerState* Resampler(AudioNodeStream* aStream, uint32_t aChannels)
+  bool BegunResampling()
+  {
+    return mBeginProcessing == -TRACK_TICKS_MAX;
+  }
+
+  void UpdateResampler(int32_t aOutRate, uint32_t aChannels)
   {
-    if (aChannels != mChannels && mResampler) {
+    if (mResampler &&
+        (aChannels != mChannels ||
+         // If the resampler has begun, then it will have moved
+         // mBufferPosition to after the samples it has read, but it hasn't
+         // output its buffered samples.  Keep using the resampler, even if
+         // the rates now match, so that this latent segment is output.
+         (aOutRate == mBufferSampleRate && !BegunResampling()))) {
       speex_resampler_destroy(mResampler);
       mResampler = nullptr;
+      mBeginProcessing = mStart + 0.5;
+    }
+
+    if (aOutRate == mBufferSampleRate && !mResampler) {
+      return;
     }
 
     if (!mResampler) {
       mChannels = aChannels;
-      mResampler = speex_resampler_init(mChannels, mBufferSampleRate,
-                                        ComputeFinalOutSampleRate(aStream->SampleRate()),
+      mResampler = speex_resampler_init(mChannels, mBufferSampleRate, aOutRate,
                                         SPEEX_RESAMPLER_QUALITY_DEFAULT,
                                         nullptr);
-      speex_resampler_skip_zeros(mResampler);
+    } else {
+      uint32_t currentOutSampleRate, currentInSampleRate;
+      speex_resampler_get_rate(mResampler, &currentInSampleRate,
+                               &currentOutSampleRate);
+      if (currentOutSampleRate == static_cast<uint32_t>(aOutRate)) {
+        return;
+      }
+      speex_resampler_set_rate(mResampler, currentInSampleRate, aOutRate);
     }
-    return mResampler;
+
+    if (!BegunResampling()) {
+      // Low pass filter effects from the resampler mean that samples before
+      // the start time are influenced by resampling the buffer.  The input
+      // latency indicates half the filter width.
+      int64_t inputLatency = speex_resampler_get_input_latency(mResampler);
+      uint32_t ratioNum, ratioDen;
+      speex_resampler_get_ratio(mResampler, &ratioNum, &ratioDen);
+      // The output subsample resolution supported in aligning the resampler
+      // is ratioNum.  First round the start time to the nearest subsample.
+      int64_t subsample = mStart * ratioNum + 0.5;
+      // Now include the leading effects of the filter, and round *up* to the
+      // next whole tick, because there is no effect on samples outside the
+      // filter width.
+      mBeginProcessing =
+        (subsample - inputLatency * ratioDen + ratioNum - 1) / ratioNum;
+    }
   }
 
   // Borrow a full buffer of size WEBAUDIO_BLOCK_SIZE from the source buffer
   // at offset aSourceOffset.  This avoids copying memory.
   void BorrowFromInputBuffer(AudioChunk* aOutput,
                              uint32_t aChannels)
   {
     aOutput->mDuration = WEBAUDIO_BLOCK_SIZE;
@@ -182,84 +227,101 @@ public:
   // Resamples input data to an output buffer, according to |mBufferSampleRate| and
   // the playbackRate.
   // The number of frames consumed/produced depends on the amount of space
   // remaining in both the input and output buffer, and the playback rate (that
   // is, the ratio between the output samplerate and the input samplerate).
   void CopyFromInputBufferWithResampling(AudioNodeStream* aStream,
                                          AudioChunk* aOutput,
                                          uint32_t aChannels,
-                                         uint32_t aOffsetWithinBlock,
-                                         uint32_t& aFramesWritten,
+                                         uint32_t* aOffsetWithinBlock,
+                                         TrackTicks* aCurrentPosition,
                                          int32_t aBufferMax) {
     // TODO: adjust for mStop (see bug 913854 comment 9).
-    uint32_t availableInOutputBuffer = WEBAUDIO_BLOCK_SIZE - aOffsetWithinBlock;
-    SpeexResamplerState* resampler = Resampler(aStream, aChannels);
+    uint32_t availableInOutputBuffer =
+      WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock;
+    SpeexResamplerState* resampler = mResampler;
     MOZ_ASSERT(aChannels > 0);
 
     if (mBufferPosition < aBufferMax) {
       uint32_t availableInInputBuffer = aBufferMax - mBufferPosition;
+      uint32_t ratioNum, ratioDen;
+      speex_resampler_get_ratio(resampler, &ratioNum, &ratioDen);
       // Limit the number of input samples copied and possibly
       // format-converted for resampling by estimating how many will be used.
-      // This may be a little small when filling the resampler with initial
-      // data, but we'll get called again and it will work out.
-      uint32_t num, den;
-      speex_resampler_get_ratio(resampler, &num, &den);
-      uint32_t inputLimit = std::min(availableInInputBuffer,
-                                     availableInOutputBuffer * num / den + 10);
+      // This may be a little small if still filling the resampler with
+      // initial data, but we'll get called again and it will work out.
+      uint32_t inputLimit = availableInOutputBuffer * ratioNum / ratioDen + 10;
+      if (!BegunResampling()) {
+        // First time the resampler is used.
+        uint32_t inputLatency = speex_resampler_get_input_latency(resampler);
+        inputLimit += inputLatency;
+        // If starting after mStart, then play from the beginning of the
+        // buffer, but correct for input latency.  If starting before mStart,
+        // then align the resampler so that the time corresponding to the
+        // first input sample is mStart.
+        uint32_t skipFracNum = inputLatency * ratioDen;
+        double leadTicks = mStart - *aCurrentPosition;
+        if (leadTicks > 0.0) {
+          // Round to nearest output subsample supported by the resampler at
+          // these rates.
+          skipFracNum -= leadTicks * ratioNum + 0.5;
+          MOZ_ASSERT(skipFracNum < INT32_MAX, "mBeginProcessing is wrong?");
+        }
+        speex_resampler_set_skip_frac_num(resampler, skipFracNum);
+
+        mBeginProcessing = -TRACK_TICKS_MAX;
+      }
+      inputLimit = std::min(inputLimit, availableInInputBuffer);
+
       for (uint32_t i = 0; true; ) {
         uint32_t inSamples = inputLimit;
         const float* inputData = mBuffer->GetData(i) + mBufferPosition;
 
         uint32_t outSamples = availableInOutputBuffer;
         float* outputData =
           static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
-          aOffsetWithinBlock;
+          *aOffsetWithinBlock;
 
         WebAudioUtils::SpeexResamplerProcess(resampler, i,
                                              inputData, &inSamples,
                                              outputData, &outSamples);
         if (++i == aChannels) {
           mBufferPosition += inSamples;
           MOZ_ASSERT(mBufferPosition <= mBufferEnd || mLoop);
-          aFramesWritten = outSamples;
+          *aOffsetWithinBlock += outSamples;
+          *aCurrentPosition += outSamples;
           if (inSamples == availableInInputBuffer && !mLoop) {
-            // If the available output space were unbounded then the input
-            // latency would always be the correct amount of extra input to
-            // provide in order to advance the output position to align with
-            // the final point in the buffer.  However, when the output space
-            // becomes full, the resampler may read all available input
-            // without writing out the corresponding output.  Add one more
-            // input sample, so that we know that enough output has been
-            // written when the last input sample has been read.  This may
-            // often write more than necessary but the extra samples will be
-            // based on (mostly) zero input.
+            // We'll feed in enough zeros to empty out the resampler's memory.
+            // This handles the output latency as well as capturing the low
+            // pass effects of the resample filter.
             mRemainingResamplerTail =
-              speex_resampler_get_input_latency(resampler) + 1;
+              2 * speex_resampler_get_input_latency(resampler) - 1;
           }
           return;
         }
       }
     } else {
       for (uint32_t i = 0; true; ) {
         uint32_t inSamples = mRemainingResamplerTail;
         uint32_t outSamples = availableInOutputBuffer;
         float* outputData =
           static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])) +
-          aOffsetWithinBlock;
+          *aOffsetWithinBlock;
 
         // AudioDataValue* for aIn selects the function that does not try to
         // copy and format-convert input data.
         WebAudioUtils::SpeexResamplerProcess(resampler, i,
                          static_cast<AudioDataValue*>(nullptr), &inSamples,
                          outputData, &outSamples);
         if (++i == aChannels) {
           mRemainingResamplerTail -= inSamples;
           MOZ_ASSERT(mRemainingResamplerTail >= 0);
-          aFramesWritten = outSamples;
+          *aOffsetWithinBlock += outSamples;
+          *aCurrentPosition += outSamples;
           break;
         }
       }
     }
   }
 
   /**
    * Fill aOutput with as many zero frames as we can, and advance
@@ -307,88 +369,63 @@ public:
                       TrackTicks* aCurrentPosition,
                       int32_t aBufferMax)
   {
     MOZ_ASSERT(*aCurrentPosition < mStop);
     uint32_t numFrames =
       std::min(std::min<TrackTicks>(WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock,
                                     aBufferMax - mBufferPosition),
                mStop - *aCurrentPosition);
-    if (numFrames == WEBAUDIO_BLOCK_SIZE && !ShouldResample(aStream->SampleRate())) {
+    if (numFrames == WEBAUDIO_BLOCK_SIZE && !mResampler) {
       MOZ_ASSERT(mBufferPosition < aBufferMax);
       BorrowFromInputBuffer(aOutput, aChannels);
       *aOffsetWithinBlock += numFrames;
       *aCurrentPosition += numFrames;
       mBufferPosition += numFrames;
     } else {
       if (*aOffsetWithinBlock == 0) {
         AllocateAudioBlock(aChannels, aOutput);
       }
-      if (!ShouldResample(aStream->SampleRate())) {
+      if (!mResampler) {
         MOZ_ASSERT(mBufferPosition < aBufferMax);
         CopyFromInputBuffer(aOutput, aChannels, *aOffsetWithinBlock, numFrames);
         *aOffsetWithinBlock += numFrames;
         *aCurrentPosition += numFrames;
         mBufferPosition += numFrames;
       } else {
-        uint32_t framesWritten;
-        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, *aOffsetWithinBlock, framesWritten, aBufferMax);
-        *aOffsetWithinBlock += framesWritten;
-        *aCurrentPosition += framesWritten;
+        CopyFromInputBufferWithResampling(aStream, aOutput, aChannels, aOffsetWithinBlock, aCurrentPosition, aBufferMax);
       }
     }
   }
 
-  uint32_t ComputeFinalOutSampleRate(TrackRate aStreamSampleRate)
+  int32_t ComputeFinalOutSampleRate(float aPlaybackRate)
   {
-    if (mPlaybackRate <= 0 || mPlaybackRate != mPlaybackRate) {
-      mPlaybackRate = 1.0f;
-    }
-    if (mDopplerShift <= 0 || mDopplerShift != mDopplerShift) {
-      mDopplerShift = 1.0f;
-    }
-    return WebAudioUtils::TruncateFloatToInt<uint32_t>(aStreamSampleRate /
-                                                       (mPlaybackRate * mDopplerShift));
-  }
-
-  bool ShouldResample(TrackRate aStreamSampleRate) const
-  {
-    // There is latency in the resampler.  If there is already a resampler,
-    // then it will have moved mBufferPosition to after the samples it has
-    // read, but it hasn't output its buffered samples.  Keep using the
-    // resampler, even if the rates now match, so that this latent segment is
-    // output.
-    return mResampler ||
-      (mPlaybackRate * mDopplerShift * mBufferSampleRate != aStreamSampleRate);
+    // Make sure the playback rate and the doppler shift are something
+    // our resampler can work with.
+    int32_t rate = WebAudioUtils::
+      TruncateFloatToInt<int32_t>(mSource->SampleRate() /
+                                  (aPlaybackRate * mDopplerShift));
+    return rate ? rate : mBufferSampleRate;
   }
 
-  void UpdateSampleRateIfNeeded(AudioNodeStream* aStream, uint32_t aChannels)
+  void UpdateSampleRateIfNeeded(uint32_t aChannels)
   {
+    float playbackRate;
+
     if (mPlaybackRateTimeline.HasSimpleValue()) {
-      mPlaybackRate = mPlaybackRateTimeline.GetValue();
+      playbackRate = mPlaybackRateTimeline.GetValue();
     } else {
-      mPlaybackRate = mPlaybackRateTimeline.GetValueAtTime(aStream->GetCurrentPosition());
+      playbackRate = mPlaybackRateTimeline.GetValueAtTime(mSource->GetCurrentPosition());
+    }
+    if (playbackRate <= 0 || playbackRate != playbackRate) {
+      playbackRate = 1.0f;
     }
 
-    // Make sure the playback rate and the doppler shift are something
-    // our resampler can work with.
-    if (ComputeFinalOutSampleRate(aStream->SampleRate()) == 0) {
-      mPlaybackRate = 1.0;
-      mDopplerShift = 1.0;
-    }
-
-    if (mResampler) {
-      SpeexResamplerState* resampler = Resampler(aStream, aChannels);
-      uint32_t currentOutSampleRate, currentInSampleRate;
-      speex_resampler_get_rate(resampler, &currentInSampleRate, &currentOutSampleRate);
-      uint32_t finalSampleRate = ComputeFinalOutSampleRate(aStream->SampleRate());
-      if (currentOutSampleRate != finalSampleRate) {
-        speex_resampler_set_rate(resampler, currentInSampleRate, finalSampleRate);
-      }
-    }
+    int32_t outRate = ComputeFinalOutSampleRate(playbackRate);
+    UpdateResampler(outRate, aChannels);
   }
 
   virtual void ProduceAudioBlock(AudioNodeStream* aStream,
                                  const AudioChunk& aInput,
                                  AudioChunk* aOutput,
                                  bool* aFinished)
   {
     if (!mBuffer || !mBufferEnd) {
@@ -400,28 +437,29 @@ public:
     if (!channels) {
       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
       return;
     }
 
     // WebKit treats the playbackRate as a k-rate parameter in their code,
     // despite the spec saying that it should be an a-rate parameter. We treat
     // it as k-rate. Spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=21592
-    UpdateSampleRateIfNeeded(aStream, channels);
+    UpdateSampleRateIfNeeded(channels);
 
     uint32_t written = 0;
     TrackTicks streamPosition = aStream->GetCurrentPosition();
     while (written < WEBAUDIO_BLOCK_SIZE) {
       if (mStop != TRACK_TICKS_MAX &&
           streamPosition >= mStop) {
         FillWithZeroes(aOutput, channels, &written, &streamPosition, TRACK_TICKS_MAX);
         continue;
       }
-      if (streamPosition < mStart) {
-        FillWithZeroes(aOutput, channels, &written, &streamPosition, mStart);
+      if (streamPosition < mBeginProcessing) {
+        FillWithZeroes(aOutput, channels, &written, &streamPosition,
+                       mBeginProcessing);
         continue;
       }
       if (mLoop) {
         // mLoopEnd can become less than mBufferPosition when a LOOPEND engine
         // parameter is received after "loopend" is changed on the node or a
         // new buffer with lower samplerate is set.
         if (mBufferPosition >= mLoopEnd) {
           mBufferPosition = mLoopStart;
@@ -439,30 +477,34 @@ public:
     // We've finished if we've gone past mStop, or if we're past mDuration when
     // looping is disabled.
     if (streamPosition >= mStop ||
         (!mLoop && mBufferPosition >= mBufferEnd && !mRemainingResamplerTail)) {
       *aFinished = true;
     }
   }
 
-  TrackTicks mStart;
+  double mStart; // including the fractional position between ticks
+  // Low pass filter effects from the resampler mean that samples before the
+  // start time are influenced by resampling the buffer.  mBeginProcessing
+  // includes the extent of this filter.  The special value of -TRACK_TICKS_MAX
+  // indicates that the resampler has begun processing.
+  TrackTicks mBeginProcessing;
   TrackTicks mStop;
   nsRefPtr<ThreadSharedFloatArrayBufferList> mBuffer;
   SpeexResamplerState* mResampler;
   // mRemainingResamplerTail, like mBufferPosition, and
   // mBufferEnd, is measured in input buffer samples.
   int mRemainingResamplerTail;
   int32_t mBufferEnd;
   int32_t mLoopStart;
   int32_t mLoopEnd;
   int32_t mBufferSampleRate;
   int32_t mBufferPosition;
   uint32_t mChannels;
-  float mPlaybackRate;
   float mDopplerShift;
   AudioNodeStream* mDestination;
   AudioNodeStream* mSource;
   AudioParamTimeline mPlaybackRateTimeline;
   bool mLoop;
 };
 
 AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
@@ -527,17 +569,17 @@ AudioBufferSourceNode::Start(double aWhe
   // We can't send these parameters without a buffer because we don't know the
   // buffer's sample rate or length.
   if (mBuffer) {
     SendOffsetAndDurationParametersToStream(ns);
   }
 
   // Don't set parameter unnecessarily
   if (aWhen > 0.0) {
-    ns->SetStreamTimeParameter(START, Context(), aWhen);
+    ns->SetDoubleParameter(START, mContext->DOMTimeToStreamTime(aWhen));
   }
 }
 
 void
 AudioBufferSourceNode::SendBufferParameterToStream(JSContext* aCx)
 {
   AudioNodeStream* ns = static_cast<AudioNodeStream*>(mStream.get());
   MOZ_ASSERT(ns, "Why don't we have a stream here?");
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -58,18 +58,20 @@ support-files =
 [test_bug866737.html]
 [test_bug867089.html]
 [test_bug867104.html]
 [test_bug867174.html]
 [test_bug867203.html]
 [test_bug875221.html]
 [test_bug875402.html]
 [test_bug894150.html]
+[test_bug938022.html]
 [test_bug956489.html]
 [test_bug964376.html]
+[test_bug972678.html]
 [test_channelMergerNode.html]
 [test_channelMergerNodeWithVolume.html]
 [test_channelSplitterNode.html]
 [test_channelSplitterNodeWithVolume.html]
 [test_convolverNode.html]
 [test_convolverNodeChannelCount.html]
 [test_convolverNodeWithGain.html]
 [test_convolverNode_mono_mono.html]
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_bug938022.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test audio element currentTime is correct when used as media source</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  var context = new AudioContext();
+  var audio = new Audio("small-shot.ogg");
+  audio.load();
+  audio.addEventListener("loadeddata", function (e) {
+    is(this.currentTime, 0, "currentTime must be 0");
+    SimpleTest.finish();
+  });
+  audio.play();
+
+  var source = context.createMediaElementSource(audio);
+  source.connect(context.destination);
+});
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_bug972678.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test buffers do not interfere when scheduled in sequence</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="webaudio.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var OFFSETS = [0.005, 0.01, 0.02, 0.03];
+var LENGTH = 128;
+
+var gTest = {
+  length: 128 * OFFSETS.length,
+  numberOfChannels: 1,
+
+  createGraph: function(context) {
+    var gain = context.createGain();
+
+    // create a repeating sample
+    var repeatingSample = context.createBuffer(1, 2, context.sampleRate);
+    var c = repeatingSample.getChannelData(0);
+    for (var i = 0; i < repeatingSample.length; ++i) {
+      c[i] = i % 2 == 0 ? 1 : -1;
+    }
+
+    OFFSETS.forEach(function (offset, offsetIdx) {
+      // Schedule a set of nodes to repeat the sample.
+      for (var i = 0; i < LENGTH; i += repeatingSample.length) {
+        var source = context.createBufferSource();
+        source.buffer = repeatingSample;
+        source.connect(gain);
+        source.start((offsetIdx * LENGTH + i + offset) / context.sampleRate);
+      }
+
+      buffer = context.createBuffer(1, LENGTH, context.sampleRate);
+      c = buffer.getChannelData(0);
+      for (var i = 0; i < buffer.length; ++i) {
+        c[i] = i % 2 == 0 ? -1 : 1;
+      }
+
+      var source = context.createBufferSource();
+      source.buffer = buffer;
+      source.connect(gain);
+      source.start((offsetIdx * LENGTH + offset) / context.sampleRate);
+    });
+
+    return gain;
+  },
+
+  createExpectedBuffers: function(context) {
+    return context.createBuffer(1, gTest.length, context.sampleRate);
+  },
+};
+
+runTest();
+</script>
+</pre>
+</body>
+</html>
--- a/content/svg/content/test/mochitest.ini
+++ b/content/svg/content/test/mochitest.ini
@@ -52,16 +52,17 @@ skip-if = true
 [test_pathAnimInterpolation.xhtml]
 [test_pathSeg.xhtml]
 [test_pointAtLength.xhtml]
 [test_pointer-events-1a.xhtml]
 [test_pointer-events-1b.xhtml]
 [test_pointer-events-2.xhtml]
 [test_pointer-events-3.xhtml]
 [test_pointer-events-4.xhtml]
+[test_pointer-events-5.xhtml]
 [test_scientific.html]
 [test_selectSubString.xhtml]
 [test_stroke-linecap-hit-testing.xhtml]
 [test_SVGLengthList-2.xhtml]
 [test_SVGLengthList.xhtml]
 [test_SVGMatrix.xhtml]
 [test_SVG_namespace_ids.html]
 [test_SVGNumberList.xhtml]
copy from content/svg/content/test/test_pointer-events-2.xhtml
copy to content/svg/content/test/test_pointer-events-5.xhtml
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -7974,18 +7974,26 @@ nsDocShell::RestoreFromHistory()
     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
     uint32_t parentSuspendCount = 0;
     if (document) {
         nsCOMPtr<nsIDocShellTreeItem> parent;
         GetParent(getter_AddRefs(parent));
         nsCOMPtr<nsIDocument> d = do_GetInterface(parent);
         if (d) {
             if (d->EventHandlingSuppressed()) {
-                document->SuppressEventHandling(d->EventHandlingSuppressed());
-            }
+                document->SuppressEventHandling(nsIDocument::eEvents,
+                                                d->EventHandlingSuppressed());
+            }
+
+            // Ick, it'd be nicer to not rewalk all of the subdocs here.
+            if (d->AnimationsPaused()) {
+                document->SuppressEventHandling(nsIDocument::eAnimationsOnly,
+                                                d->AnimationsPaused());
+            }
+
             nsCOMPtr<nsPIDOMWindow> parentWindow = d->GetWindow();
             if (parentWindow) {
                 parentSuspendCount = parentWindow->TimeoutSuspendCount();
             }
         }
 
         // Use the uri from the mLSHE we had when we entered this function
         // (which need not match the document's URI if anchors are involved),
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1678,19 +1678,19 @@ nsDOMWindowUtils::SuppressEventHandling(
 
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
 
   nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
   NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
 
   if (aSuppress) {
-    doc->SuppressEventHandling();
+    doc->SuppressEventHandling(nsIDocument::eEvents);
   } else {
-    doc->UnsuppressEventHandlingAndFireEvents(true);
+    doc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, true);
   }
 
   return NS_OK;
 }
 
 static nsresult
 getScrollXYAppUnits(nsWeakPtr mWindow, bool aFlushLayout, nsPoint& aScrollPos) {
   if (!nsContentUtils::IsCallerChrome()) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1563,18 +1563,21 @@ nsGlobalWindow::FreeInnerObjects()
 
   if (mDoc) {
     // Remember the document's principal and URI.
     mDocumentPrincipal = mDoc->NodePrincipal();
     mDocumentURI = mDoc->GetDocumentURI();
     mDocBaseURI = mDoc->GetDocBaseURI();
 
     while (mDoc->EventHandlingSuppressed()) {
-      mDoc->UnsuppressEventHandlingAndFireEvents(false);
-    }
+      mDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents, false);
+    }
+
+    // Note: we don't have to worry about eAnimationsOnly suppressions because
+    // they won't leak.
   }
 
   // Remove our reference to the document and the document principal.
   mFocusedNode = nullptr;
 
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
     mApplicationCache = nullptr;
@@ -8277,17 +8280,17 @@ nsGlobalWindow::EnterModalState()
     nsIPresShell::SetCapturingContent(nullptr, 0);
   }
 
   if (topWin->mModalStateDepth == 0) {
     NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
 
     mSuspendedDoc = topDoc;
     if (mSuspendedDoc) {
-      mSuspendedDoc->SuppressEventHandling();
+      mSuspendedDoc->SuppressEventHandling(nsIDocument::eAnimationsOnly);
     }
   }
   topWin->mModalStateDepth++;
 }
 
 // static
 void
 nsGlobalWindow::RunPendingTimeoutsRecursive(nsGlobalWindow *aTopWindow,
@@ -8374,17 +8377,18 @@ nsGlobalWindow::LeaveModalState()
 
   if (topWin->mModalStateDepth == 0) {
     nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
     if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
       NS_WARNING("failed to dispatch pending timeout runnable");
 
     if (mSuspendedDoc) {
       nsCOMPtr<nsIDocument> currentDoc = topWin->GetExtantDoc();
-      mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc == mSuspendedDoc);
+      mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eAnimationsOnly,
+                                                          currentDoc == mSuspendedDoc);
       mSuspendedDoc = nullptr;
     }
   }
 
   // Remember the time of the last dialog quit.
   nsGlobalWindow *inner = topWin->GetCurrentInnerWindowInternal();
   if (inner)
     inner->mLastDialogQuitTime = TimeStamp::Now();
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -22,17 +22,17 @@
 #include "mozilla/dom/RootedDictionary.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsCycleCollector.h"
 #include "nsIXPConnect.h"
 #include "MainThreadUtils.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "qsObjectHelper.h"
 #include "xpcpublic.h"
 #include "nsIVariant.h"
 
 #include "nsWrapperCacheInlines.h"
 
 class nsPIDOMWindow;
 
--- a/dom/bindings/NonRefcountedDOMObject.h
+++ b/dom/bindings/NonRefcountedDOMObject.h
@@ -2,17 +2,17 @@
 /* vim: set ts=2 sw=2 et tw=79: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_NonRefcountedDOMObject_h__
 #define mozilla_dom_NonRefcountedDOMObject_h__
 
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
 
 // Natives for DOM classes with 'owned' as the value for nativeOwnership in
 // Bindings.conf need to inherit from this class.
 // If you're seeing objects of this class leak then natives for one of the DOM
 // classes with 'owned' as the value for nativeOwnership in Bindings.conf is
--- a/dom/bluetooth/ipc/BluetoothChild.cpp
+++ b/dom/bluetooth/ipc/BluetoothChild.cpp
@@ -5,18 +5,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "BluetoothChild.h"
 
 #include "mozilla/Assertions.h"
 #include "nsDebug.h"
+#include "nsISupportsImpl.h"
 #include "nsThreadUtils.h"
-#include "nsTraceRefcnt.h"
 
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothServiceChildProcess.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 namespace {
--- a/dom/bluetooth/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/ipc/BluetoothParent.cpp
@@ -6,18 +6,18 @@
 
 #include "base/basictypes.h"
 
 #include "BluetoothParent.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/unused.h"
 #include "nsDebug.h"
+#include "nsISupportsImpl.h"
 #include "nsThreadUtils.h"
-#include "nsTraceRefcnt.h"
 
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 
 using mozilla::unused;
 USING_BLUETOOTH_NAMESPACE
 
 /*******************************************************************************
--- a/dom/events/Touch.h
+++ b/dom/events/Touch.h
@@ -3,29 +3,31 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Touch_h
 #define mozilla_dom_Touch_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
+#include "mozilla/MouseEvents.h"
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
 #include "Units.h"
 
 class nsPresContext;
 
 namespace mozilla {
 namespace dom {
 
 class EventTarget;
 
 class Touch MOZ_FINAL : public nsISupports
                       , public nsWrapperCache
+                      , public WidgetPointerHelper
 {
 public:
   static bool PrefEnabled(JSContext* aCx, JSObject* aGlobal);
 
   Touch(mozilla::dom::EventTarget* aTarget,
         int32_t aIdentifier,
         int32_t aPageX,
         int32_t aPageY,
--- a/dom/events/nsEventStateManager.cpp
+++ b/dom/events/nsEventStateManager.cpp
@@ -1089,16 +1089,21 @@ nsEventStateManager::PreHandleEvent(nsPr
         // then fall through...
       case WidgetMouseEvent::eRightButton:
       case WidgetMouseEvent::eMiddleButton:
         SetClickCount(aPresContext, mouseEvent, aStatus);
         break;
     }
     break;
   }
+  case NS_POINTER_CANCEL:
+  {
+    GenerateMouseEnterExit(mouseEvent);
+    break;
+  }
   case NS_MOUSE_EXIT:
     // If the event is not a top-level window exit, then it's not
     // really an exit --- we may have traversed widget boundaries but
     // we're still in our toplevel window.
     if (mouseEvent->exit != WidgetMouseEvent::eTopLevel) {
       // Treat it as a synthetic move so we don't generate spurious
       // "exit" or "move" events.  Any necessary "out" or "over" events
       // will be generated by GenerateMouseEnterExit
@@ -4435,16 +4440,17 @@ nsEventStateManager::GenerateMouseEnterE
         targetElement = mDocument->GetRootElement();
       }
       if (targetElement) {
         NotifyMouseOver(aMouseEvent, targetElement);
       }
     }
     break;
   case NS_POINTER_LEAVE:
+  case NS_POINTER_CANCEL:
   case NS_MOUSE_EXIT:
     {
       // This is actually the window mouse exit or pointer leave event. We're not moving
       // into any new element.
 
       OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
       if (helper->mLastOverFrame &&
           nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
--- a/dom/plugins/base/nsPluginNativeWindow.h
+++ b/dom/plugins/base/nsPluginNativeWindow.h
@@ -4,20 +4,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _nsPluginNativeWindow_h_
 #define _nsPluginNativeWindow_h_
 
 #include "nscore.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
+#include "nsISupportsImpl.h"
 #include "nsNPAPIPluginInstance.h"
 #include "npapi.h"
 #include "nsIWidget.h"
-#include "nsTraceRefcnt.h"
 
 /**
  * base class for native plugin window implementations
  */
 class nsPluginNativeWindow : public NPWindow
 {
 public: 
   nsPluginNativeWindow() : NPWindow() {
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -69,16 +69,17 @@ var ecmaGlobals =
     {name: "NaN", xbl: false},
     "Number",
     "Object",
     "Proxy",
     "RangeError",
     "ReferenceError",
     "RegExp",
     "Set",
+    {name: "SharedArrayBuffer", nightly: true},
     {name: "SIMD", nightly: true},
     "StopIteration",
     "String",
     "SyntaxError",
     {name: "TypedObject", nightly: true},
     "TypeError",
     "Uint16Array",
     "Uint32Array",
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -35,22 +35,22 @@
 #include "mozilla/dom/MessageEventBinding.h"
 #include "mozilla/dom/WorkerBinding.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/Navigator.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollector.h"
 #include "nsDOMJSUtils.h"
+#include "nsISupportsImpl.h"
 #include "nsLayoutStatics.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
-#include "nsTraceRefcnt.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMPrivate.h"
 #include "OSFileConstants.h"
 #include "xpcpublic.h"
 
 #ifdef MOZ_NUWA_PROCESS
 #include "ipc/Nuwa.h"
 #endif
--- a/dom/xslt/base/txCore.h
+++ b/dom/xslt/base/txCore.h
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __txCore_h__
 #define __txCore_h__
 
 #include "nscore.h"
 #include "nsDebug.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 class nsAString;
 
 class txObject
 {
 public:
     txObject()
     {
--- a/editor/libeditor/html/TypeInState.cpp
+++ b/editor/libeditor/html/TypeInState.cpp
@@ -11,19 +11,19 @@
 #include "nsAString.h"
 #include "nsDebug.h"
 #include "nsEditProperty.h"
 #include "nsEditor.h"
 #include "nsError.h"
 #include "nsIDOMNode.h"
 #include "nsISelection.h"
 #include "nsISupportsBase.h"
+#include "nsISupportsImpl.h"
 #include "nsReadableUtils.h"
 #include "nsStringFwd.h"
-#include "nsTraceRefcnt.h"
 
 class nsIAtom;
 class nsIDOMDocument;
 
 /********************************************************************
  *                     XPCOM cruft 
  *******************************************************************/
 
--- a/editor/libeditor/html/nsHTMLEditRules.h
+++ b/editor/libeditor/html/nsHTMLEditRules.h
@@ -12,17 +12,16 @@
 #include "nsEditor.h"
 #include "nsIEditActionListener.h"
 #include "nsIEditor.h"
 #include "nsIHTMLEditor.h"
 #include "nsISupportsImpl.h"
 #include "nsSelectionState.h"
 #include "nsTArray.h"
 #include "nsTextEditRules.h"
-#include "nsTraceRefcnt.h"
 #include "nscore.h"
 
 class nsHTMLEditor;
 class nsIAtom;
 class nsIDOMCharacterData;
 class nsIDOMDocument;
 class nsIDOMElement;
 class nsIDOMNode;
--- a/editor/txmgr/src/nsTransactionItem.cpp
+++ b/editor/txmgr/src/nsTransactionItem.cpp
@@ -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 "mozilla/mozalloc.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsError.h"
+#include "nsISupportsImpl.h"
 #include "nsITransaction.h"
-#include "nsTraceRefcnt.h"
 #include "nsTransactionItem.h"
 #include "nsTransactionManager.h"
 #include "nsTransactionStack.h"
 
 nsTransactionItem::nsTransactionItem(nsITransaction *aTransaction)
     : mTransaction(aTransaction), mUndoStack(0), mRedoStack(0)
 {
 }
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -9,17 +9,17 @@
 #include "Units.h"                      // for ScreenPoint
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/gfx/Point.h"          // for IntSize, Point
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for Float
 #include "mozilla/layers/CompositorTypes.h"  // for DiagnosticTypes, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"
 #include <vector>
 
 /**
  * Different elements of a web pages are rendered into separate "layers" before
  * they are flattened into the final image that is brought to the screen.
  * See Layers.h for more informations about layers and why we use retained
  * structures.
--- a/gfx/layers/CopyableCanvasLayer.h
+++ b/gfx/layers/CopyableCanvasLayer.h
@@ -14,17 +14,17 @@
 #include "gfxTypes.h"
 #include "gfxPlatform.h"                // for gfxImageFormat
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class CanvasClientWebGL;
 
 /**
  * A shared CanvasLayer implementation that supports copying
--- a/gfx/layers/LayerTreeInvalidation.cpp
+++ b/gfx/layers/LayerTreeInvalidation.cpp
@@ -20,17 +20,16 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr, etc
 #include "nsDataHashtable.h"            // for nsDataHashtable
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsHashKeys.h"                 // for nsPtrHashKey
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray_Impl
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 struct LayerPropertiesBase;
 LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot);
 
 static nsIntRect
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -14,17 +14,16 @@
 #include "LayerSorter.h"                // for SortLayersBy3DZOrder
 #include "LayersLogging.h"              // for AppendToString
 #include "ReadbackLayer.h"              // for ReadbackLayer
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxUtils.h"                   // for gfxUtils, etc
 #include "gfx2DGlue.h"
 #include "mozilla/DebugOnly.h"          // for DebugOnly
 #include "mozilla/Telemetry.h"          // for Accumulate
-#include "mozilla/TelemetryHistogramEnums.h"
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/layers/AsyncPanZoomController.h"
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite
 #include "mozilla/layers/LayersMessages.h"  // for TransformFunction, etc
--- a/gfx/layers/RotatedBuffer.h
+++ b/gfx/layers/RotatedBuffer.h
@@ -10,20 +10,20 @@
 #include "gfxASurface.h"                // for gfxASurface, etc
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/RefPtr.h"             // for RefPtr, TemporaryRef
 #include "mozilla/gfx/2D.h"             // for DrawTarget, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "LayersTypes.h"
 
 struct nsIntSize;
 
 namespace mozilla {
 namespace gfx {
 class Matrix;
 }
--- a/gfx/layers/basic/BasicColorLayer.cpp
+++ b/gfx/layers/basic/BasicColorLayer.cpp
@@ -12,17 +12,16 @@
 #include "gfx2DGlue.h"
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class BasicColorLayer : public ColorLayer, public BasicImplData {
 public:
--- a/gfx/layers/basic/BasicContainerLayer.h
+++ b/gfx/layers/basic/BasicContainerLayer.h
@@ -5,18 +5,18 @@
 
 #ifndef GFX_BASICCONTAINERLAYER_H
 #define GFX_BASICCONTAINERLAYER_H
 
 #include "BasicImplData.h"              // for BasicImplData
 #include "BasicLayers.h"                // for BasicLayerManager
 #include "Layers.h"                     // for Layer, ContainerLayer
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR
 struct nsIntRect;
 
 namespace mozilla {
 namespace layers {
 
 class BasicContainerLayer : public ContainerLayer, public BasicImplData {
 public:
   BasicContainerLayer(BasicLayerManager* aManager) :
--- a/gfx/layers/basic/BasicImageLayer.cpp
+++ b/gfx/layers/basic/BasicImageLayer.cpp
@@ -18,17 +18,16 @@
 #endif
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxPattern::Release, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "mozilla/gfx/Point.h"          // for IntSize
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class BasicImageLayer : public ImageLayer, public BasicImplData {
--- a/gfx/layers/basic/BasicImplData.h
+++ b/gfx/layers/basic/BasicImplData.h
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_BASICIMPLDATA_H
 #define GFX_BASICIMPLDATA_H
 
 #include "Layers.h"                     // for Layer (ptr only), etc
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "nsDebug.h"                    // for NS_ASSERTION
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "mozilla/gfx/Types.h"
 
 class gfxASurface;
 
 namespace mozilla {
 namespace layers {
 
 class ReadbackProcessor;
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -40,17 +40,16 @@
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, etc
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion, etc
 #include "nsTArray.h"                   // for nsAutoTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #define PIXMAN_DONT_DEFINE_STDINT
 #include "pixman.h"                     // for pixman_f_transform, etc
 
 class nsIWidget;
 
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
--- a/gfx/layers/basic/BasicLayersImpl.h
+++ b/gfx/layers/basic/BasicLayersImpl.h
@@ -13,17 +13,16 @@
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "ipc/AutoOpenSurface.h"        // for AutoOpenSurface
 #include "mozilla/Attributes.h"         // for MOZ_DELETE, MOZ_STACK_CLASS
 #include "mozilla/Maybe.h"              // for Maybe
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for gfxContext::Release, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class AutoMaskData;
 class BasicContainerLayer;
 class Layer;
 
--- a/gfx/layers/basic/BasicThebesLayer.h
+++ b/gfx/layers/basic/BasicThebesLayer.h
@@ -11,18 +11,18 @@
 #include "BasicImplData.h"              // for BasicImplData
 #include "BasicLayers.h"                // for BasicLayerManager
 #include "gfxPoint.h"                   // for gfxPoint
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/layers/ContentClient.h"  // for ContentClientBasic
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 class gfxContext;
 
 namespace mozilla {
 namespace layers {
 
 class ReadbackProcessor;
 
 class BasicThebesLayer : public ThebesLayer, public BasicImplData {
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -11,18 +11,18 @@
 #include "CopyableCanvasLayer.h"        // for CopyableCanvasLayer
 #include "Layers.h"                     // for CanvasLayer, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/LayersMessages.h"  // for CanvasLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
 class ShadowableLayer;
 
 class ClientCanvasLayer : public CopyableCanvasLayer,
--- a/gfx/layers/client/ClientColorLayer.cpp
+++ b/gfx/layers/client/ClientColorLayer.cpp
@@ -7,17 +7,16 @@
 #include "Layers.h"                     // for ColorLayer, etc
 #include "mozilla/layers/LayersMessages.h"  // for ColorLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator new
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class ClientColorLayer : public ColorLayer, 
                          public ClientLayer {
--- a/gfx/layers/client/ClientContainerLayer.h
+++ b/gfx/layers/client/ClientContainerLayer.h
@@ -6,20 +6,20 @@
 #ifndef GFX_CLIENTCONTAINERLAYER_H
 #define GFX_CLIENTCONTAINERLAYER_H
 
 #include <stdint.h>                     // for uint32_t
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 #include "Layers.h"                     // for Layer, ContainerLayer, etc
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsAutoTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class ShadowableLayer;
 
 class ClientContainerLayer : public ContainerLayer,
                              public ClientLayer
--- a/gfx/layers/client/ClientImageLayer.cpp
+++ b/gfx/layers/client/ClientImageLayer.cpp
@@ -13,17 +13,16 @@
 #include "mozilla/layers/ImageClient.h"  // for ImageClient, etc
 #include "mozilla/layers/LayersMessages.h"  // for ImageLayerAttributes, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr, getter_AddRefs, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Layer::AddRef, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 class ClientImageLayer : public ImageLayer, 
                          public ClientLayer {
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -16,17 +16,16 @@
 #include "mozilla/layers/LayersTypes.h"  // for BufferMode, LayersBackend, etc
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR
 #include "nscore.h"                     // for nsAString
 
 class nsIWidget;
 
 namespace mozilla {
 namespace layers {
 
 class ClientThebesLayer;
--- a/gfx/layers/client/ClientThebesLayer.h
+++ b/gfx/layers/client/ClientThebesLayer.h
@@ -9,18 +9,18 @@
 #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 #include "Layers.h"                     // for ThebesLayer, etc
 #include "RotatedBuffer.h"              // for RotatedContentBuffer, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/ContentClient.h"  // for ContentClient
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "mozilla/layers/PLayerTransaction.h" // for ThebesLayerAttributes
 
 class gfxContext;
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
--- a/gfx/layers/client/ClientTiledThebesLayer.cpp
+++ b/gfx/layers/client/ClientTiledThebesLayer.cpp
@@ -9,18 +9,18 @@
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/gfx/Rect.h"           // for Rect, RectTyped
 #include "mozilla/layers/LayersMessages.h"
 #include "mozilla/mozalloc.h"           // for operator delete, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRect.h"                     // for nsIntRect
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 
 ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager)
   : ThebesLayer(aManager,
                 static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
--- a/gfx/layers/client/CompositableClient.h
+++ b/gfx/layers/client/CompositableClient.h
@@ -10,17 +10,17 @@
 #include <vector>                       // for vector
 #include <map>                          // for map
 #include "mozilla/Assertions.h"         // for MOZ_CRASH
 #include "mozilla/RefPtr.h"             // for TemporaryRef, RefCounted
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend
 #include "mozilla/layers/PCompositableChild.h"  // for PCompositableChild
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "gfxASurface.h"                // for gfxContentType
 
 namespace mozilla {
 namespace layers {
 
 class CompositableClient;
 class DeprecatedTextureClient;
 class TextureClient;
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -16,17 +16,17 @@
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "mozilla/layers/SharedPlanarYCbCrImage.h"
 #include "mozilla/layers/YCbCrImageDataSerializer.h"
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "ImageContainer.h"             // for PlanarYCbCrImage, etc
 #include "mozilla/gfx/2D.h"
 
 #ifdef MOZ_ANDROID_OMTC
 #  include "gfxReusableImageSurfaceWrapper.h"
 #  include "gfxImageSurface.h"
 #else
 #  include "gfxReusableSharedImageSurfaceWrapper.h"
@@ -103,17 +103,17 @@ private:
     AddRef();
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
 
-  CompositableForwarder* mForwarder;
+  RefPtr<CompositableForwarder> mForwarder;
   TextureClientData* mTextureData;
   TextureClient* mTextureClient;
   bool mIPCOpen;
 
   friend class TextureClient;
 };
 
 void
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -16,21 +16,21 @@
 #include "gfxTypes.h"
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
 #include "mozilla/layers/CompositorTypes.h"  // for TextureInfo, etc
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsRefPtr
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_DTOR
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_DTOR
 #include "mozilla/layers/ISurfaceAllocator.h"
 #include "gfxReusableSurfaceWrapper.h"
 
 class gfxImageSurface;
 
 namespace mozilla {
 namespace layers {
 
--- a/gfx/layers/composite/APZCTreeManager.h
+++ b/gfx/layers/composite/APZCTreeManager.h
@@ -11,18 +11,17 @@
 #include "Units.h"                      // for CSSPoint, CSSRect, etc
 #include "gfxPoint.h"                   // for gfxPoint
 #include "gfx3DMatrix.h"                // for gfx3DMatrix
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/EventForwards.h"      // for WidgetInputEvent, nsEventStatus
 #include "mozilla/Monitor.h"            // for Monitor
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
-#include "nsISupportsImpl.h"
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "mozilla/Vector.h"             // for mozilla::Vector
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 
 class gfx3DMatrix;
 template <class E> class nsTArray;
 
 namespace mozilla {
 class InputData;
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -12,17 +12,16 @@
 #include "mozilla/Attributes.h"         // for MOZ_DELETE, MOZ_FINAL, etc
 #include "mozilla/RefPtr.h"             // for RefCounted
 #include "mozilla/TimeStamp.h"          // for TimeStamp
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/gfx/BasePoint.h"      // for BasePoint
 #include "mozilla/layers/LayersMessages.h"  // for TargetConfig
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for LayerManager::AddRef, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
 namespace layers {
 
 class AsyncPanZoomController;
 class Layer;
 class LayerManagerComposite;
 class AutoResolveRefLayers;
--- a/gfx/layers/composite/CanvasLayerComposite.cpp
+++ b/gfx/layers/composite/CanvasLayerComposite.cpp
@@ -11,19 +11,19 @@
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/gfx/Point.h"          // for Point
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/Effects.h"     // for EffectChain
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsString.h"                   // for nsAutoCString
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::gfx;
 
 CanvasLayerComposite::CanvasLayerComposite(LayerManagerComposite* aManager)
   : CanvasLayer(aManager, nullptr)
   , LayerComposite(aManager)
--- a/gfx/layers/composite/ColorLayerComposite.h
+++ b/gfx/layers/composite/ColorLayerComposite.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_ColorLayerComposite_H
 #define GFX_ColorLayerComposite_H
 
 #include "Layers.h"                     // for ColorLayer, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/layers/LayerManagerComposite.h"  // for LayerComposite, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 
 struct nsIntPoint;
 struct nsIntRect;
 
 namespace mozilla {
 namespace layers {
 
 class CompositableHost;
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -9,17 +9,17 @@
 #include "ContentHost.h"                // for ContentHostDoubleBuffered, etc
 #include "Effects.h"                    // for EffectMask, Effect, etc
 #include "ImageHost.h"                  // for DeprecatedImageHostBuffered, etc
 #include "TiledContentHost.h"           // for TiledContentHost
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureHost.h"  // for TextureHost, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_WARNING
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "gfxPlatform.h"                // for gfxPlatform
 
 namespace mozilla {
 namespace layers {
 
 class Matrix4x4;
 class Compositor;
 
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -20,22 +20,22 @@
 #include "mozilla/gfx/Rect.h"           // for IntRect, Rect
 #include "mozilla/layers/Compositor.h"  // for Compositor, etc
 #include "mozilla/layers/CompositorTypes.h"  // for DIAGNOSTIC_CONTAINER
 #include "mozilla/layers/Effects.h"     // for Effect, EffectChain, etc
 #include "mozilla/layers/TextureHost.h"  // for CompositingRenderTarget
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsAutoTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include <vector>
 
 namespace mozilla {
 namespace layers {
 
 // HasOpaqueAncestorLayer and ContainerRender are shared between RefLayer and ContainerLayer
 static bool
 HasOpaqueAncestorLayer(Layer* aLayer)
--- a/gfx/layers/composite/ContentHost.h
+++ b/gfx/layers/composite/ContentHost.h
@@ -21,21 +21,21 @@
 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/LayersTypes.h"  // for etc
 #include "mozilla/layers/TextureHost.h"  // for DeprecatedTextureHost
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAutoPtr.h"                  // for nsAutoPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for nsACString
 
 namespace mozilla {
 namespace gfx {
 class Matrix4x4;
 }
 namespace layers {
 class Compositor;
--- a/gfx/layers/composite/ImageLayerComposite.cpp
+++ b/gfx/layers/composite/ImageLayerComposite.cpp
@@ -15,20 +15,20 @@
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/Effects.h"     // for EffectChain
 #include "mozilla/layers/TextureHost.h"  // for DeprecatedTextureHost, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_ASSERTION
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsString.h"                   // for nsAutoCString
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace layers {
 
 ImageLayerComposite::ImageLayerComposite(LayerManagerComposite* aManager)
   : ImageLayer(aManager, nullptr)
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -15,18 +15,18 @@
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface
 #include "mozilla/gfx/Point.h"          // for IntSize, IntPoint
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat, etc
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags, etc
 #include "mozilla/layers/LayersTypes.h"  // for LayerRenderState, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsRegion.h"                   // for nsIntRegion
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for nsACString
 #include "mozilla/layers/AtomicRefCountedWithFinalize.h"
 
 class gfxImageSurface;
 class gfxReusableSurfaceWrapper;
 struct nsIntPoint;
 struct nsIntSize;
 struct nsIntRect;
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -15,22 +15,22 @@
 #include "mozilla/gfx/Rect.h"           // for RoundedToInt, Rect
 #include "mozilla/gfx/Types.h"          // for Filter::Filter::LINEAR
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/ContentHost.h"  // for ContentHost
 #include "mozilla/layers/Effects.h"     // for EffectChain
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "nsAString.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsMathUtils.h"                // for NS_lround
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
 #include "nsString.h"                   // for nsAutoCString
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "GeckoProfiler.h"
 
 namespace mozilla {
 namespace layers {
 
 class TiledLayerComposer;
 
 ThebesLayerComposite::ThebesLayerComposite(LayerManagerComposite *aManager)
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -44,24 +44,23 @@
 #include "mozilla/layers/TaskThrottler.h"  // for TaskThrottler
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "mozilla/unused.h"             // for unused
 #include "nsAlgorithm.h"                // for clamped
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsIDOMWindowUtils.h"          // for nsIDOMWindowUtils
-#include "nsISupportsImpl.h"
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsMathUtils.h"                // for NS_hypot
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsStyleConsts.h"
 #include "nsStyleStruct.h"              // for nsTimingFunction
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
 #include "nsThreadUtils.h"              // for NS_IsMainThread
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "SharedMemoryBasic.h"          // for SharedMemoryBasic
 
 // #define APZC_ENABLE_RENDERTRACE
 
 #define APZC_LOG(...)
 // #define APZC_LOG(...) printf_stderr("APZC: " __VA_ARGS__)
 #define APZC_LOG_FM(fm, prefix, ...) \
   APZC_LOG(prefix ":" \
--- a/gfx/layers/ipc/CompositorChild.cpp
+++ b/gfx/layers/ipc/CompositorChild.cpp
@@ -11,18 +11,18 @@
 #include "base/process_util.h"          // for OpenProcessHandle
 #include "base/task.h"                  // for NewRunnableMethod, etc
 #include "base/tracked.h"               // for FROM_HERE
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/PLayerTransactionChild.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsIObserver.h"                // for nsIObserver
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop, etc
 #include "FrameLayerBuilder.h"
 
 using mozilla::layers::LayerTransactionChild;
 
 namespace mozilla {
 namespace layers {
 
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -33,21 +33,21 @@
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayerManagerComposite.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/PLayerTransactionParent.h"
 #include "mozilla/mozalloc.h"           // for operator new, etc
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsIWidget.h"                  // for nsIWidget
 #include "nsRect.h"                     // for nsIntRect
 #include "nsTArray.h"                   // for nsTArray
 #include "nsThreadUtils.h"              // for NS_IsMainThread
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nsXULAppAPI.h"                // for XRE_GetIOMessageLoop
 #ifdef XP_WIN
 #include "mozilla/layers/CompositorD3D11.h"
 #include "mozilla/layers/CompositorD3D9.h"
 #endif
 #include "GeckoProfiler.h"
 #include "mozilla/ipc/ProtocolTypes.h"
 
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -32,17 +32,16 @@
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsCoord.h"                    // for NSAppUnitsToFloatPixels
 #include "nsDebug.h"                    // for NS_RUNTIMEABORT
 #include "nsISupportsImpl.h"            // for Layer::Release, etc
 #include "nsLayoutUtils.h"              // for nsLayoutUtils
 #include "nsMathUtils.h"                // for NS_round
 #include "nsPoint.h"                    // for nsPoint
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "GeckoProfiler.h"
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/layers/AsyncCompositionManager.h"
 
 typedef std::vector<mozilla::layers::EditReply> EditReplyVector;
 
 using mozilla::layout::RenderFrameParent;
 
@@ -392,17 +391,21 @@ LayerTransactionParent::RecvUpdate(const
         edit.get_OpSetDiagnosticTypes().diagnostics());
       break;
     }
     // Tree ops
     case Edit::TOpSetRoot: {
       MOZ_LAYERS_LOG(("[ParentSide] SetRoot"));
 
       Layer* newRoot = AsLayerComposite(edit.get_OpSetRoot())->AsLayer();
+      if (!newRoot) {
+        return false;
+      }
       if (newRoot->GetParent()) {
+        // newRoot is not a root!
         return false;
       }
       mRoot = newRoot;
       break;
     }
     case Edit::TOpInsertAfter: {
       MOZ_LAYERS_LOG(("[ParentSide] InsertAfter"));
 
--- a/gfx/layers/ipc/SharedPlanarYCbCrImage.h
+++ b/gfx/layers/ipc/SharedPlanarYCbCrImage.h
@@ -5,17 +5,17 @@
 
 #include <stdint.h>                     // for uint8_t, uint32_t
 #include "ImageContainer.h"             // for PlanarYCbCrImage, etc
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/ipc/Shmem.h"          // for Shmem
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR
 
 class gfxASurface;
 
 #ifndef MOZILLA_LAYERS_DeprecatedSharedPlanarYCbCrImage_H
 #define MOZILLA_LAYERS_DeprecatedSharedPlanarYCbCrImage_H
 
 namespace mozilla {
 namespace layers {
--- a/gfx/layers/ipc/SharedRGBImage.cpp
+++ b/gfx/layers/ipc/SharedRGBImage.cpp
@@ -14,17 +14,16 @@
 #include "mozilla/layers/TextureClient.h"  // for BufferTextureClient, etc
 #include "mozilla/layers/ImageBridgeChild.h"  // for ImageBridgeChild
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for NS_WARNING, NS_ASSERTION
 #include "nsISupportsImpl.h"            // for Image::AddRef, etc
 #include "nsRect.h"                     // for nsIntRect
 #include "nsSize.h"                     // for nsIntSize
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 // Just big enough for a 1080p RGBA32 frame
 #define MAX_FRAME_SIZE (16 * 1024 * 1024)
 
 namespace mozilla {
 namespace layers {
 
 DeprecatedSharedRGBImage::DeprecatedSharedRGBImage(ISurfaceAllocator *aAllocator) :
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -19,20 +19,20 @@
 #include "mozilla/gfx/Rect.h"           // for Rect, IntRect
 #include "mozilla/gfx/Types.h"          // for Float, SurfaceFormat, etc
 #include "mozilla/layers/Compositor.h"  // for SurfaceInitMode, Compositor, etc
 #include "mozilla/layers/CompositorTypes.h"  // for MaskType::NumMaskTypes, etc
 #include "mozilla/layers/LayersTypes.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr, nsAutoPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsSize.h"                     // for nsIntSize
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"              // for nsRunnable
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType
 #include "nscore.h"                     // for NS_IMETHOD
 #include "VBOArena.h"                   // for gl::VBOArena
 
 class gfx3DMatrix;
 class nsIWidget;
 
 namespace mozilla {
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -23,17 +23,16 @@
 #include "mozilla/layers/CompositorTypes.h"  // for TextureFlags
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureHost.h"  // for DeprecatedTextureHost, etc
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 #include "nsDebug.h"                    // for NS_WARNING
 #include "nsISupportsImpl.h"            // for TextureImage::Release, etc
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "OGLShaderProgram.h"           // for ShaderProgramType, etc
 #ifdef MOZ_WIDGET_GONK
 #include <ui/GraphicBuffer.h>
 #if ANDROID_VERSION >= 18
 #include <ui/Fence.h>
 #endif
 #endif
 
--- a/gfx/src/nsDeviceContext.cpp
+++ b/gfx/src/nsDeviceContext.cpp
@@ -20,25 +20,25 @@
 #include "nsIAtom.h"                    // for nsIAtom, do_GetAtom
 #include "nsID.h"
 #include "nsIDeviceContextSpec.h"       // for nsIDeviceContextSpec
 #include "nsILanguageAtomService.h"     // for nsILanguageAtomService, etc
 #include "nsIObserver.h"                // for nsIObserver, etc
 #include "nsIObserverService.h"         // for nsIObserverService
 #include "nsIScreen.h"                  // for nsIScreen
 #include "nsIScreenManager.h"           // for nsIScreenManager
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsISupportsUtils.h"           // for NS_ADDREF, NS_RELEASE
 #include "nsIWidget.h"                  // for nsIWidget, NS_NATIVE_WINDOW
 #include "nsRect.h"                     // for nsRect
 #include "nsRenderingContext.h"         // for nsRenderingContext
 #include "nsServiceManagerUtils.h"      // for do_GetService
 #include "nsString.h"               // for nsDependentString
 #include "nsTArray.h"                   // for nsTArray, nsTArray_Impl
 #include "nsThreadUtils.h"              // for NS_IsMainThread
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 
 #if !XP_MACOSX
 #include "gfxPDFSurface.h"
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPSSurface.h"
 #elif XP_WIN
--- a/gfx/src/nsRect.h
+++ b/gfx/src/nsRect.h
@@ -10,19 +10,19 @@
 #include <stdio.h>                      // for FILE
 #include <stdint.h>                     // for int32_t, int64_t
 #include <algorithm>                    // for min/max
 #include "nsDebug.h"                    // for NS_WARNING
 #include "gfxCore.h"                    // for NS_GFX
 #include "mozilla/Likely.h"             // for MOZ_UNLIKELY
 #include "mozilla/gfx/BaseRect.h"       // for BaseRect
 #include "nsCoord.h"                    // for nscoord, etc
+#include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsPoint.h"                    // for nsIntPoint, nsPoint
 #include "nsSize.h"                     // for nsIntSize, nsSize
-#include "nsTraceRefcnt.h"              // for MOZ_COUNT_CTOR, etc
 #include "nscore.h"                     // for NS_BUILD_REFCNT_LOGGING
 
 struct nsIntRect;
 struct nsMargin;
 struct nsIntMargin;
 
 struct NS_GFX nsRect :
   public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> {
--- a/gfx/thebes/gfxASurface.cpp
+++ b/gfx/thebes/gfxASurface.cpp
@@ -5,17 +5,17 @@
 
 #include "nsIMemoryReporter.h"
 #include "nsMemory.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "mozilla/gfx/2D.h"
 
 #include "gfxASurface.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 #include "gfxRect.h"
 
--- a/gfx/thebes/gfxFontInfoLoader.h
+++ b/gfx/thebes/gfxFontInfoLoader.h
@@ -11,17 +11,17 @@
 #include "nsIObserver.h"
 #include "nsITimer.h"
 #include "nsIThread.h"
 #include "nsRefPtrHashtable.h"
 #include "nsString.h"
 #include "gfxFont.h"
 #include "nsIRunnable.h"
 #include "mozilla/TimeStamp.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 // data retrieved for a given face
 
 struct FontFaceData {
     FontFaceData() : mUVSOffset(0), mSymbolFont(false) {}
 
     FontFaceData(const FontFaceData& aFontFaceData) {
         mFullName = aFontFaceData.mFullName;
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/process_util.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/ipc/ProtocolTypes.h"
 #include "BackgroundChild.h"
@@ -136,17 +137,17 @@ private:
   // background thread. It is specific to each instance of sBackgroundThread.
   static nsTArray<ParentImpl*>* sLiveActorsForBackgroundThread;
 
   // This is only modified on the main thread.
   static StaticRefPtr<nsITimer> sShutdownTimer;
 
   // This exists so that that [Assert]IsOnBackgroundThread() can continue to
   // work during shutdown.
-  static PRThread* sBackgroundPRThread;
+  static Atomic<PRThread*> sBackgroundPRThread;
 
   // This is only modified on the main thread. It is null if the thread does not
   // exist or is shutting down.
   static MessageLoop* sBackgroundThreadMessageLoop;
 
   // This is only modified on the main thread. It maintains a count of live
   // actors so that the background thread can be shut down when it is no longer
   // needed.
@@ -792,17 +793,17 @@ const ParentImpl::ProcessHandle ParentIm
 #endif
 
 StaticRefPtr<nsIThread> ParentImpl::sBackgroundThread;
 
 nsTArray<ParentImpl*>* ParentImpl::sLiveActorsForBackgroundThread;
 
 StaticRefPtr<nsITimer> ParentImpl::sShutdownTimer;
 
-PRThread* ParentImpl::sBackgroundPRThread = nullptr;
+Atomic<PRThread*> ParentImpl::sBackgroundPRThread;
 
 MessageLoop* ParentImpl::sBackgroundThreadMessageLoop = nullptr;
 
 uint64_t ParentImpl::sLiveActorCount = 0;
 
 bool ParentImpl::sShutdownObserverRegistered = false;
 
 bool ParentImpl::sShutdownHasStarted = false;
@@ -1244,27 +1245,27 @@ ParentImpl::RequestMessageLoopRunnable::
     return NS_OK;
   }
 
   char stackBaseGuess;
   profiler_register_thread("IPDL Background", &stackBaseGuess);
 
 #ifdef DEBUG
   {
-    PRThread* currentPRThread = PR_GetCurrentThread();
-    MOZ_ASSERT(currentPRThread);
-    MOZ_ASSERT_IF(sBackgroundPRThread, currentPRThread != sBackgroundPRThread);
-
     bool correctThread;
     MOZ_ASSERT(NS_SUCCEEDED(mTargetThread->IsOnCurrentThread(&correctThread)));
     MOZ_ASSERT(correctThread);
   }
 #endif
 
-  sBackgroundPRThread = PR_GetCurrentThread();
+  DebugOnly<PRThread*> oldBackgroundThread =
+    sBackgroundPRThread.exchange(PR_GetCurrentThread());
+
+  MOZ_ASSERT_IF(oldBackgroundThread,
+                PR_GetCurrentThread() != oldBackgroundThread);
 
   MOZ_ASSERT(!mMessageLoop);
 
   mMessageLoop = MessageLoop::current();
   MOZ_ASSERT(mMessageLoop);
 
   if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
     NS_WARNING("Failed to dispatch RequestMessageLoopRunnable to main thread!");
@@ -1276,17 +1277,21 @@ ParentImpl::RequestMessageLoopRunnable::
 
 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ShutdownBackgroundThreadRunnable,
                              nsRunnable)
 
 NS_IMETHODIMP
 ParentImpl::ShutdownBackgroundThreadRunnable::Run()
 {
   AssertIsInMainProcess();
-  AssertIsOnBackgroundThread();
+
+  // It is possible that another background thread was created while this thread
+  // was shutting down. In that case we can't assert anything about
+  // sBackgroundPRThread and we should not modify it here.
+  sBackgroundPRThread.compareExchange(PR_GetCurrentThread(), nullptr);
 
   profiler_unregister_thread();
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(ParentImpl::ForceCloseBackgroundActorsRunnable,
                              nsRunnable)
--- a/ipc/glue/CrossProcessMutex_posix.cpp
+++ b/ipc/glue/CrossProcessMutex_posix.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; 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 "CrossProcessMutex.h"
 #include "mozilla/unused.h"
 #include "nsDebug.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 namespace {
 
 struct MutexData {
   pthread_mutex_t mMutex;
   mozilla::Atomic<int32_t> mCount;
 };
 
--- a/ipc/glue/CrossProcessMutex_windows.cpp
+++ b/ipc/glue/CrossProcessMutex_windows.cpp
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <windows.h>
 
 #include "base/process_util.h"
 #include "CrossProcessMutex.h"
 #include "nsDebug.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 using namespace base;
 
 namespace mozilla {
 
 CrossProcessMutex::CrossProcessMutex(const char*)
 {
   // We explicitly share this using DuplicateHandle, we do -not- want this to
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -7,17 +7,17 @@
 
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Move.h"
 #include "nsDebug.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 // Undo the damage done by mozzconf.h
 #undef compress
 
 using namespace mozilla;
 using namespace std;
 
 using mozilla::MonitorAutoLock;
--- a/ipc/glue/MessageLink.cpp
+++ b/ipc/glue/MessageLink.cpp
@@ -6,17 +6,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 
 #include "nsDebug.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "nsXULAppAPI.h"
 
 using namespace mozilla;
 using namespace std;
 
 template<>
 struct RunnableMethodTraits<mozilla::ipc::ProcessLink>
 {
--- a/ipc/glue/SharedMemory.cpp
+++ b/ipc/glue/SharedMemory.cpp
@@ -43,16 +43,17 @@ public:
 };
 
 NS_IMPL_ISUPPORTS1(ShmemReporter, nsIMemoryReporter)
 
 SharedMemory::SharedMemory()
   : mAllocSize(0)
   , mMappedSize(0)
 {
+  MOZ_COUNT_CTOR(SharedMemory);
   static Atomic<bool> registered;
   if (registered.compareExchange(false, true)) {
     RegisterStrongMemoryReporter(new ShmemReporter());
   }
 }
 
 /*static*/ size_t
 SharedMemory::PageAlignedSize(size_t aSize)
--- a/ipc/glue/SharedMemory.h
+++ b/ipc/glue/SharedMemory.h
@@ -25,24 +25,29 @@ enum Rights {
 }
 
 namespace mozilla {
 namespace ipc {
 
 class SharedMemory
 {
 public:
+  virtual ~SharedMemory()
+  {
+    MOZ_COUNT_DTOR(SharedMemory);
+    Unmapped();
+    Destroyed();
+  }
+
   enum SharedMemoryType {
     TYPE_BASIC,
     TYPE_SYSV,
     TYPE_UNKNOWN
   };
 
-  virtual ~SharedMemory() { Unmapped(); Destroyed(); }
-
   size_t Size() const { return mMappedSize; }
 
   virtual void* memory() const = 0;
 
   virtual bool Create(size_t size) = 0;
   virtual bool Map(size_t nBytes) = 0;
 
   virtual SharedMemoryType Type() const = 0;
--- a/ipc/glue/WindowsMessageLoop.h
+++ b/ipc/glue/WindowsMessageLoop.h
@@ -7,17 +7,17 @@
 
 #ifndef IPC_GLUE_WINDOWSMESSAGELOOP_H
 #define IPC_GLUE_WINDOWSMESSAGELOOP_H
 
 // This file is only meant to compile on windows
 #include <windows.h>
 
 #include "base/basictypes.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace ipc {
 namespace windows {
 
 class DeferredMessage
 {
 public:
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -8,20 +8,20 @@ var ignoreIndirectCalls = {
     "aMallocSizeOf" : true,
     "_malloc_message" : true,
     "__conv" : true,
     "__convf" : true,
     "prerrortable.c:callback_newtable" : true,
     "mozalloc_oom.cpp:void (* gAbortHandler)(size_t)" : true,
 
     // I don't know why these are getting truncated
-    "nsTraceRefcntImpl.cpp:void (* leakyLogAddRef)(void*": true,
-    "nsTraceRefcntImpl.cpp:void (* leakyLogAddRef)(void*, int, int)": true,
-    "nsTraceRefcntImpl.cpp:void (* leakyLogRelease)(void*": true,
-    "nsTraceRefcntImpl.cpp:void (* leakyLogRelease)(void*, int, int)": true,
+    "nsTraceRefcnt.cpp:void (* leakyLogAddRef)(void*": true,
+    "nsTraceRefcnt.cpp:void (* leakyLogAddRef)(void*, int, int)": true,
+    "nsTraceRefcnt.cpp:void (* leakyLogRelease)(void*": true,
+    "nsTraceRefcnt.cpp:void (* leakyLogRelease)(void*, int, int)": true,
 };
 
 function indirectCallCannotGC(fullCaller, fullVariable)
 {
     var caller = readable(fullCaller);
 
     // This is usually a simple variable name, but sometimes a full name gets
     // passed through. And sometimes that name is truncated. Examples:
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -427,16 +427,17 @@ Is##base##AboutToBeFinalized(BarrieredPt
 }
 
 DeclMarkerImpl(BaseShape, BaseShape)
 DeclMarkerImpl(BaseShape, UnownedBaseShape)
 DeclMarkerImpl(JitCode, jit::JitCode)
 DeclMarkerImpl(Object, ArgumentsObject)
 DeclMarkerImpl(Object, ArrayBufferObject)
 DeclMarkerImpl(Object, ArrayBufferViewObject)
+DeclMarkerImpl(Object, SharedArrayBufferObject)
 DeclMarkerImpl(Object, DebugScopeObject)
 DeclMarkerImpl(Object, GlobalObject)
 DeclMarkerImpl(Object, JSObject)
 DeclMarkerImpl(Object, JSFunction)
 DeclMarkerImpl(Object, ObjectImpl)
 DeclMarkerImpl(Object, ScopeObject)
 DeclMarkerImpl(Script, JSScript)
 DeclMarkerImpl(LazyScript, LazyScript)
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -12,16 +12,17 @@
 class JSAtom;
 class JSLinearString;
 
 namespace js {
 
 class ArgumentsObject;
 class ArrayBufferObject;
 class ArrayBufferViewObject;
+class SharedArrayBufferObject;
 class BaseShape;
 class DebugScopeObject;
 struct GCMarker;
 class GlobalObject;
 class LazyScript;
 class ScopeObject;
 class Shape;
 class UnownedBaseShape;
@@ -92,16 +93,17 @@ bool Is##base##AboutToBeFinalized(type *
 bool Is##base##AboutToBeFinalized(BarrieredPtr<type> *thingp);                                 \
 
 DeclMarker(BaseShape, BaseShape)
 DeclMarker(BaseShape, UnownedBaseShape)
 DeclMarker(JitCode, jit::JitCode)
 DeclMarker(Object, ArgumentsObject)
 DeclMarker(Object, ArrayBufferObject)
 DeclMarker(Object, ArrayBufferViewObject)
+DeclMarker(Object, SharedArrayBufferObject)
 DeclMarker(Object, DebugScopeObject)
 DeclMarker(Object, GlobalObject)
 DeclMarker(Object, JSObject)
 DeclMarker(Object, JSFunction)
 DeclMarker(Object, ScopeObject)
 DeclMarker(Script, JSScript)
 DeclMarker(LazyScript, LazyScript)
 DeclMarker(Shape, Shape)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/sharedbuf/asm-link.js
@@ -0,0 +1,10 @@
+// Don't assert.
+function $(stdlib, foreign, heap) {
+    "use asm";
+    var Float64ArrayView = new stdlib.Float64Array(heap);
+    function f() {}
+    return f
+}
+
+if (typeof SharedArrayBuffer !== "undefined")
+    $(this, {}, new SharedArrayBuffer(4096));
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/sharedbuf/gc-one-view.js
@@ -0,0 +1,10 @@
+// Test tracing of a single linked ArrayBufferViewObject.
+
+function f() {
+    var x = new SharedArrayBuffer(0x1000);
+    var y = new Int32Array(x);
+    gc();
+}
+
+if (typeof SharedArrayBuffer !== "undefined")
+    f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/sharedbuf/gc-two-views.js
@@ -0,0 +1,11 @@
+// Test tracing of two views of a SharedArrayBuffer. Uses a different path.
+
+function f() {
+    var x = new SharedArrayBuffer(0x1000);
+    var y = new Int32Array(x);
+    var z = new Int8Array(x);
+    gc();
+}
+
+if (typeof SharedArrayBuffer !== "undefined")
+    f();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/sharedbuf/is-zeroed.js
@@ -0,0 +1,12 @@
+// Test that the SharedArrayBuffer memory is properly zeroed.
+
+function f() {
+    var x = new SharedArrayBuffer(4096);
+    var y = new Int32Array(x);
+    assertEq(y[0], 0);
+    assertEq(y[1], 0);
+    assertEq(y[1023], 0);
+}
+
+if (typeof SharedArrayBuffer !== "undefined")
+    f();
--- a/js/src/jit/AsmJS.h
+++ b/js/src/jit/AsmJS.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jit_AsmJS_h
 #define jit_AsmJS_h
 
 #include <stddef.h>
 
 #include "js/TypeDecls.h"
+#include "vm/ObjectImpl.h"
 
 namespace js {
 
 class ExclusiveContext;
 class AsmJSModule;
 class SPSProfiler;
 namespace frontend {
     template <typename ParseHandler> struct Parser;
@@ -86,17 +87,39 @@ RoundUpToNextValidAsmJSHeapLength(uint32
 extern bool
 IsValidAsmJSHeapLength(uint32_t length);
 
 #ifdef JS_CODEGEN_X64
 // On x64, the internal ArrayBuffer data array is inflated to 4GiB (only the
 // byteLength portion of which is accessible) so that out-of-bounds accesses
 // (made using a uint32 index) are guaranteed to raise a SIGSEGV.
 static const size_t AsmJSBufferProtectedSize = 4 * 1024ULL * 1024ULL * 1024ULL;
-#endif
+
+// To avoid dynamically checking bounds on each load/store, asm.js code relies
+// on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works
+// if we can guarantee that *any* out-of-bounds access generates a fault. This
+// isn't generally true since an out-of-bounds access could land on other
+// Mozilla data. To overcome this on x64, we reserve an entire 4GB space,
+// making only the range [0, byteLength) accessible, and use a 32-bit unsigned
+// index into this space. (x86 and ARM require different tricks.)
+//
+// One complication is that we need to put an ObjectElements struct immediately
+// before the data array (as required by the general JSObject data structure).
+// Thus, we must stick a page before the elements to hold ObjectElements.
+//
+//   |<------------------------------ 4GB + 1 pages --------------------->|
+//           |<--- sizeof --->|<------------------- 4GB ----------------->|
+//
+//   | waste | ObjectElements | data array | inaccessible reserved memory |
+//                            ^            ^                              ^
+//                            |            \                             /
+//                      obj->elements       required to be page boundaries
+//
+static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
+#endif // JS_CODEGEN_X64
 
 #ifdef JS_ION
 
 // Return whether asm.js optimization is inhibitted by the platform or
 // dynamically disabled:
 extern bool
 IsAsmJSCompilationAvailable(JSContext *cx, unsigned argc, JS::Value *vp);
 
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -219,16 +219,48 @@ ValidateConstant(JSContext *cx, AsmJSMod
         if (v.toNumber() != global.constantValue())
             return LinkFail(cx, "global constant value mismatch");
     }
 
     return true;
 }
 
 static bool
+LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handle<ArrayBufferObject*> heap)
+{
+    if (!IsValidAsmJSHeapLength(heap->byteLength())) {
+        ScopedJSFreePtr<char> msg(
+            JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
+                        "valid length is 0x%x",
+                        heap->byteLength(),
+                        RoundUpToNextValidAsmJSHeapLength(heap->byteLength())));
+        return LinkFail(cx, msg.get());
+    }
+
+    // This check is sufficient without considering the size of the loaded datum because heap
+    // loads and stores start on an aligned boundary and the heap byteLength has larger alignment.
+    JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX);
+    if (heap->byteLength() < module.minHeapLength()) {
+        ScopedJSFreePtr<char> msg(
+            JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the"
+                        "largest constant heap access offset rounded up to the next valid "
+                        "heap size).",
+                        heap->byteLength(),
+                        module.minHeapLength()));
+        return LinkFail(cx, msg.get());
+    }
+
+    if (!ArrayBufferObject::prepareForAsmJS(cx, heap))
+        return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use");
+
+    module.initHeap(heap, cx);
+    return true;
+}
+
+static bool
 DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module)
 {
     module.setIsDynamicallyLinked();
 
     RootedValue globalVal(cx);
     if (args.length() > 0)
         globalVal = args[0];
 
@@ -240,44 +272,19 @@ DynamicallyLinkModule(JSContext *cx, Cal
     if (args.length() > 2)
         bufferVal = args[2];
 
     Rooted<ArrayBufferObject*> heap(cx);
     if (module.hasArrayView()) {
         if (!IsTypedArrayBuffer(bufferVal))
             return LinkFail(cx, "bad ArrayBuffer argument");
 
-        heap = &bufferVal.toObject().as<ArrayBufferObject>();
-
-        if (!IsValidAsmJSHeapLength(heap->byteLength())) {
-            ScopedJSFreePtr<char> msg(
-                JS_smprintf("ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
-                            "valid length is 0x%x",
-                            heap->byteLength(),
-                            RoundUpToNextValidAsmJSHeapLength(heap->byteLength())));
-            return LinkFail(cx, msg.get());
-        }
-
-        // This check is sufficient without considering the size of the loaded datum because heap
-        // loads and stores start on an aligned boundary and the heap byteLength has larger alignment.
-        JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX);
-        if (heap->byteLength() < module.minHeapLength()) {
-            ScopedJSFreePtr<char> msg(
-                JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the"
-                            "largest constant heap access offset rounded up to the next valid "
-                            "heap size).",
-                            heap->byteLength(),
-                            module.minHeapLength()));
-            return LinkFail(cx, msg.get());
-        }
-
-        if (!ArrayBufferObject::prepareForAsmJS(cx, heap))
-            return LinkFail(cx, "Unable to prepare ArrayBuffer for asm.js use");
-
-        module.initHeap(heap, cx);
+        heap = &AsTypedArrayBuffer(bufferVal);
+        if (!LinkModuleToHeap(cx, module, heap))
+            return false;
     }
 
     AutoObjectVector ffis(cx);
     if (!ffis.resize(module.numFFIs()))
         return false;
 
     for (unsigned i = 0; i < module.numGlobals(); i++) {
         AsmJSModule::Global &global = module.global(i);
@@ -414,17 +421,16 @@ CallAsmJS(JSContext *cx, unsigned argc, 
         // pushed on a stack maintained by the runtime. This record is used for
         // to handle a variety of exceptional things that can happen in asm.js
         // code.
         AsmJSActivation activation(cx, module);
 
         // Eagerly push an IonContext+JitActivation so that the optimized
         // asm.js-to-Ion FFI call path (which we want to be very fast) can
         // avoid doing so.
-        jit::IonContext ictx(cx, nullptr);
         JitActivation jitActivation(cx, /* firstFrameIsConstructing = */ false, /* active */ false);
 
         // Call the per-exported-function trampoline created by GenerateEntry.
         AsmJSModule::CodePtr enter = module.entryTrampoline(func);
         if (!CALL_GENERATED_ASMJS(enter, coercedArgs.begin(), module.globalData()))
             return false;
     }
 
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -44,33 +44,34 @@ SnapshotIterator::SnapshotIterator(const
     ionScript_(iter.ionScript())
 {
 }
 
 void
 IonBailoutIterator::dump() const
 {
     if (type_ == IonFrame_OptimizedJS) {
-        InlineFrameIterator frames(GetIonContext()->cx, this);
+        InlineFrameIterator frames(GetJSContextFromJitCode(), this);
         for (;;) {
             frames.dump();
             if (!frames.more())
                 break;
             ++frames;
         }
     } else {
         IonFrameIterator::dump();
     }
 }
 
 uint32_t
 jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
 {
+    JSContext *cx = GetJSContextFromJitCode();
     JS_ASSERT(bailoutInfo);
-    JSContext *cx = GetIonContext()->cx;
+
     // We don't have an exit frame.
     cx->mainThread().ionTop = nullptr;
     JitActivationIterator jitActivations(cx->runtime());
     IonBailoutIterator iter(jitActivations, sp);
     JitActivation *activation = jitActivations.activation()->asJit();
 
     IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
 
@@ -90,17 +91,17 @@ jit::Bailout(BailoutStack *sp, BaselineB
 }
 
 uint32_t
 jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
                          BaselineBailoutInfo **bailoutInfo)
 {
     sp->checkInvariants();
 
-    JSContext *cx = GetIonContext()->cx;
+    JSContext *cx = GetJSContextFromJitCode();
 
     // We don't have an exit frame.
     cx->mainThread().ionTop = nullptr;
     JitActivationIterator jitActivations(cx->runtime());
     IonBailoutIterator iter(jitActivations, sp);
     JitActivation *activation = jitActivations.activation()->asJit();
 
     IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1411,17 +1411,17 @@ HandleBaselineInfoBailout(JSContext *cx,
     return Invalidate(cx, outerScript);
 }
 
 uint32_t
 jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
 {
     // The caller pushes R0 and R1 on the stack without rooting them.
     // Since GC here is very unlikely just suppress it.
-    JSContext *cx = GetIonContext()->cx;
+    JSContext *cx = GetJSContextFromJitCode();
     js::gc::AutoSuppressGC suppressGC(cx);
 
     IonSpew(IonSpew_BaselineBailouts, "  Done restoring frames");
 
     // Check that we can get the current script's PC.
 #ifdef DEBUG
     jsbytecode *pc;
     cx->currentScript(&pc);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -450,17 +450,17 @@ BaselineCompiler::emitIC(ICStub *stub, b
 typedef bool (*CheckOverRecursedWithExtraFn)(JSContext *, BaselineFrame *, uint32_t, uint32_t);
 static const VMFunction CheckOverRecursedWithExtraInfo =
     FunctionInfo<CheckOverRecursedWithExtraFn>(CheckOverRecursedWithExtra);
 
 bool
 BaselineCompiler::emitStackCheck(bool earlyCheck)
 {
     Label skipCall;
-    uintptr_t *limitAddr = &cx->runtime()->mainThread.ionStackLimit;
+    uintptr_t *limitAddr = &cx->runtime()->mainThread.jitStackLimit;
     uint32_t slotsSize = script->nslots() * sizeof(Value);
     uint32_t tolerance = earlyCheck ? slotsSize : 0;
 
     masm.movePtr(BaselineStackReg, R1.scratchReg());
 
     // If this is the early stack check, locals haven't been pushed yet.  Adjust the
     // stack pointer to account for the locals that would be pushed before performing
     // the guard around the vmcall to the stack check.
--- a/js/src/jit/BaselineFrame.cpp
+++ b/js/src/jit/BaselineFrame.cpp
@@ -178,17 +178,17 @@ BaselineFrame::initForOsr(StackFrame *fp
         BaselineFrame::Size() +
         numStackValues * sizeof(Value);
 
     JS_ASSERT(numValueSlots() == numStackValues);
 
     for (uint32_t i = 0; i < numStackValues; i++)
         *valueSlot(i) = fp->slots()[i];
 
-    JSContext *cx = GetIonContext()->cx;
+    JSContext *cx = GetJSContextFromJitCode();
     if (cx->compartment()->debugMode()) {
         // In debug mode, update any Debugger.Frame objects for the StackFrame to
         // point to the BaselineFrame.
 
         // The caller pushed a fake return address. ScriptFrameIter, used by the
         // debugger, wants a valid return address, but it's okay to just pick one.
         // In debug mode there's always at least 1 ICEntry (since there are always
         // debug prologue/epilogue calls).
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -572,16 +572,17 @@ ICStubCompiler::getStubCode()
 
     // Check for existing cached stubcode.
     uint32_t stubKey = getKey();
     JitCode *stubCode = comp->getStubCode(stubKey);
     if (stubCode)
         return stubCode;
 
     // Compile new stubcode.
+    IonContext ictx(cx, nullptr);
     MacroAssembler masm;
 #ifdef JS_CODEGEN_ARM
     masm.setSecondScratchReg(BaselineSecondScratchReg);
 #endif
 
     AutoFlushCache afc("ICStubCompiler::getStubCode", cx->runtime()->jitRuntime());
     if (!generateStubCode(masm))
         return nullptr;
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -103,17 +103,16 @@ EnterBaseline(JSContext *cx, EnterJitDat
     EnterJitCode enter = cx->runtime()->jitRuntime()->enterBaseline();
 
     // Caller must construct |this| before invoking the Ion function.
     JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
 
     data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
-        IonContext ictx(cx, nullptr);
         JitActivation activation(cx, data.constructing);
         JSAutoResolveFlags rf(cx, RESOLVE_INFER);
         AutoFlushInhibitor afi(cx->runtime()->jitRuntime());
 
         if (data.osrFrame)
             data.osrFrame->setRunningInJit();
 
         JS_ASSERT_IF(data.osrFrame, !IsJSDEnabled(cx));
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2736,17 +2736,17 @@ CodeGenerator::visitCheckOverRecursed(LC
     // crossed, an error must be thrown, which requires more frames.
     //
     // It must always be possible to trespass past the stack limit.
     // Ion may legally place frames very close to the limit. Calling additional
     // C functions may then violate the limit without any checking.
 
     // Since Ion frames exist on the C stack, the stack limit may be
     // dynamically set by JS_SetThreadStackLimit() and JS_SetNativeStackQuota().
-    const void *limitAddr = GetIonContext()->runtime->addressOfIonStackLimit();
+    const void *limitAddr = GetIonContext()->runtime->addressOfJitStackLimit();
 
     CheckOverRecursedFailure *ool = new(alloc()) CheckOverRecursedFailure(lir);
     if (!addOutOfLineCode(ool))
         return false;
 
     // Conditional forward (unlikely) branch to failure.
     masm.branchPtr(Assembler::AboveOrEqual, AbsoluteAddress(limitAddr), StackPointer, ool->entry());
     masm.bind(ool->rejoin());
@@ -2829,27 +2829,27 @@ class CheckOverRecursedFailurePar : publ
         return lir_;
     }
 };
 
 bool
 CodeGenerator::visitCheckOverRecursedPar(LCheckOverRecursedPar *lir)
 {
     // See above: unlike visitCheckOverRecursed(), this code runs in
-    // parallel mode and hence uses the ionStackLimit from the current
+    // parallel mode and hence uses the jitStackLimit from the current
     // thread state.  Also, we must check the interrupt flags because
     // on interrupt or abort, only the stack limit for the main thread
     // is reset, not the worker threads.  See comment in vm/ForkJoin.h
     // for more details.
 
     Register cxReg = ToRegister(lir->forkJoinContext());
     Register tempReg = ToRegister(lir->getTempReg());
 
     masm.loadPtr(Address(cxReg, offsetof(ForkJoinContext, perThreadData)), tempReg);
-    masm.loadPtr(Address(tempReg, offsetof(PerThreadData, ionStackLimit)), tempReg);
+    masm.loadPtr(Address(tempReg, offsetof(PerThreadData, jitStackLimit)), tempReg);
 
     // Conditional forward (unlikely) branch to failure.
     CheckOverRecursedFailurePar *ool = new(alloc()) CheckOverRecursedFailurePar(lir);
     if (!addOutOfLineCode(ool))
         return false;
     masm.branchPtr(Assembler::BelowOrEqual, StackPointer, tempReg, ool->entry());
     masm.checkInterruptFlagPar(tempReg, ool->entry());
     masm.bind(ool->rejoin());
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -29,25 +29,25 @@ CompileRuntime::onMainThread()
 
 const void *
 CompileRuntime::addressOfIonTop()
 {
     return &runtime()->mainThread.ionTop;
 }
 
 const void *
-CompileRuntime::addressOfIonStackLimit()
+CompileRuntime::addressOfJitStackLimit()
 {
-    return &runtime()->mainThread.ionStackLimit;
+    return &runtime()->mainThread.jitStackLimit;
 }
 
 const void *
 CompileRuntime::addressOfJSContext()
 {
-    return &runtime()->mainThread.ionJSContext;
+    return &runtime()->mainThread.jitJSContext;
 }
 
 const void *
 CompileRuntime::addressOfActivation()
 {
     return runtime()->mainThread.addressOfActivation();
 }
 
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -29,18 +29,18 @@ class CompileRuntime
   public:
     static CompileRuntime *get(JSRuntime *rt);
 
     bool onMainThread();
 
     // &mainThread.ionTop
     const void *addressOfIonTop();
 
-    // rt->mainThread.ionStackLimit;
-    const void *addressOfIonStackLimit();
+    // rt->mainThread.jitStackLimit;
+    const void *addressOfJitStackLimit();
 
     // &mainThread.ionJSContext
     const void *addressOfJSContext();
 
     // &mainThread.activation_
     const void *addressOfActivation();
 
     // &GetIonContext()->runtime->nativeIterCache.last
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -2222,17 +2222,16 @@ EnterIon(JSContext *cx, EnterJitData &da
     EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon();
 
     // Caller must construct |this| before invoking the Ion function.
     JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
 
     data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
-        IonContext ictx(cx, nullptr);
         JitActivation activation(cx, data.constructing);
         JSAutoResolveFlags rf(cx, RESOLVE_INFER);
         AutoFlushInhibitor afi(cx->runtime()->jitRuntime());
 
         CALL_GENERATED_CODE(enter, data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */nullptr, data.calleeToken,
                             /* scopeChain = */ nullptr, 0, data.result.address());
     }
 
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -566,17 +566,17 @@ HandleExceptionBaseline(JSContext *cx, c
         }
     }
 
 }
 
 void
 HandleException(ResumeFromException *rfe)
 {
-    JSContext *cx = GetIonContext()->cx;
+    JSContext *cx = GetJSContextFromJitCode();
 
     rfe->kind = ResumeFromException::RESUME_ENTRY_FRAME;
 
     IonSpew(IonSpew_Invalidate, "handling exception");
 
     // Clear any Ion return override that's been set.
     // This may happen if a callVM function causes an invalidation (setting the
     // override), and then fails, bypassing the bailout handlers that would
@@ -1646,17 +1646,17 @@ MachineState::FromBailout(mozilla::Array
 }
 
 template <AllowGC allowGC>
 bool
 InlineFrameIteratorMaybeGC<allowGC>::isConstructing() const
 {
     // Skip the current frame and look at the caller's.
     if (more()) {
-        InlineFrameIteratorMaybeGC<allowGC> parent(GetIonContext()->cx, this);
+        InlineFrameIteratorMaybeGC<allowGC> parent(GetJSContextFromJitCode(), this);
         ++parent;
 
         // Inlined Getters and Setters are never constructing.
         if (IsGetPropPC(parent.pc()) || IsSetPropPC(parent.pc()))
             return false;
 
         // In the case of a JS frame, look up the pc from the snapshot.
         JS_ASSERT(IsCallPC(parent.pc()));
@@ -1676,17 +1676,17 @@ IonFrameIterator::isConstructing() const
 
     // Skip the current frame and look at the caller's.
     do {
         ++parent;
     } while (!parent.done() && !parent.isScripted());
 
     if (parent.isOptimizedJS()) {
         // In the case of a JS frame, look up the pc from the snapshot.
-        InlineFrameIterator inlinedParent(GetIonContext()->cx, &parent);
+        InlineFrameIterator inlinedParent(GetJSContextFromJitCode(), &parent);
 
         //Inlined Getters and Setters are never constructing.
         if (IsGetPropPC(inlinedParent.pc()) || IsSetPropPC(inlinedParent.pc()))
             return false;
 
         JS_ASSERT(IsCallPC(inlinedParent.pc()));
 
         return (JSOp)*inlinedParent.pc() == JSOP_NEW;
@@ -1756,17 +1756,17 @@ IonFrameIterator::dumpBaseline() const
 #endif
     } else {
         fprintf(stderr, "  global frame, no callee\n");
     }
 
     fprintf(stderr, "  file %s line %u\n",
             script()->filename(), (unsigned) script()->lineno());
 
-    JSContext *cx = GetIonContext()->cx;
+    JSContext *cx = GetJSContextFromJitCode();
     RootedScript script(cx);
     jsbytecode *pc;
     baselineScriptAndPc(script.address(), &pc);
 
     fprintf(stderr, "  script = %p, pc = %p (offset %u)\n", (void *)script, pc, uint32_t(script->pcToOffset(pc)));
     fprintf(stderr, "  current op: %s\n", js_CodeName[*pc]);
 
     fprintf(stderr, "  actual args: %d\n", numActualArgs());
@@ -1824,17 +1824,17 @@ InlineFrameIteratorMaybeGC<allowGC>::dum
                 fprintf(stderr, "  scope chain: ");
             else if (i == 1)
                 fprintf(stderr, "  this: ");
             else if (i - 2 < callee()->nargs())
                 fprintf(stderr, "  formal (arg %d): ", i - 2);
             else {
                 if (i - 2 == callee()->nargs() && numActualArgs() > callee()->nargs()) {
                     DumpOp d(callee()->nargs());
-                    forEachCanonicalActualArg(GetIonContext()->cx, d, d.i_, numActualArgs() - d.i_);
+                    forEachCanonicalActualArg(GetJSContextFromJitCode(), d, d.i_, numActualArgs() - d.i_);
                 }
 
                 fprintf(stderr, "  slot %d: ", int(i - 2 - callee()->nargs()));
             }
         } else
             fprintf(stderr, "  slot %u: ", i);
 #ifdef DEBUG
         js_DumpValue(si.maybeRead());
@@ -1861,17 +1861,17 @@ IonFrameIterator::dump() const
         break;
       case IonFrame_BaselineStub:
       case IonFrame_Unwound_BaselineStub:
         fprintf(stderr, " Baseline stub frame\n");
         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
         break;
       case IonFrame_OptimizedJS:
       {
-        InlineFrameIterator frames(GetIonContext()->cx, this);
+        InlineFrameIterator frames(GetJSContextFromJitCode(), this);
         for (;;) {
             frames.dump();
             if (!frames.more())
                 break;
             ++frames;
         }
         break;
       }
--- a/js/src/jit/ParallelFunctions.cpp
+++ b/js/src/jit/ParallelFunctions.cpp
@@ -196,17 +196,17 @@ jit::CheckOverRecursedPar(ForkJoinContex
         return false;
     }
 #endif
 
     uintptr_t realStackLimit;
     if (cx->isMainThread())
         realStackLimit = GetNativeStackLimit(cx);
     else
-        realStackLimit = cx->perThreadData->ionStackLimit;
+        realStackLimit = cx->perThreadData->jitStackLimit;
 
     if (!JS_CHECK_STACK_SIZE(realStackLimit, &stackDummy_)) {
         cx->bailoutRecord->setCause(ParallelBailoutOverRecursed);
         return false;
     }
 
     return InterruptCheckPar(cx);
 }
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -104,24 +104,24 @@ NewGCObject(JSContext *cx, gc::AllocKind
 {
     return js::NewGCObject<CanGC>(cx, allocKind, 0, initialHeap);
 }
 
 bool
 CheckOverRecursed(JSContext *cx)
 {
     // IonMonkey's stackLimit is equal to nativeStackLimit by default. When we
-    // want to trigger an operation callback, we set the ionStackLimit to nullptr,
+    // want to trigger an operation callback, we set the jitStackLimit to nullptr,
     // which causes the stack limit check to fail.
     //
     // There are two states we're concerned about here:
     //   (1) The interrupt bit is set, and we need to fire the interrupt callback.
     //   (2) The stack limit has been exceeded, and we need to throw an error.
     //
-    // Note that we can reach here if ionStackLimit is MAXADDR, but interrupt
+    // Note that we can reach here if jitStackLimit is MAXADDR, but interrupt
     // has not yet been set to 1. That's okay; it will be set to 1 very shortly,
     // and in the interim we might just fire a few useless calls to
     // CheckOverRecursed.
 #ifdef JS_ARM_SIMULATOR
     JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, 0, return false);
 #else
     JS_CHECK_RECURSION(cx, return false);
 #endif
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -73,16 +73,17 @@
 #include "vm/DateObject.h"
 #include "vm/Debugger.h"
 #include "vm/ErrorObject.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/RegExpStatics.h"
 #include "vm/Runtime.h"
 #include "vm/Shape.h"
+#include "vm/SharedArrayObject.h"
 #include "vm/StopIterationObject.h"
 #include "vm/StringBuffer.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WeakMapObject.h"
 #include "vm/WrapperObject.h"
 #include "vm/Xdr.h"
 #include "yarr/BumpPointerAllocator.h"
 
@@ -2137,28 +2138,28 @@ js::RecomputeStackLimit(JSRuntime *rt, S
     } else {
         JS_ASSERT(rt->nativeStackBase >= stackSize);
         rt->mainThread.nativeStackLimit[kind] =
           rt->nativeStackBase - (stackSize - 1);
     }
 #endif
 
     // If there's no pending interrupt request set on the runtime's main thread's
-    // ionStackLimit, then update it so that it reflects the new nativeStacklimit.
+    // jitStackLimit, then update it so that it reflects the new nativeStacklimit.
     //
     // Note that, for now, we use the untrusted limit for ion. This is fine,
     // because it's the most conservative limit, and if we hit it, we'll bail
     // out of ion into the interpeter, which will do a proper recursion check.
 #ifdef JS_ION
     if (kind == StackForUntrustedScript) {
         JSRuntime::AutoLockForOperationCallback lock(rt);
-        if (rt->mainThread.ionStackLimit != uintptr_t(-1)) {
-            rt->mainThread.ionStackLimit = rt->mainThread.nativeStackLimit[kind];
+        if (rt->mainThread.jitStackLimit != uintptr_t(-1)) {
+            rt->mainThread.jitStackLimit = rt->mainThread.nativeStackLimit[kind];
 #ifdef JS_ARM_SIMULATOR
-            rt->mainThread.ionStackLimit = jit::Simulator::StackLimit();
+            rt->mainThread.jitStackLimit = jit::Simulator::StackLimit();
 #endif
         }
     }
 #endif
 }
 
 JS_PUBLIC_API(void)
 JS_SetNativeStackQuota(JSRuntime *rt, size_t systemCodeStackSize,
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1010,17 +1010,17 @@ js_InvokeOperationCallback(JSContext *cx
 
     // Reset the callback counter first, then run GC and yield. If another
     // thread is racing us here we will accumulate another callback request
     // which will be serviced at the next opportunity.
     rt->interrupt = false;
 
     // IonMonkey sets its stack limit to UINTPTR_MAX to trigger operation
     // callbacks.
-    rt->resetIonStackLimit();
+    rt->resetJitStackLimit();
 
     js::gc::GCIfNeeded(cx);
 
 #ifdef JS_ION
 #ifdef JS_THREADSAFE
     rt->interruptPar = false;
 #endif
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -25,16 +25,17 @@ struct JSCompartment;
 class JSFlatString;
 class JSLinearString;
 
 namespace js {
 
 class ArgumentsObject;
 class ArrayBufferObject;
 class ArrayBufferViewObject;
+class SharedArrayBufferObject;
 class BaseShape;
 class DebugScopeObject;
 class GCHelperThread;
 class GlobalObject;
 class LazyScript;
 class Nursery;
 class PropertyName;
 class ScopeObject;
@@ -127,16 +128,17 @@ MapAllocToTraceKind(AllocKind kind)
 
 template <typename T> struct MapTypeToTraceKind {};
 template <> struct MapTypeToTraceKind<ObjectImpl>       { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<JSObject>         { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<JSFunction>       { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ArgumentsObject>  { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ArrayBufferViewObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
+template <> struct MapTypeToTraceKind<SharedArrayBufferObject>{ static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<DebugScopeObject> { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<GlobalObject>     { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<ScopeObject>      { static const JSGCTraceKind kind = JSTRACE_OBJECT; };
 template <> struct MapTypeToTraceKind<JSScript>         { static const JSGCTraceKind kind = JSTRACE_SCRIPT; };
 template <> struct MapTypeToTraceKind<LazyScript>       { static const JSGCTraceKind kind = JSTRACE_LAZY_SCRIPT; };
 template <> struct MapTypeToTraceKind<Shape>            { static const JSGCTraceKind kind = JSTRACE_SHAPE; };
 template <> struct MapTypeToTraceKind<BaseShape>        { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
 template <> struct MapTypeToTraceKind<UnownedBaseShape> { static const JSGCTraceKind kind = JSTRACE_BASE_SHAPE; };
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -14,16 +14,17 @@
 #include "mozilla/PodOperations.h"
 
 #include "jsanalyze.h"
 
 #include "jit/ExecutionModeInlines.h"
 #include "vm/ArrayObject.h"
 #include "vm/BooleanObject.h"
 #include "vm/NumberObject.h"
+#include "vm/SharedArrayObject.h"
 #include "vm/StringObject.h"
 #include "vm/TypedArrayObject.h"
 
 #include "jscntxtinlines.h"
 
 namespace js {
 namespace types {
 
@@ -300,16 +301,19 @@ GetClassForProtoKey(JSProtoKey key)
       case JSProto_Float32Array:
       case JSProto_Float64Array:
       case JSProto_Uint8ClampedArray:
         return &TypedArrayObject::classes[key - JSProto_Int8Array];
 
       case JSProto_ArrayBuffer:
         return &ArrayBufferObject::class_;
 
+      case JSProto_SharedArrayBuffer:
+        return &SharedArrayBufferObject::class_;
+
       case JSProto_DataView:
         return &DataViewObject::class_;
 
       default:
         MOZ_ASSUME_UNREACHABLE("Bad proto key");
     }
 }
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1029,17 +1029,18 @@ ObjectClassIs(HandleObject obj, ESClassV
         return Proxy::objectClassIs(obj, classValue, cx);
 
     switch (classValue) {
       case ESClass_Array: return obj->is<ArrayObject>();
       case ESClass_Number: return obj->is<NumberObject>();
       case ESClass_String: return obj->is<StringObject>();
       case ESClass_Boolean: return obj->is<BooleanObject>();
       case ESClass_RegExp: return obj->is<RegExpObject>();
-      case ESClass_ArrayBuffer: return obj->is<ArrayBufferObject>();
+      case ESClass_ArrayBuffer:
+        return obj->is<ArrayBufferObject>() || obj->is<SharedArrayBufferObject>();
       case ESClass_Date: return obj->is<DateObject>();
     }
     MOZ_ASSUME_UNREACHABLE("bad classValue");
 }
 
 inline bool
 IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx)
 {
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -49,16 +49,22 @@
 #endif
 
 #ifdef ENABLE_BINARYDATA
 #define IF_BDATA(real,imaginary) real
 #else
 #define IF_BDATA(real,imaginary) imaginary
 #endif
 
+#ifdef ENABLE_SHARED_ARRAY_BUFFER
+#define IF_SAB(real,imaginary) real
+#else
+#define IF_SAB(real,imaginary) imaginary
+#endif
+
 #define JS_FOR_PROTOTYPES(real,imaginary) \
     imaginary(Null,              0,     js_InitNullClass,          dummy) \
     real(Object,                 1,     js_InitObjectClass,        &JSObject::class_) \
     real(Function,               2,     js_InitFunctionClass,      &JSFunction::class_) \
     real(Array,                  3,     js_InitArrayClass,         OCLASP(Array)) \
     real(Boolean,                4,     js_InitBooleanClass,       OCLASP(Boolean)) \
     real(JSON,                   5,     js_InitJSONClass,          CLASP(JSON)) \
     real(Date,                   6,     js_InitViaClassSpec,       OCLASP(Date)) \
@@ -86,16 +92,17 @@
     real(Float32Array,          28,     js_InitTypedArrayClasses,  TYPED_ARRAY_CLASP(TYPE_FLOAT32)) \
     real(Float64Array,          29,     js_InitTypedArrayClasses,  TYPED_ARRAY_CLASP(TYPE_FLOAT64)) \
     real(Uint8ClampedArray,     30,     js_InitTypedArrayClasses,  TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)) \
     real(Proxy,                 31,     js_InitProxyClass,         &ProxyObject::uncallableClass_) \
     real(WeakMap,               32,     js_InitWeakMapClass,       OCLASP(WeakMap)) \
     real(Map,                   33,     js_InitMapClass,           OCLASP(Map)) \
     real(Set,                   34,     js_InitSetClass,           OCLASP(Set)) \
     real(DataView,              35,     js_InitTypedArrayClasses,  OCLASP(DataView)) \
-IF_INTL(real,imaginary) (Intl,                  36,     js_InitIntlClass,          CLASP(Intl)) \
-IF_BDATA(real,imaginary)(TypedObject,           37,     js_InitTypedObjectModuleObject,   OCLASP(TypedObjectModule)) \
-    imaginary(GeneratorFunction,     38,     js_InitIteratorClasses, dummy) \
-IF_BDATA(real,imaginary)(SIMD,                  39,     js_InitSIMDClass, OCLASP(SIMD)) \
+IF_SAB(real,imaginary)(SharedArrayBuffer,       36,     js_InitSharedArrayBufferClass, &js::SharedArrayBufferObject::protoClass) \
+IF_INTL(real,imaginary) (Intl,                  37,     js_InitIntlClass,          CLASP(Intl)) \
+IF_BDATA(real,imaginary)(TypedObject,           38,     js_InitTypedObjectModuleObject,   OCLASP(TypedObjectModule)) \
+    imaginary(GeneratorFunction,     39,     js_InitIteratorClasses, dummy) \
+IF_BDATA(real,imaginary)(SIMD,                  40,     js_InitSIMDClass, OCLASP(SIMD)) \
 
 #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro)
 
 #endif /* jsprototypes_h */
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -176,16 +176,17 @@ UNIFIED_SOURCES += [
     'vm/PropertyKey.cpp',
     'vm/ProxyObject.cpp',
     'vm/RegExpObject.cpp',
     'vm/RegExpStatics.cpp',
     'vm/Runtime.cpp',
     'vm/ScopeObject.cpp',
     'vm/SelfHosting.cpp',
     'vm/Shape.cpp',
+    'vm/SharedArrayObject.cpp',
     'vm/SPSProfiler.cpp',
     'vm/Stack.cpp',
     'vm/String.cpp',
     'vm/StringBuffer.cpp',
     'vm/StructuredClone.cpp',
     'vm/ThreadPool.cpp',
     'vm/TypedArrayObject.cpp',
     'vm/Unicode.cpp',
@@ -422,16 +423,17 @@ if CONFIG['MOZ_ETW']:
         'ETWProvider.h',
     ]
     # This will get the ETW provider resources into the library mozjs.dll
     RESFILE = 'ETWProvider.res'
 
 if CONFIG['NIGHTLY_BUILD']:
     DEFINES['ENABLE_PARALLEL_JS'] = True
     DEFINES['ENABLE_BINARYDATA'] = True
+    DEFINES['ENABLE_SHARED_ARRAY_BUFFER'] = True
 
 DEFINES['EXPORT_JS_API'] = True
 
 if CONFIG['JS_THREADSAFE']:
     DEFINES['JS_THREADSAFE'] = True
 
 if CONFIG['JS_HAS_CTYPES']:
     DEFINES['JS_HAS_CTYPES'] = True
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -30,16 +30,17 @@
 
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
 #include "jit/AsmJS.h"
 #include "jit/AsmJSModule.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
+#include "vm/SharedArrayObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/Shape-inl.h"
 
@@ -166,16 +167,54 @@ const JSFunctionSpec ArrayBufferObject::
     JS_FS_END
 };
 
 const JSFunctionSpec ArrayBufferObject::jsstaticfuncs[] = {
     JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
     JS_FS_END
 };
 
+bool
+js::IsArrayBuffer(HandleValue v)
+{
+    return v.isObject() &&
+           (v.toObject().is<ArrayBufferObject>() ||
+            v.toObject().is<SharedArrayBufferObject>());
+}
+
+bool
+js::IsArrayBuffer(HandleObject obj)
+{
+    return obj->is<ArrayBufferObject>() || obj->is<SharedArrayBufferObject>();
+}
+
+bool
+js::IsArrayBuffer(JSObject *obj)
+{
+    return obj->is<ArrayBufferObject>() || obj->is<SharedArrayBufferObject>();
+}
+
+ArrayBufferObject &
+js::AsArrayBuffer(HandleObject obj)
+{
+    JS_ASSERT(IsArrayBuffer(obj));
+    if (obj->is<SharedArrayBufferObject>())
+        return obj->as<SharedArrayBufferObject>();
+    return obj->as<ArrayBufferObject>();
+}
+
+ArrayBufferObject &
+js::AsArrayBuffer(JSObject *obj)
+{
+    JS_ASSERT(IsArrayBuffer(obj));
+    if (obj->is<SharedArrayBufferObject>())
+        return obj->as<SharedArrayBufferObject>();
+    return obj->as<ArrayBufferObject>();
+}
+
 MOZ_ALWAYS_INLINE bool
 ArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsArrayBuffer(args.thisv()));
     args.rval().setInt32(args.thisv().toObject().as<ArrayBufferObject>().byteLength());
     return true;
 }
 
@@ -378,20 +417,28 @@ ArrayBufferObject::neuterViews(JSContext
                 prev = b;
             }
         }
     }
 
     return true;
 }
 
+uint8_t *
+ArrayBufferObject::dataPointer() const {
+    if (isSharedArrayBuffer())
+        return (uint8_t *)this->as<SharedArrayBufferObject>().dataPointer();
+    return (uint8_t *)elements;
+}
+
 void
 ArrayBufferObject::changeContents(JSContext *cx, ObjectElements *newHeader)
 {
     JS_ASSERT(!isAsmJSArrayBuffer());
+    JS_ASSERT(!isSharedArrayBuffer());
 
     // Grab out data before invalidating it.
     uint32_t byteLengthCopy = byteLength();
     uintptr_t oldDataPointer = uintptr_t(dataPointer());
     ArrayBufferViewObject *viewListHead = GetViewList(this);
 
     // Update all views.
     uintptr_t newDataPointer = uintptr_t(newHeader->elements());
@@ -433,16 +480,18 @@ ArrayBufferObject::changeContents(JSCont
 
     initElementsHeader(newHeader, byteLengthCopy);
     InitViewList(this, viewListHead);
 }
 
 void
 ArrayBufferObject::neuter(JSContext *cx)
 {
+    JS_ASSERT(!isSharedArrayBuffer());
+
     JS_ASSERT(cx);
     if (hasDynamicElements() && !isAsmJSArrayBuffer()) {
         ObjectElements *oldHeader = getElementsHeader();
         changeContents(cx, ObjectElements::fromElements(fixedElements()));
 
         FreeOp fop(cx->runtime(), false);
         fop.free_(oldHeader);
     }
@@ -451,61 +500,48 @@ ArrayBufferObject::neuter(JSContext *cx)
     updateElementsHeader(getElementsHeader(), byteLen);
 
     getElementsHeader()->setIsNeuteredBuffer();
 }
 
 /* static */ bool
 ArrayBufferObject::ensureNonInline(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
+    JS_ASSERT(!buffer->isSharedArrayBuffer());
     if (buffer->hasDynamicElements())
         return true;
 
     ObjectElements *newHeader = AllocateArrayBufferContents(cx, buffer->byteLength());
     if (!newHeader)
         return false;
 
     void *newHeaderDataPointer = reinterpret_cast<void*>(newHeader->elements());
     memcpy(newHeaderDataPointer, buffer->dataPointer(), buffer->byteLength());
 
     buffer->changeContents(cx, newHeader);
     return true;
 }
 
-#if defined(JS_ION) && defined(JS_CPU_X64)
-// To avoid dynamically checking bounds on each load/store, asm.js code relies
-// on the SIGSEGV handler in AsmJSSignalHandlers.cpp. However, this only works
-// if we can guarantee that *any* out-of-bounds access generates a fault. This
-// isn't generally true since an out-of-bounds access could land on other
-// Mozilla data. To overcome this on x64, we reserve an entire 4GB space,
-// making only the range [0, byteLength) accessible, and use a 32-bit unsigned
-// index into this space. (x86 and ARM require different tricks.)
-//
-// One complication is that we need to put an ObjectElements struct immediately
-// before the data array (as required by the general JSObject data structure).
-// Thus, we must stick a page before the elements to hold ObjectElements.
-//
-//   |<------------------------------ 4GB + 1 pages --------------------->|
-//           |<--- sizeof --->|<------------------- 4GB ----------------->|
-//
-//   | waste | ObjectElements | data array | inaccessible reserved memory |
-//                            ^            ^                              ^
-//                            |            \                             /
-//                      obj->elements       required to be page boundaries
-//
+#if defined(JS_CPU_X64)
+// Refer to comment above AsmJSMappedSize in AsmJS.h.
 JS_STATIC_ASSERT(sizeof(ObjectElements) < AsmJSPageSize);
 JS_STATIC_ASSERT(AsmJSAllocationGranularity == AsmJSPageSize);
-static const size_t AsmJSMappedSize = AsmJSPageSize + AsmJSBufferProtectedSize;
+#endif
 
+#if defined(JS_ION) && defined(JS_CPU_X64)
 bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
     if (buffer->isAsmJSArrayBuffer())
         return true;
 
+    // SharedArrayBuffers are already created with AsmJS support in mind.
+    if (buffer->isSharedArrayBuffer())
+        return true;
+
     // Get the entire reserved region (with all pages inaccessible).
     void *p;
 # ifdef XP_WIN
     p = VirtualAlloc(nullptr, AsmJSMappedSize, MEM_RESERVE, PAGE_NOACCESS);
     if (!p)
         return false;
 # else
     p = mmap(nullptr, AsmJSMappedSize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
@@ -561,16 +597,19 @@ ArrayBufferObject::releaseAsmJSArrayBuff
 }
 #else  /* defined(JS_ION) && defined(JS_CPU_X64) */
 bool
 ArrayBufferObject::prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer)
 {
     if (buffer->isAsmJSArrayBuffer())
         return true;
 
+    if (buffer->isSharedArrayBuffer())
+        return true;
+
     if (!ensureNonInline(cx, buffer))
         return false;
 
     JS_ASSERT(buffer->hasDynamicElements());
     buffer->getElementsHeader()->setIsAsmJSArrayBuffer();
     return true;
 }
 
@@ -579,16 +618,17 @@ ArrayBufferObject::releaseAsmJSArrayBuff
 {
     fop->free_(obj->as<ArrayBufferObject>().getElementsHeader());
 }
 #endif
 
 bool
 ArrayBufferObject::neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer)
 {
+    JS_ASSERT(!buffer.isSharedArrayBuffer());
 #ifdef JS_ION
     AsmJSActivation *act = cx->mainThread().asmJSActivationStackFromOwnerThread();
     for (; act; act = act->prev()) {
         if (act->module().maybeHeapBufferObject() == &buffer)
             break;
     }
     if (!act)
         return true;
@@ -654,24 +694,25 @@ ArrayBufferObject::create(JSContext *cx,
         if (!header)
             return nullptr;
         obj->elements = header->elements();
 
 #ifdef JSGC_GENERATIONAL
         JSRuntime *rt = obj->runtimeFromMainThread();
         rt->gcNursery.notifyNewElements(obj, header);
 #endif
+        obj->initElementsHeader(obj->getElementsHeader(), nbytes);
     } else {
+        // Elements header must be initialized before dataPointer() is callable.
         obj->setFixedElements();
+        obj->initElementsHeader(obj->getElementsHeader(), nbytes);
         if (clear)
             memset(obj->dataPointer(), 0, nbytes);
     }
 
-    obj->initElementsHeader(obj->getElementsHeader(), nbytes);
-
     return obj;
 }
 
 JSObject *
 ArrayBufferObject::createSlice(JSContext *cx, Handle<ArrayBufferObject*> arrayBuffer,
                                uint32_t begin, uint32_t end)
 {
     JS_ASSERT(begin <= arrayBuffer->byteLength());
@@ -786,17 +827,17 @@ ArrayBufferObject::obj_trace(JSTracer *t
     // performance cost.  Instead, ArrayBufferObjects with a single view hold a
     // strong pointer to the view. This can entrain garbage when the single
     // view becomes otherwise unreachable while the buffer is still live, but
     // this is expected to be rare. ArrayBufferObjects with 0-1 views are
     // expected to be by far the most common cases. ArrayBufferObjects with
     // multiple views are collected into a linked list during collection, and
     // then swept to prune out their dead views.
 
-    ArrayBufferObject &buffer = obj->as<ArrayBufferObject>();
+    ArrayBufferObject &buffer = AsArrayBuffer(obj);
     ArrayBufferViewObject *viewsHead = GetViewList(&buffer);
     if (!viewsHead)
         return;
 
     // During minor collections, mark weak pointers on the buffer strongly.
     if (trc->runtime->isHeapMinorCollecting()) {
         MarkObject(trc, &GetViewListRef(&buffer), "arraybuffer.viewlist");
         ArrayBufferViewObject *prior = GetViewList(&buffer);
@@ -821,17 +862,17 @@ ArrayBufferObject::obj_trace(JSTracer *t
         // Multiple views: do not mark, but append buffer to list.
         if (IS_GC_MARKING_TRACER(trc)) {
             // obj_trace may be called multiple times before sweep(), so avoid
             // adding this buffer to the list multiple times.
             if (firstView->bufferLink() == UNSET_BUFFER_LINK) {
                 JS_ASSERT(obj->compartment() == firstView->compartment());
                 ArrayBufferObject **bufList = &obj->compartment()->gcLiveArrayBuffers;
                 firstView->setBufferLink(*bufList);
-                *bufList = &obj->as<ArrayBufferObject>();
+                *bufList = &AsArrayBuffer(obj);
             } else {
 #ifdef DEBUG
                 bool found = false;
                 for (ArrayBufferObject *p = obj->compartment()->gcLiveArrayBuffers;
                      p;
                      p = GetViewList(p)->bufferLink())
                 {
                     if (p == obj)
@@ -1203,17 +1244,17 @@ ArrayBufferObject::obj_enumerate(JSConte
 ArrayBufferViewObject::trace(JSTracer *trc, JSObject *obj)
 {
     HeapSlot &bufSlot = obj->getReservedSlotRef(BUFFER_SLOT);
     MarkSlot(trc, &bufSlot, "typedarray.buffer");
 
     /* Update obj's data slot if the array buffer moved. Note that during
      * initialization, bufSlot may still be JSVAL_VOID. */
     if (bufSlot.isObject()) {
-        ArrayBufferObject &buf = bufSlot.toObject().as<ArrayBufferObject>();
+        ArrayBufferObject &buf = AsArrayBuffer(&bufSlot.toObject());
         if (buf.getElementsHeader()->isNeuteredBuffer()) {
             // When a view is neutered, it is set to NULL
             JS_ASSERT(obj->getPrivate() == nullptr);
         } else {
             int32_t offset = obj->getReservedSlot(BYTEOFFSET_SLOT).toInt32();
             obj->initPrivate(buf.dataPointer() + offset);
         }
     }
@@ -1252,36 +1293,36 @@ JS_IsArrayBufferViewObject(JSObject *obj
     obj = CheckedUnwrap(obj);
     return obj ? obj->is<ArrayBufferViewObject>() : false;
 }
 
 JS_FRIEND_API(uint32_t)
 JS_GetArrayBufferByteLength(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
-    return obj ? obj->as<ArrayBufferObject>().byteLength() : 0;
+    return obj ? AsArrayBuffer(obj).byteLength() : 0;
 }
 
 JS_FRIEND_API(uint8_t *)
 JS_GetArrayBufferData(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
-    return obj->as<ArrayBufferObject>().dataPointer();
+    return AsArrayBuffer(obj).dataPointer();
 }
 
 JS_FRIEND_API(uint8_t *)
 JS_GetStableArrayBufferData(JSContext *cx, JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
     if (!obj)
         return nullptr;
 
-    Rooted<ArrayBufferObject*> buffer(cx, &obj->as<ArrayBufferObject>());
+    Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(obj));
     if (!ArrayBufferObject::ensureNonInline(cx, buffer))
         return nullptr;
 
     return buffer->dataPointer();
 }
 
 JS_FRIEND_API(bool)
 JS_NeuterArrayBuffer(JSContext *cx, HandleObject obj)
@@ -1425,17 +1466,17 @@ JS_GetObjectAsArrayBufferView(JSObject *
     return obj;
 }
 
 JS_FRIEND_API(JSObject *)
 JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data)
 {
     if (!(obj = CheckedUnwrap(obj)))
         return nullptr;
-    if (!obj->is<ArrayBufferObject>())
+    if (!IsArrayBuffer(obj))
         return nullptr;
 
-    *length = obj->as<ArrayBufferObject>().byteLength();
-    *data = obj->as<ArrayBufferObject>().dataPointer();
+    *length = AsArrayBuffer(obj).byteLength();
+    *data = AsArrayBuffer(obj).dataPointer();
 
     return obj;
 }
 
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -18,16 +18,17 @@ namespace js {
 
 class ArrayBufferViewObject;
 
 // The inheritance hierarchy for the various classes relating to typed arrays
 // is as follows.
 //
 // - JSObject
 //   - ArrayBufferObject
+//     - SharedArrayBufferObject
 //   - ArrayBufferViewObject
 //     - DataViewObject
 //     - TypedArrayObject (declared in vm/TypedArrayObject.h)
 //       - TypedArrayObjectTemplate
 //         - Int8ArrayObject
 //         - Uint8ArrayObject
 //         - ...
 //     - TypedObject (declared in builtin/TypedObject.h)
@@ -180,34 +181,36 @@ class ArrayBufferObject : public JSObjec
         return getElementsHeader()->initializedLength;
     }
 
     /*
      * Neuter all views of an ArrayBuffer.
      */
     static bool neuterViews(JSContext *cx, Handle<ArrayBufferObject*> buffer);
 
-    inline uint8_t * dataPointer() const {
-        return (uint8_t *) elements;
-    }
+    uint8_t * dataPointer() const;
 
     /*
      * Discard the ArrayBuffer contents. For asm.js buffers, at least, should
      * be called after neuterViews().
      */
     void neuter(JSContext *cx);
 
     /*
      * Check if the arrayBuffer contains any data. This will return false for
      * ArrayBuffer.prototype and neutered ArrayBuffers.
      */
     bool hasData() const {
         return getClass() == &class_;
     }
 
+    bool isSharedArrayBuffer() const {
+        return getElementsHeader()->isSharedArrayBuffer();
+    }
+
     bool isAsmJSArrayBuffer() const {
         return getElementsHeader()->isAsmJSArrayBuffer();
     }
     bool isNeutered() const {
         return getElementsHeader()->isNeuteredBuffer();
     }
     static bool prepareForAsmJS(JSContext *cx, Handle<ArrayBufferObject*> buffer);
     static bool neuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &buffer);
@@ -287,21 +290,25 @@ InitArrayBufferViewDataPointer(ArrayBuff
      * N.B. The base of the array's data is stored in the object's
      * private data rather than a slot to avoid alignment restrictions
      * on private Values.
      */
     obj->initPrivate(buffer->dataPointer() + byteOffset);
     PostBarrierTypedArrayObject(obj);
 }
 
-MOZ_ALWAYS_INLINE bool
-IsArrayBuffer(HandleValue v)
-{
-    return v.isObject() && v.toObject().is<ArrayBufferObject>();
-}
+/*
+ * Tests for either ArrayBufferObject or SharedArrayBufferObject.
+ * For specific class testing, use e.g., obj->is<ArrayBufferObject>().
+ */
+bool IsArrayBuffer(HandleValue v);
+bool IsArrayBuffer(HandleObject obj);
+bool IsArrayBuffer(JSObject *obj);
+ArrayBufferObject &AsArrayBuffer(HandleObject obj);
+ArrayBufferObject &AsArrayBuffer(JSObject *obj);
 
 inline void
 ArrayBufferViewObject::setBufferLink(ArrayBufferObject *buffer)
 {
     setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(buffer));
     PostBarrierTypedArrayObject(this);
 }
 
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1463,17 +1463,17 @@ ForkJoinShared::executeFromWorker(uint32
     TlsPerThreadData.set(&thisThread);
 
 #ifdef JS_ARM_SIMULATOR
     stackLimit = Simulator::StackLimit();
 #endif
 
     // Don't use setIonStackLimit() because that acquires the ionStackLimitLock, and the
     // lock has not been initialized in these cases.
-    thisThread.ionStackLimit = stackLimit;
+    thisThread.jitStackLimit = stackLimit;
     executePortion(&thisThread, workerId);
     TlsPerThreadData.set(nullptr);
 
     return !abort_;
 }
 
 bool
 ForkJoinShared::executeFromMainThread()
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -21,16 +21,19 @@ extern JSObject *
 js_InitObjectClass(JSContext *cx, js::HandleObject obj);
 
 extern JSObject *
 js_InitFunctionClass(JSContext *cx, js::HandleObject obj);
 
 extern JSObject *
 js_InitTypedArrayClasses(JSContext *cx, js::HandleObject obj);
 
+extern JSObject *
+js_InitSharedArrayBufferClass(JSContext *cx, js::HandleObject obj);
+
 namespace js {
 
 class Debugger;
 class TypedObjectModuleObject;
 
 /*
  * Global object slots are reserved as follows:
  *
@@ -257,16 +260,19 @@ class GlobalObject : public JSObject
         return classIsInitialized(JSProto_String);
     }
     bool regexpClassInitialized() const {
         return classIsInitialized(JSProto_RegExp);
     }
     bool arrayBufferClassInitialized() const {
         return classIsInitialized(JSProto_ArrayBuffer);
     }
+    bool sharedArrayBufferClassInitialized() const {
+        return classIsInitialized(JSProto_SharedArrayBuffer);
+    }
     bool errorClassesInitialized() const {
         return classIsInitialized(JSProto_Error);
     }
     bool dataViewClassInitialized() const {
         return classIsInitialized(JSProto_DataView);
     }
     bool typedArrayClassesInitialized() const {
         // This alias exists only for clarity: in reality all the typed array
@@ -383,16 +389,22 @@ class GlobalObject : public JSObject
     }
 
     static JSObject *getOrCreateArrayBufferPrototype(JSContext *cx, Handle<GlobalObject*> global) {
         if (!ensureConstructor(cx, global, JSProto_ArrayBuffer))
             return nullptr;
         return &global->getPrototype(JSProto_ArrayBuffer).toObject();
     }
 
+    JSObject *getOrCreateSharedArrayBufferPrototype(JSContext *cx, Handle<GlobalObject*> global) {
+        if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer))
+            return nullptr;
+        return &global->getPrototype(JSProto_SharedArrayBuffer).toObject();
+    }
+
     static JSObject *getOrCreateCustomErrorPrototype(JSContext *cx,
                                                      Handle<GlobalObject*> global,
                                                      JSExnType exnType)
     {
         JSProtoKey key = GetExceptionProtoKey(exnType);
         if (!ensureConstructor(cx, global, key))
             return nullptr;
         return &global->getPrototype(key).toObject();
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -654,17 +654,16 @@ ReportIfNotFunction(JSContext *cx, Handl
 class FastInvokeGuard
 {
     InvokeArgs args_;
     RootedFunction fun_;
     RootedScript script_;
 #ifdef JS_ION
     // Constructing an IonContext is pretty expensive due to the TLS access,
     // so only do this if we have to.
-    mozilla::Maybe<jit::IonContext> ictx_;
     bool useIon_;
 #endif
 
   public:
     FastInvokeGuard(JSContext *cx, const Value &fval)
       : args_(cx)
       , fun_(cx)
       , script_(cx)
@@ -691,18 +690,16 @@ class FastInvokeGuard
     bool invoke(JSContext *cx) {
 #ifdef JS_ION
         if (useIon_ && fun_) {
             if (!script_) {
                 script_ = fun_->getOrCreateScript(cx);
                 if (!script_)
                     return false;
             }
-            if (ictx_.empty())
-                ictx_.construct(cx, (js::jit::TempAllocator *)nullptr);
             JS_ASSERT(fun_->nonLazyScript() == script_);
 
             jit::MethodStatus status = jit::CanEnterUsingFastInvoke(cx, script_, args_.length());
             if (status == jit::Method_Error)
                 return false;
             if (status == jit::Method_Compiled) {
                 jit::IonExecStatus result = jit::FastInvoke(cx, fun_, args_);
                 if (IsErrorStatus(result))
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -528,17 +528,19 @@ DenseElementsHeader::defineElement(JSCon
     obj->elements[index].set(obj->asObjectPtr(), HeapSlot::Element, index, desc.value());
     *succeeded = true;
     return true;
 }
 
 JSObject *
 js::ArrayBufferDelegate(JSContext *cx, Handle<ObjectImpl*> obj)
 {
-    MOZ_ASSERT(obj->hasClass(&ArrayBufferObject::class_));
+    MOZ_ASSERT(obj->hasClass(&ArrayBufferObject::class_) ||
+               obj->hasClass(&SharedArrayBufferObject::class_));
+
     if (obj->getPrivate())
         return static_cast<JSObject *>(obj->getPrivate());
     JSObject *delegate = NewObjectWithGivenProto(cx, &JSObject::class_,
                                                  obj->getTaggedProto(), nullptr);
     obj->setPrivateGCThing(delegate);
     return delegate;
 }
 
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -754,28 +754,30 @@ ArraySetLength(typename ExecutionModeTra
  */
 class ObjectElements
 {
   public:
     enum Flags {
         CONVERT_DOUBLE_ELEMENTS     = 0x1,
         ASMJS_ARRAY_BUFFER          = 0x2,
         NEUTERED_BUFFER             = 0x4,
+        SHARED_ARRAY_BUFFER         = 0x8,
 
         // Present only if these elements correspond to an array with
         // non-writable length; never present for non-arrays.
-        NONWRITABLE_ARRAY_LENGTH    = 0x8
+        NONWRITABLE_ARRAY_LENGTH    = 0x10
     };
 
   private:
     friend class ::JSObject;
     friend class ObjectImpl;
     friend class ArrayObject;
     friend class ArrayBufferObject;
     friend class ArrayBufferViewObject;
+    friend class SharedArrayBufferObject;
     friend class TypedArrayObject;
     friend class Nursery;
 
     template <ExecutionMode mode>
     friend bool
     ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
                    Handle<ArrayObject*> obj, HandleId id,
                    unsigned attrs, HandleValue value, bool setterIsStrict);
@@ -825,16 +827,22 @@ class ObjectElements
         flags |= ASMJS_ARRAY_BUFFER;
     }
     bool isNeuteredBuffer() const {
         return flags & NEUTERED_BUFFER;
     }
     void setIsNeuteredBuffer() {
         flags |= NEUTERED_BUFFER;
     }
+    bool isSharedArrayBuffer() const {
+        return flags & SHARED_ARRAY_BUFFER;
+    }
+    void setIsSharedArrayBuffer() {
+        flags |= SHARED_ARRAY_BUFFER;
+    }
     bool hasNonwritableArrayLength() const {
         return flags & NONWRITABLE_ARRAY_LENGTH;
     }
     void setNonwritableArrayLength() {
         flags |= NONWRITABLE_ARRAY_LENGTH;
     }
 
   public:
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -65,18 +65,18 @@ using JS::DoubleNaNValue;
 #endif
 
 const JSSecurityCallbacks js::NullSecurityCallbacks = { };
 
 PerThreadData::PerThreadData(JSRuntime *runtime)
   : PerThreadDataFriendFields(),
     runtime_(runtime),
     ionTop(nullptr),
-    ionJSContext(nullptr),
-    ionStackLimit(0),
+    jitJSContext(nullptr),
+    jitStackLimit(0),
     activation_(nullptr),
     asmJSActivationStack_(nullptr),
 #ifdef JS_ARM_SIMULATOR
     simulator_(nullptr),
     simulatorStackLimit_(0),
 #endif
     dtoaState(nullptr),
     suppressGC(0),
@@ -561,23 +561,23 @@ NewObjectCache::clearNurseryObjects(JSRu
             IsInsideNursery(rt, obj->elements))
         {
             PodZero(&e);
         }
     }
 }
 
 void
-JSRuntime::resetIonStackLimit()
+JSRuntime::resetJitStackLimit()
 {
     AutoLockForOperationCallback lock(this);
-    mainThread.setIonStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
+    mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
 
 #ifdef JS_ARM_SIMULATOR
-    mainThread.setIonStackLimit(js::jit::Simulator::StackLimit());
+    mainThread.setJitStackLimit(js::jit::Simulator::StackLimit());
 #endif
  }
 
 void
 JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
 {
     // Several tables in the runtime enumerated below can be used off thread.
     AutoLockForExclusiveAccess lock(this);
@@ -641,20 +641,20 @@ SignalBasedTriggersDisabled()
 void
 JSRuntime::triggerOperationCallback(OperationCallbackTrigger trigger)
 {
     AutoLockForOperationCallback lock(this);
 
     /*
      * Invalidate ionTop to trigger its over-recursion check. Note this must be
      * set before interrupt, to avoid racing with js_InvokeOperationCallback,
-     * into a weird state where interrupt is stuck at 0 but ionStackLimit is
+     * into a weird state where interrupt is stuck at 0 but jitStackLimit is
      * MAXADDR.
      */
-    mainThread.setIonStackLimit(-1);
+    mainThread.setJitStackLimit(-1);
 
     interrupt = true;
 
 #ifdef JS_ION
 #ifdef JS_THREADSAFE
     TriggerOperationCallbackForForkJoin(this, trigger);
 #endif
 
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -529,20 +529,31 @@ class PerThreadData : public PerThreadDa
     js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
 #endif
 
     /*
      * If Ion code is on the stack, and has called into C++, this will be
      * aligned to an Ion exit frame.
      */
     uint8_t             *ionTop;
-    JSContext           *ionJSContext;
-    uintptr_t            ionStackLimit;
+
+    /*
+     * The current JSContext when entering JIT code. This field may only be used
+     * from JIT code and C++ directly called by JIT code (otherwise it may refer
+     * to the wrong JSContext).
+     */
+    JSContext           *jitJSContext;
 
-    inline void setIonStackLimit(uintptr_t limit);
+    /*
+     * The stack limit checked by JIT code. This stack limit may be temporarily
+     * set to null to force JIT code to exit (e.g., for the operation callback).
+     */
+    uintptr_t            jitStackLimit;
+
+    inline void setJitStackLimit(uintptr_t limit);
 
     /*
      * asm.js maintains a stack of AsmJSModule activations (see AsmJS.h). This
      * stack is used by JSRuntime::triggerOperationCallback to stop long-
      * running asm.js without requiring dynamic polling operations in the
      * generated code. Since triggerOperationCallback may run on a separate
      * thread than the JSRuntime's owner thread all reads/writes must be
      * synchronized (by rt->operationCallbackLock).
@@ -1561,19 +1572,19 @@ struct JSRuntime : public JS::shadow::Ru
     }
 
 #ifdef DEBUG
     size_t              noGCOrAllocationCheck;
 #endif
 
     bool                jitSupportsFloatingPoint;
 
-    // Used to reset stack limit after a signaled interrupt (i.e. ionStackLimit_ = -1)
+    // Used to reset stack limit after a signaled interrupt (i.e. jitStackLimit_ = -1)
     // has been noticed by Ion/Baseline.
-    void resetIonStackLimit();
+    void resetJitStackLimit();
 
     // Cache for jit::GetPcScript().
     js::jit::PcScriptCache *ionPcScriptCache;
 
     js::ThreadPool threadPool;
 
     js::DefaultJSContextCallback defaultJSContextCallback;
 
@@ -1765,16 +1776,29 @@ struct JSRuntime : public JS::shadow::Ru
             return nullptr;
         largeAllocationFailureCallback();
         return onOutOfMemory(p, bytes);
     }
 };
 
 namespace js {
 
+// When entering JIT code, the calling JSContext* is stored into the thread's
+// PerThreadData. This function retrieves the JSContext with the pre-condition
+// that the caller is JIT code or C++ called directly from JIT code. This
+// function should not be called from arbitrary locations since the JSContext
+// may be the wrong one.
+static inline JSContext *
+GetJSContextFromJitCode()
+{
+    JSContext *cx = TlsPerThreadData.get()->jitJSContext;
+    JS_ASSERT(cx);
+    return cx;
+}
+
 /*
  * Flags accompany script version data so that a) dynamically created scripts
  * can inherit their caller's compile-time properties and b) scripts can be
  * appropriately compared in the eval cache across global option changes. An
  * example of the latter is enabling the top-level-anonymous-function-is-error
  * option: subsequent evals of the same, previously-valid script text may have
  * become invalid.
  */
@@ -1897,20 +1921,20 @@ class MOZ_STACK_CLASS AutoKeepAtoms
         if (JSRuntime *rt = pt->runtimeIfOnOwnerThread()) {
             JS_ASSERT(rt->keepAtoms_);
             rt->keepAtoms_--;
         }
     }
 };
 
 inline void
-PerThreadData::setIonStackLimit(uintptr_t limit)
+PerThreadData::setJitStackLimit(uintptr_t limit)
 {
     JS_ASSERT(runtime_->currentThreadOwnsOperationCallbackLock());
-    ionStackLimit = limit;
+    jitStackLimit = limit;
 }
 
 inline JSRuntime *
 PerThreadData::runtimeFromMainThread()
 {
     JS_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
     return runtime_;
 }
new file mode 100644
--- /dev/null
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -0,0 +1,387 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "vm/SharedArrayObject.h"
+
+#include "jsprf.h"
+#include "jsobjinlines.h"
+
+#ifdef XP_WIN
+# include "jswin.h"
+#else
+# include <sys/mman.h>
+#endif
+
+#include "mozilla/Atomics.h"
+#include "jit/AsmJS.h"
+
+using namespace js;
+
+using mozilla::IsNaN;
+using mozilla::PodCopy;
+
+#define SHAREDARRAYBUFFER_RESERVED_SLOTS 15
+
+/*
+ * SharedArrayRawBuffer
+ */
+
+static inline void *
+MapMemory(size_t length, bool commit)
+{
+#ifdef XP_WIN
+    int prot = (commit ? MEM_COMMIT : MEM_RESERVE);
+    int flags = (commit ? PAGE_READWRITE : PAGE_NOACCESS);
+    return VirtualAlloc(nullptr, length, prot, flags);
+#else
+    int prot = (commit ? (PROT_READ | PROT_WRITE) : PROT_NONE);
+    void *p = mmap(nullptr, length, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (p == MAP_FAILED)
+        return nullptr;
+    return p;
+#endif
+}
+
+static inline void
+UnmapMemory(void *addr, size_t len)
+{
+#ifdef XP_WIN
+    VirtualFree(addr, 0, MEM_RELEASE);
+#else
+    munmap(addr, len);
+#endif
+}
+
+static inline bool
+MarkValidRegion(void *addr, size_t len)
+{
+#ifdef XP_WIN
+    if (!VirtualAlloc(addr, len, MEM_COMMIT, PAGE_READWRITE))
+        return false;
+    return true;
+#else
+    if (mprotect(addr, len, PROT_READ | PROT_WRITE))
+        return false;
+    return true;
+#endif
+}
+
+SharedArrayRawBuffer *
+SharedArrayRawBuffer::New(uint32_t length)
+{
+    // Enforced by SharedArrayBufferObject constructor.
+    JS_ASSERT(IsValidAsmJSHeapLength(length));
+
+#ifdef JS_CPU_X64
+    // Get the entire reserved region (with all pages inaccessible)
+    void *p = MapMemory(AsmJSMappedSize, false);
+    if (!p)
+        return nullptr;
+
+    if (!MarkValidRegion(p, AsmJSPageSize + length)) {
+        UnmapMemory(p, AsmJSMappedSize);
+        return nullptr;
+    }
+
+    uint8_t *buffer = reinterpret_cast<uint8_t*>(p) + AsmJSPageSize;
+    uint8_t *base = buffer - sizeof(SharedArrayRawBuffer);
+    return new (base) SharedArrayRawBuffer(buffer, length);
+#else
+    uint32_t allocSize = sizeof(SharedArrayRawBuffer) + length;
+    if (allocSize <= length)
+        return nullptr;
+
+    void *base = MapMemory(allocSize, true);
+    if (!base)
+        return nullptr;
+
+    uint8_t *buffer = reinterpret_cast<uint8_t*>(base) + sizeof(SharedArrayRawBuffer);
+    return new (base) SharedArrayRawBuffer(buffer, length);
+#endif
+}
+
+void
+SharedArrayRawBuffer::addReference()
+{
+    JS_ASSERT(this->refcount > 0);
+    ++this->refcount; // Atomic.
+}
+
+void
+SharedArrayRawBuffer::dropReference()
+{
+    // Drop the reference to the buffer.
+    uint32_t refcount = --this->refcount; // Atomic.
+
+    // If this was the final reference, release the buffer.
+    if (refcount == 0) {
+#ifdef JS_CPU_X64
+        uint8_t *p = this->dataPointer() - AsmJSPageSize;
+        JS_ASSERT(uintptr_t(p) % AsmJSPageSize == 0);
+        UnmapMemory(p, AsmJSMappedSize);
+#else
+        uint8_t *p = (uint8_t *)this;
+        UnmapMemory(p, this->length);
+#endif
+    }
+}
+
+/*
+ * SharedArrayBufferObject
+ */
+bool
+js::IsSharedArrayBuffer(HandleValue v)
+{
+    return v.isObject() && v.toObject().is<SharedArrayBufferObject>();
+}
+
+MOZ_ALWAYS_INLINE bool
+SharedArrayBufferObject::byteLengthGetterImpl(JSContext *cx, CallArgs args)
+{
+    JS_ASSERT(IsSharedArrayBuffer(args.thisv()));
+    args.rval().setInt32(args.thisv().toObject().as<SharedArrayBufferObject>().byteLength());
+    return true;
+}
+
+bool
+SharedArrayBufferObject::byteLengthGetter(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsSharedArrayBuffer, byteLengthGetterImpl>(cx, args);
+}
+
+bool
+SharedArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
+{
+    int32_t length = 0;
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (argc > 0 && !ToInt32(cx, args[0], &length))
+        return false;
+
+    if (length < 0) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
+        return false;
+    }
+
+    JSObject *bufobj = New(cx, uint32_t(length));
+    if (!bufobj)
+        return false;
+    args.rval().setObject(*bufobj);
+    return true;
+}
+
+JSObject *
+SharedArrayBufferObject::New(JSContext *cx, uint32_t length)
+{
+    if (!IsValidAsmJSHeapLength(length)) {
+        ScopedJSFreePtr<char> msg(
+            JS_smprintf("SharedArrayBuffer byteLength 0x%x is not a valid length. The next valid "
+                        "length is 0x%x", length, RoundUpToNextValidAsmJSHeapLength(length)));
+        JS_ReportError(cx, msg.get());
+        return nullptr;
+    }
+
+    RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
+    if (!obj)
+        return nullptr;
+
+    JS_ASSERT(obj->getClass() == &class_);
+
+    Rooted<js::Shape*> empty(cx);
+    empty = EmptyShape::getInitialShape(cx, &class_, obj->getProto(), obj->getParent(),
+                                        obj->getMetadata(), gc::FINALIZE_OBJECT16_BACKGROUND);
+    if (!empty)
+        return nullptr;
+    obj->setLastPropertyInfallible(empty);
+
+    obj->setFixedElements();
+    obj->as<SharedArrayBufferObject>().initElementsHeader(obj->getElementsHeader(), length);
+    obj->getElementsHeader()->setIsSharedArrayBuffer();
+
+    SharedArrayRawBuffer *buffer = SharedArrayRawBuffer::New(length);
+    if (!buffer)
+        return nullptr;
+    obj->as<SharedArrayBufferObject>().acceptRawBuffer(buffer);
+
+    return obj;
+}
+
+JSObject *
+SharedArrayBufferObject::New(JSContext *cx, SharedArrayRawBuffer *buffer)
+{
+    RootedObject obj(cx, NewBuiltinClassInstance(cx, &class_));
+    if (!obj)
+        return nullptr;
+
+    JS_ASSERT(obj->getClass() == &class_);
+
+    Rooted<js::Shape*> empty(cx);
+    empty = EmptyShape::getInitialShape(cx, &class_, obj->getProto(), obj->getParent(),
+                                        obj->getMetadata(), gc::FINALIZE_OBJECT16_BACKGROUND);
+    if (!empty)
+        return nullptr;
+    obj->setLastPropertyInfallible(empty);
+
+    obj->setFixedElements();
+    obj->as<SharedArrayBufferObject>().initElementsHeader(obj->getElementsHeader(),
+                                                          buffer->byteLength());
+    obj->getElementsHeader()->setIsSharedArrayBuffer();
+
+    obj->as<SharedArrayBufferObject>().acceptRawBuffer(buffer);
+
+    return obj;
+}
+
+void
+SharedArrayBufferObject::acceptRawBuffer(SharedArrayRawBuffer *buffer)
+{
+    setReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT, PrivateValue(buffer));
+}
+
+void
+SharedArrayBufferObject::dropRawBuffer()
+{
+    setReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT, UndefinedValue());
+}
+
+SharedArrayRawBuffer *
+SharedArrayBufferObject::rawBufferObject() const
+{
+    // RAWBUF_SLOT must be populated via acceptRawBuffer(),
+    // and the raw buffer must not have been dropped.
+    Value v = getReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT);
+    return (SharedArrayRawBuffer *)v.toPrivate();
+}
+
+uint8_t *
+SharedArrayBufferObject::dataPointer() const
+{
+    return rawBufferObject()->dataPointer();
+}
+
+uint32_t
+SharedArrayBufferObject::byteLength() const
+{
+    return rawBufferObject()->byteLength();
+}
+
+void
+SharedArrayBufferObject::Finalize(FreeOp *fop, JSObject *obj)
+{
+    SharedArrayBufferObject &buf = obj->as<SharedArrayBufferObject>();
+
+    // Detect the case of failure during SharedArrayBufferObject creation,
+    // which causes a SharedArrayRawBuffer to never be attached.
+    Value v = buf.getReservedSlot(SharedArrayBufferObject::RAWBUF_SLOT);
+    if (!v.isUndefined()) {
+        buf.rawBufferObject()->dropReference();
+        buf.dropRawBuffer();
+    }
+}
+
+/*
+ * SharedArrayBufferObject
+ */
+
+const Class SharedArrayBufferObject::protoClass = {
+    "SharedArrayBufferPrototype",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_HAS_RESERVED_SLOTS(SHAREDARRAYBUFFER_RESERVED_SLOTS) |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
+    JS_PropertyStub,         /* addProperty */
+    JS_DeletePropertyStub,   /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub
+};
+
+const Class SharedArrayBufferObject::class_ = {
+    "SharedArrayBuffer",
+    JSCLASS_HAS_PRIVATE |
+    JSCLASS_IMPLEMENTS_BARRIERS |
+    Class::NON_NATIVE |
+    JSCLASS_HAS_RESERVED_SLOTS(SHAREDARRAYBUFFER_RESERVED_SLOTS) |
+    JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer),
+    JS_PropertyStub,         /* addProperty */
+    JS_DeletePropertyStub,   /* delProperty */
+    JS_PropertyStub,         /* getProperty */
+    JS_StrictPropertyStub,   /* setProperty */
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    SharedArrayBufferObject::Finalize,
+    nullptr,        /* call        */
+    nullptr,        /* hasInstance */
+    nullptr,        /* construct   */
+    ArrayBufferObject::obj_trace,
+    JS_NULL_CLASS_SPEC,
+    JS_NULL_CLASS_EXT,
+    {
+        ArrayBufferObject::obj_lookupGeneric,
+        ArrayBufferObject::obj_lookupProperty,
+        ArrayBufferObject::obj_lookupElement,
+        ArrayBufferObject::obj_lookupSpecial,
+        ArrayBufferObject::obj_defineGeneric,
+        ArrayBufferObject::obj_defineProperty,
+        ArrayBufferObject::obj_defineElement,
+        ArrayBufferObject::obj_defineSpecial,
+        ArrayBufferObject::obj_getGeneric,
+        ArrayBufferObject::obj_getProperty,
+        ArrayBufferObject::obj_getElement,
+        ArrayBufferObject::obj_getSpecial,
+        ArrayBufferObject::obj_setGeneric,
+        ArrayBufferObject::obj_setProperty,
+        ArrayBufferObject::obj_setElement,
+        ArrayBufferObject::obj_setSpecial,
+        ArrayBufferObject::obj_getGenericAttributes,
+        ArrayBufferObject::obj_setGenericAttributes,
+        ArrayBufferObject::obj_deleteProperty,
+        ArrayBufferObject::obj_deleteElement,
+        ArrayBufferObject::obj_deleteSpecial,
+        nullptr, nullptr, /* watch/unwatch */
+        nullptr,          /* slice */
+        ArrayBufferObject::obj_enumerate,
+        nullptr,          /* thisObject      */
+    }
+};
+
+JSObject *
+js_InitSharedArrayBufferClass(JSContext *cx, HandleObject obj)
+{
+    JS_ASSERT(obj->isNative());
+    Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
+    RootedObject proto(cx, global->createBlankPrototype(cx, &SharedArrayBufferObject::protoClass));
+    if (!proto)
+        return nullptr;
+
+    RootedFunction ctor(cx, global->createConstructor(cx, SharedArrayBufferObject::class_constructor,
+                                                      cx->names().SharedArrayBuffer, 1));
+    if (!ctor)
+        return nullptr;
+
+    if (!LinkConstructorAndPrototype(cx, ctor, proto))
+        return nullptr;
+
+    RootedId byteLengthId(cx, NameToId(cx->names().byteLength));
+    unsigned flags = JSPROP_SHARED | JSPROP_GETTER | JSPROP_PERMANENT;
+    JSObject *getter = NewFunction(cx, NullPtr(), SharedArrayBufferObject::byteLengthGetter, 0,
+                                   JSFunction::NATIVE_FUN, global, NullPtr());
+    if (!getter)
+        return nullptr;
+
+    RootedValue value(cx, UndefinedValue());
+    if (!DefineNativeProperty(cx, proto, byteLengthId, value,
+                              JS_DATA_TO_FUNC_PTR(PropertyOp, getter), nullptr, flags, 0, 0))
+    {
+        return nullptr;
+    }
+
+    if (!DefineConstructorAndPrototype(cx, global, JSProto_SharedArrayBuffer, ctor, proto))
+        return nullptr;
+    return proto;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/vm/SharedArrayObject.h
@@ -0,0 +1,105 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef vm_SharedArrayObject_h
+#define vm_SharedArrayObject_h
+
+#include "mozilla/Atomics.h"
+
+#include "jsapi.h"
+#include "jsobj.h"
+#include "jstypes.h"
+
+#include "gc/Barrier.h"
+#include "vm/ArrayBufferObject.h"
+
+typedef struct JSProperty JSProperty;
+
+namespace js {
+
+/*
+ * SharedArrayRawBuffer
+ *
+ * A bookkeeping object always stored immediately before the raw buffer.
+ * The buffer itself is mmap()'d and refcounted.
+ * SharedArrayBufferObjects and AsmJS code may hold references.
+ *
+ *           |<------ sizeof ------>|<- length ->|
+ *
+ *   | waste | SharedArrayRawBuffer | data array | waste |
+ */
+class SharedArrayRawBuffer
+{
+  private:
+    mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount;
+    uint32_t length;
+
+  protected:
+    SharedArrayRawBuffer(uint8_t *buffer, uint32_t length)
+      : refcount(1), length(length)
+    {
+        JS_ASSERT(buffer == dataPointer());
+    }
+
+  public:
+    static SharedArrayRawBuffer *New(uint32_t length);
+
+    inline uint8_t *dataPointer() const {
+        return ((uint8_t *)this) + sizeof(SharedArrayRawBuffer);
+    }
+
+    inline uint32_t byteLength() const {
+        return length;
+    }
+
+    void addReference();
+    void dropReference();
+};
+
+/*
+ * SharedArrayBufferObject
+ *
+ * When transferred to a WebWorker, the buffer is not neutered on the parent side,
+ * and both child and parent reference the same buffer.
+ */
+class SharedArrayBufferObject : public ArrayBufferObject
+{
+    static bool byteLengthGetterImpl(JSContext *cx, CallArgs args);
+
+  public:
+    static const Class class_;
+    static const Class protoClass;
+
+    // Slot used for storing a pointer to the SharedArrayRawBuffer.
+    // First two slots hold the ObjectElements.
+    static const int32_t RAWBUF_SLOT = 2;
+
+    static bool class_constructor(JSContext *cx, unsigned argc, Value *vp);
+
+    // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer.
+    static JSObject *New(JSContext *cx, uint32_t length);
+
+    // Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer.
+    static JSObject *New(JSContext *cx, SharedArrayRawBuffer *buffer);
+
+    static bool byteLengthGetter(JSContext *cx, unsigned argc, Value *vp);
+
+    static void Finalize(FreeOp *fop, JSObject *obj);
+
+    void acceptRawBuffer(SharedArrayRawBuffer *buffer);
+    void dropRawBuffer();
+
+    SharedArrayRawBuffer *rawBufferObject() const;
+    uint8_t *dataPointer() const;
+    uint32_t byteLength() const;
+};
+
+bool
+IsSharedArrayBuffer(HandleValue v);
+
+} // namespace js
+
+#endif // vm_SharedArrayObject_h
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1324,48 +1324,48 @@ js::CheckLocalUnaliased(MaybeCheckAliasi
 
 jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active)
   : Activation(cx, Jit),
     firstFrameIsConstructing_(firstFrameIsConstructing),
     active_(active)
 {
     if (active) {
         prevIonTop_ = cx->mainThread().ionTop;
-        prevIonJSContext_ = cx->mainThread().ionJSContext;
-        cx->mainThread().ionJSContext = cx;
+        prevJitJSContext_ = cx->mainThread().jitJSContext;
+        cx->mainThread().jitJSContext = cx;
     } else {
         prevIonTop_ = nullptr;
-        prevIonJSContext_ = nullptr;
+        prevJitJSContext_ = nullptr;
     }
 }
 
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         cx_->mainThread().ionTop = prevIonTop_;
-        cx_->mainThread().ionJSContext = prevIonJSContext_;
+        cx_->mainThread().jitJSContext = prevJitJSContext_;
     }
 }
 
 void
 jit::JitActivation::setActive(JSContext *cx, bool active)
 {
     // Only allowed to deactivate/activate if activation is top.
     // (Not tested and will probably fail in other situations.)
     JS_ASSERT(cx->mainThread().activation_ == this);
     JS_ASSERT(active != active_);
     active_ = active;
 
     if (active) {
         prevIonTop_ = cx->mainThread().ionTop;
-        prevIonJSContext_ = cx->mainThread().ionJSContext;
-        cx->mainThread().ionJSContext = cx;
+        prevJitJSContext_ = cx->mainThread().jitJSContext;
+        cx->mainThread().jitJSContext = cx;
     } else {
         cx->mainThread().ionTop = prevIonTop_;
-        cx->mainThread().ionJSContext = prevIonJSContext_;
+        cx->mainThread().jitJSContext = prevJitJSContext_;
     }
 }
 
 InterpreterFrameIterator &
 InterpreterFrameIterator::operator++()
 {
     JS_ASSERT(!done());
     if (fp_ != activation_->entryFrame_) {
@@ -1396,14 +1396,13 @@ ActivationIterator::operator++()
     activation_ = activation_->prev();
     settle();
     return *this;
 }
 
 void
 ActivationIterator::settle()
 {
-    while (!done() && activation_->isJit() && !activation_->asJit()->isActive()) {
-        if (activation_->asJit()->isActive())
-            jitTop_ = activation_->asJit()->prevIonTop();
+    // Stop at the next active activation. No need to update jitTop_, since
+    // we don't iterate over an active jit activation.
+    while (!done() && activation_->isJit() && !activation_->asJit()->isActive())
         activation_ = activation_->prev();
-    }
 }
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1300,17 +1300,17 @@ class ActivationIterator
 };
 
 namespace jit {
 
 // A JitActivation is used for frames running in Baseline or Ion.
 class JitActivation : public Activation
 {
     uint8_t *prevIonTop_;
-    JSContext *prevIonJSContext_;
+    JSContext *prevJitJSContext_;
     bool firstFrameIsConstructing_;
     bool active_;
 
 #ifdef CHECK_OSIPOINT_REGISTERS
   protected:
     // Used to verify that live registers don't change between a VM call and
     // the OsiPoint that follows it. Protected to silence Clang warning.
     uint32_t checkRegs_;
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -34,16 +34,17 @@
 
 #include <algorithm>
 
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jswrapper.h"
 
+#include "vm/SharedArrayObject.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jscntxtinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 
@@ -107,18 +108,21 @@ enum TransferableObjectType {
     SCTAG_TM_UNFILLED = 0,
 
     // Structured clone buffer does not yet own the data
     SCTAG_TM_UNOWNED = 1,
 
     // All values at least this large are owned by the clone buffer
     SCTAG_TM_FIRST_OWNED = 2,
 
+    // Data is a pointer to a SharedArrayRawBuffer.
+    SCTAG_TM_SHARED_BUFFER = 2,
+
     // Data is a pointer that can be freed
-    SCTAG_TM_ALLOC_DATA = 2,
+    SCTAG_TM_ALLOC_DATA = 3,
 };
 
 namespace js {
 
 struct SCOutput {
   public:
     explicit SCOutput(JSContext *cx);
     ~SCOutput();
@@ -331,19 +335,26 @@ ReadStructuredClone(JSContext *cx, uint6
     return r.read(vp.address());
 }
 
 // This may acquire new ways of discarding transfer map entries as new
 // Transferables are implemented.
 static void
 DiscardEntry(uint32_t mapEntryDescriptor, const uint64_t *ptr)
 {
-    JS_ASSERT(mapEntryDescriptor == SCTAG_TM_ALLOC_DATA);
-    uint64_t u = LittleEndian::readUint64(ptr);
-    js_free(reinterpret_cast<void*>(u));
+    if (mapEntryDescriptor == SCTAG_TM_ALLOC_DATA) {
+        uint64_t u = LittleEndian::readUint64(ptr);
+        js_free(reinterpret_cast<void*>(u));
+    } else {
+        JS_ASSERT(mapEntryDescriptor == SCTAG_TM_SHARED_BUFFER);
+        uint64_t u = LittleEndian::readUint64(ptr);
+        SharedArrayRawBuffer *raw = reinterpret_cast<SharedArrayRawBuffer *>(u);
+        if (raw)
+            raw->dropReference();
+    }
 }
 
 static void
 Discard(const uint64_t *begin, const uint64_t *end)
 {
     const uint64_t *point = begin;
     if (begin >= end)
         return; // Empty buffer
@@ -713,17 +724,17 @@ JSStructuredCloneWriter::parseTransferab
             return false;
         }
 
         JSObject* tObj = CheckedUnwrap(&v.toObject());
         if (!tObj) {
             JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED);
             return false;
         }
-        if (!tObj->is<ArrayBufferObject>()) {
+        if (!tObj->is<ArrayBufferObject>() && !tObj->is<SharedArrayBufferObject>()) {
             reportErrorTransferable();
             return false;
         }
 
         // No duplicates allowed
         if (std::find(transferableObjects.begin(), transferableObjects.end(), tObj) != transferableObjects.end()) {
             JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr, JSMSG_SC_DUP_TRANSFERABLE);
             return false;
@@ -949,32 +960,30 @@ JSStructuredCloneWriter::writeTransferMa
         return true;
 
     if (!out.writePair(SCTAG_TRANSFER_MAP_HEADER, (uint32_t)SCTAG_TM_UNREAD))
         return false;
 
     if (!out.write(transferableObjects.length()))
         return false;
 
-    for (JS::AutoObjectVector::Range tr = transferableObjects.all();
-         !tr.empty(); tr.popFront())
-    {
+    for (JS::AutoObjectVector::Range tr = transferableObjects.all(); !tr.empty(); tr.popFront()) {
         JSObject *obj = tr.front();
 
         if (!memory.put(obj, memory.count()))
             return false;
 
         // Emit a placeholder pointer. We will steal the data and neuter the
-        // transferable later.
-        if (!out.writePair(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_UNFILLED) ||
-            !out.writePtr(nullptr) ||
-            !out.write(0))
-        {
+        // transferable later, in the case of ArrayBufferObject.
+        if (!out.writePair(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_UNFILLED))
             return false;
-        }
+        if (!out.writePtr(nullptr)) // Pointer to ArrayBuffer contents or to SharedArrayRawBuffer.
+            return false;
+        if (!out.write(0)) // |userdata|, intended to be passed to callbacks.
+            return false;
     }
 
     return true;
 }
 
 bool
 JSStructuredCloneWriter::transferOwnership()
 {
@@ -985,30 +994,44 @@ JSStructuredCloneWriter::transferOwnersh
     // grabbing out pointers from the transferables and stuffing them into the
     // transfer map.
     uint64_t *point = out.rawBuffer();
     JS_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_HEADER);
     point++;
     JS_ASSERT(LittleEndian::readUint64(point) == transferableObjects.length());
     point++;
 
-    for (JS::AutoObjectVector::Range tr = transferableObjects.all();
-         !tr.empty();
-         tr.popFront())
-    {
+    for (JS::AutoObjectVector::Range tr = transferableObjects.all(); !tr.empty(); tr.popFront()) {
         RootedObject obj(context(), tr.front());
-        void *content;
-        uint8_t *data;
-        if (!JS_StealArrayBufferContents(context(), obj, &content, &data))
-            return false; // Destructor will clean up the already-transferred data
 
         MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point) >> 32) == SCTAG_TRANSFER_MAP_ENTRY);
-        LittleEndian::writeUint64(point++, PairToUInt64(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_ALLOC_DATA));
-        LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(content));
-        LittleEndian::writeUint64(point++, 0);
+        MOZ_ASSERT(uint32_t(LittleEndian::readUint64(point)) == SCTAG_TM_UNFILLED);
+
+        if (obj->is<ArrayBufferObject>()) {
+            void *content;
+            uint8_t *data;
+            if (!JS_StealArrayBufferContents(context(), obj, &content, &data))
+                return false; // Destructor will clean up the already-transferred data
+
+            uint64_t entryTag = PairToUInt64(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_ALLOC_DATA);
+            LittleEndian::writeUint64(point++, entryTag);
+            LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(content));
+            LittleEndian::writeUint64(point++, 0);
+        } else {
+            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();
+
+            uint64_t entryTag = PairToUInt64(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_SHARED_BUFFER);
+            LittleEndian::writeUint64(point++, entryTag);
+            LittleEndian::writeUint64(point++, reinterpret_cast<uint64_t>(rawbuf));
+            LittleEndian::writeUint64(point++, 0);
+        }
     }
 
     JS_ASSERT(point <= out.rawBuffer() + out.count());
     JS_ASSERT_IF(point < out.rawBuffer() + out.count(),
                  uint32_t(LittleEndian::readUint64(point) >> 32) != SCTAG_TRANSFER_MAP_ENTRY);
 
     return true;
 }
@@ -1478,27 +1501,33 @@ JSStructuredCloneReader::readTransferMap
         return false;
 
     for (uint64_t i = 0; i < numTransferables; i++) {
         uint64_t *pos = in.tell();
 
         if (!in.readPair(&tag, &data))
             return false;
         JS_ASSERT(tag == SCTAG_TRANSFER_MAP_ENTRY);
-        JS_ASSERT(data == SCTAG_TM_ALLOC_DATA);
+        JS_ASSERT(data == SCTAG_TM_ALLOC_DATA || data == SCTAG_TM_SHARED_BUFFER);
 
         void *content;
         if (!in.readPtr(&content))
             return false;
 
         uint64_t userdata;
         if (!in.read(&userdata))
             return false;
 
-        RootedObject obj(context(), JS_NewArrayBufferWithContents(context(), content));
+        RootedObject obj(context());
+
+        if (data == SCTAG_TM_ALLOC_DATA)
+            obj = JS_NewArrayBufferWithContents(context(), content);
+        else if (data == SCTAG_TM_SHARED_BUFFER)
+            obj = SharedArrayBufferObject::New(context(), (SharedArrayRawBuffer *)content);
+
         if (!obj)
             return false;
 
         // Rewind to the SCTAG_TRANSFER_MAP_ENTRY and mark this entry as unowned by
         // the input buffer.
         uint64_t *next = in.tell();
         in.seek(pos);
         MOZ_ALWAYS_TRUE(in.replacePair(SCTAG_TRANSFER_MAP_ENTRY, SCTAG_TM_UNOWNED));
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -27,19 +27,21 @@
 # include "jswin.h"
 #endif
 #include "jswrapper.h"
 
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
 #include "jit/AsmJS.h"
 #include "jit/AsmJSModule.h"
+#include "vm/ArrayBufferObject.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
+#include "vm/SharedArrayObject.h"
 #include "vm/WrapperObject.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/Shape-inl.h"
 
@@ -104,16 +106,22 @@ void
 TypedArrayObject::neuter(JSContext *cx)
 {
     setSlot(LENGTH_SLOT, Int32Value(0));
     setSlot(BYTELENGTH_SLOT, Int32Value(0));
     setSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(nullptr);
 }
 
+ArrayBufferObject *
+TypedArrayObject::sharedBuffer() const
+{
+    return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<SharedArrayBufferObject>();
+}
+
 bool
 TypedArrayObject::obj_lookupGeneric(JSContext *cx, HandleObject tarray, HandleId id,
                                     MutableHandleObject objp, MutableHandleShape propp)
 {
     if (tarray->as<TypedArrayObject>().isArrayIndex(id)) {
         MarkNonNativePropertyFound(propp);
         objp.set(tarray);
         return true;
@@ -607,17 +615,17 @@ class TypedArrayObjectTemplate : public 
         if (!obj)
             return nullptr;
         JS_ASSERT_IF(obj->isTenured(),
                      obj->tenuredGetAllocKind() == gc::FINALIZE_OBJECT8_BACKGROUND);
 
         obj->setSlot(TYPE_SLOT, Int32Value(ArrayTypeID()));
         obj->setSlot(BUFFER_SLOT, ObjectValue(*bufobj));
 
-        Rooted<ArrayBufferObject *> buffer(cx, &bufobj->as<ArrayBufferObject>());
+        Rooted<ArrayBufferObject *> buffer(cx, &AsArrayBuffer(bufobj));
 
         InitArrayBufferViewDataPointer(obj, buffer, byteOffset);
         obj->setSlot(LENGTH_SLOT, Int32Value(len));
         obj->setSlot(BYTEOFFSET_SLOT, Int32Value(byteOffset));
         obj->setSlot(BYTELENGTH_SLOT, Int32Value(len * sizeof(NativeType)));
         obj->setSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
         obj->setSlot(NEXT_BUFFER_SLOT, PrivateValue(UNSET_BUFFER_LINK));
 
@@ -696,18 +704,21 @@ class TypedArrayObjectTemplate : public 
         /*
          * (typedArray)
          * (type[] array)
          *
          * Otherwise create a new typed array and copy elements 0..len-1
          * properties from the object, treating it as some sort of array.
          * Note that offset and length will be ignored
          */
-        if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>())
+        if (!UncheckedUnwrap(dataObj)->is<ArrayBufferObject>() &&
+            !UncheckedUnwrap(dataObj)->is<SharedArrayBufferObject>())
+        {
             return fromArray(cx, dataObj);
+        }
 
         /* (ArrayBuffer, [byteOffset, [length]]) */
         int32_t byteOffset = 0;
         int32_t length = -1;
 
         if (args.length() > 1) {
             if (!ToInt32(cx, args[1], &byteOffset))
                 return nullptr;
@@ -969,17 +980,17 @@ class TypedArrayObjectTemplate : public 
     fromBuffer(JSContext *cx, HandleObject bufobj, uint32_t byteOffset, int32_t lengthInt,
                HandleObject proto)
     {
         if (!ObjectClassIs(bufobj, ESClass_ArrayBuffer, cx)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // must be arrayBuffer
         }
 
-        JS_ASSERT(bufobj->is<ArrayBufferObject>() || bufobj->is<ProxyObject>());
+        JS_ASSERT(IsArrayBuffer(bufobj) || bufobj->is<ProxyObject>());
         if (bufobj->is<ProxyObject>()) {
             /*
              * Normally, NonGenericMethodGuard handles the case of transparent
              * wrappers. However, we have a peculiar situation: we want to
              * construct the new typed array in the compartment of the buffer,
              * so that the typed array can point directly at their buffer's
              * data without crossing compartment boundaries. So we use the
              * machinery underlying NonGenericMethodGuard directly to proxy the
@@ -987,17 +998,17 @@ class TypedArrayObjectTemplate : public 
              * compartment for a view in the target compartment referencing the
              * ArrayBufferObject in that same compartment.
              */
             JSObject *wrapped = CheckedUnwrap(bufobj);
             if (!wrapped) {
                 JS_ReportError(cx, "Permission denied to access object");
                 return nullptr;
             }
-            if (wrapped->is<ArrayBufferObject>()) {
+            if (IsArrayBuffer(wrapped)) {
                 /*
                  * And for even more fun, the new view's prototype should be
                  * set to the origin compartment's prototype object, not the
                  * target's (specifically, the actual view in the target
                  * compartment will use as its prototype a wrapper around the
                  * origin compartment's view.prototype object).
                  *
                  * Rather than hack some crazy solution together, implement
@@ -1022,22 +1033,22 @@ class TypedArrayObjectTemplate : public 
                 args[2].setObject(*proto);
 
                 if (!Invoke(cx, args))
                     return nullptr;
                 return &args.rval().toObject();
             }
         }
 
-        if (!bufobj->is<ArrayBufferObject>()) {
+        if (!IsArrayBuffer(bufobj)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // must be arrayBuffer
         }
 
-        ArrayBufferObject &buffer = bufobj->as<ArrayBufferObject>();
+        ArrayBufferObject &buffer = AsArrayBuffer(bufobj);
 
         if (byteOffset > buffer.byteLength() || byteOffset % sizeof(NativeType) != 0) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
             return nullptr; // invalid byteOffset
         }
 
         uint32_t len;
         if (lengthInt == -1) {
@@ -1620,31 +1631,31 @@ DataViewObject::create(JSContext *cx, ui
     dvobj.setFixedSlot(NEXT_VIEW_SLOT, PrivateValue(nullptr));
     dvobj.setFixedSlot(NEXT_BUFFER_SLOT, PrivateValue(UNSET_BUFFER_LINK));
     InitArrayBufferViewDataPointer(&dvobj, arrayBuffer, byteOffset);
     JS_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength());
 
     // Verify that the private slot is at the expected place
     JS_ASSERT(dvobj.numFixedSlots() == DATA_SLOT);
 
-    arrayBuffer->as<ArrayBufferObject>().addView(&dvobj);
+    arrayBuffer->addView(&dvobj);
 
     return &dvobj;
 }
 
 bool
 DataViewObject::construct(JSContext *cx, JSObject *bufobj, const CallArgs &args, HandleObject proto)
 {
-    if (!bufobj->is<ArrayBufferObject>()) {
+    if (!IsArrayBuffer(bufobj)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
                              "DataView", "ArrayBuffer", bufobj->getClass()->name);
         return false;
     }
 
-    Rooted<ArrayBufferObject*> buffer(cx, &bufobj->as<ArrayBufferObject>());
+    Rooted<ArrayBufferObject*> buffer(cx, &AsArrayBuffer(bufobj));
     uint32_t bufferLength = buffer->byteLength();
     uint32_t byteOffset = 0;
     uint32_t byteLength = bufferLength;
 
     if (args.length() > 1) {
         if (!ToUint32(cx, args[1], &byteOffset))
             return false;
         if (byteOffset > INT32_MAX) {
@@ -1692,17 +1703,17 @@ bool
 DataViewObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     RootedObject bufobj(cx);
     if (!GetFirstArgumentAsObject(cx, args, "DataView constructor", &bufobj))
         return false;
 
-    if (bufobj->is<WrapperObject>() && UncheckedUnwrap(bufobj)->is<ArrayBufferObject>()) {
+    if (bufobj->is<WrapperObject>() && IsArrayBuffer(UncheckedUnwrap(bufobj))) {
         Rooted<GlobalObject*> global(cx, cx->compartment()->maybeGlobal());
         Rooted<JSObject*> proto(cx, global->getOrCreateDataViewPrototype(cx));
         if (!proto)
             return false;
 
         InvokeArgs args2(cx);
         if (!args2.init(args.length() + 1))
             return false;
@@ -2752,17 +2763,28 @@ js::IsTypedArrayConstructor(HandleValue 
         return IsNativeFunction(v, Uint8ClampedArrayObject::class_constructor);
     }
     MOZ_ASSUME_UNREACHABLE("unexpected typed array type");
 }
 
 bool
 js::IsTypedArrayBuffer(HandleValue v)
 {
-    return v.isObject() && v.toObject().is<ArrayBufferObject>();
+    return v.isObject() &&
+           (v.toObject().is<ArrayBufferObject>() ||
+            v.toObject().is<SharedArrayBufferObject>());
+}
+
+ArrayBufferObject &
+js::AsTypedArrayBuffer(HandleValue v)
+{
+    JS_ASSERT(IsTypedArrayBuffer(v));
+    if (v.toObject().is<ArrayBufferObject>())
+        return v.toObject().as<ArrayBufferObject>();
+    return v.toObject().as<SharedArrayBufferObject>();
 }
 
 /* JS Friend API */
 
 JS_FRIEND_API(bool)
 JS_IsTypedArrayObject(JSObject *obj)
 {
     obj = CheckedUnwrap(obj);
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -62,18 +62,22 @@ class TypedArrayObject : public ArrayBuf
     }
     static Value byteLengthValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BYTELENGTH_SLOT);
     }
     static Value lengthValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(LENGTH_SLOT);
     }
 
+    ArrayBufferObject *sharedBuffer() const;
     ArrayBufferObject *buffer() const {
-        return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<ArrayBufferObject>();
+        JSObject &obj = bufferValue(const_cast<TypedArrayObject*>(this)).toObject();
+        if (obj.is<ArrayBufferObject>())
+            return &obj.as<ArrayBufferObject>();
+        return sharedBuffer();
     }
     uint32_t byteOffset() const {
         return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
     uint32_t byteLength() const {
         return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
     uint32_t length() const {
@@ -141,16 +145,19 @@ IsTypedArrayProtoClass(const Class *clas
 }
 
 bool
 IsTypedArrayConstructor(HandleValue v, uint32_t type);
 
 bool
 IsTypedArrayBuffer(HandleValue v);
 
+ArrayBufferObject &
+AsTypedArrayBuffer(HandleValue v);
+
 static inline unsigned
 TypedArrayShift(ArrayBufferView::ViewType viewType)
 {
     switch (viewType) {
       case ArrayBufferView::TYPE_INT8:
       case ArrayBufferView::TYPE_UINT8:
       case ArrayBufferView::TYPE_UINT8_CLAMPED:
         return 0;
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -587,17 +587,18 @@ nsDocumentViewer::SyncParentSubDocMap()
       nsCOMPtr<nsIDOMDocument> dom_doc;
       parent_win->GetDocument(getter_AddRefs(dom_doc));
 
       nsCOMPtr<nsIDocument> parent_doc(do_QueryInterface(dom_doc));
 
       if (parent_doc) {
         if (mDocument &&
             parent_doc->GetSubDocumentFor(content) != mDocument) {
-          mDocument->SuppressEventHandling(parent_doc->EventHandlingSuppressed());
+          mDocument->SuppressEventHandling(nsIDocument::eEvents,
+                                           parent_doc->EventHandlingSuppressed());
         }
         return parent_doc->SetSubDocumentFor(content->AsElement(), mDocument);
       }
     }
   }
 
   return NS_OK;
 }
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -297,17 +297,17 @@ nsPresContext::nsPresContext(nsIDocument
     mNeverAnimate = false;
   }
   NS_ASSERTION(mDocument, "Null document");
   mUserFontSet = nullptr;
   mUserFontSetDirty = true;
 
   // if text perf logging enabled, init stats struct
   PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
-  if (log && PR_LOG_TEST(log, PR_LOG_WARNING)) {
+  if (log && log->level >= PR_LOG_WARNING) {
     mTextPerf = new gfxTextPerfMetrics();
   }
 
   PR_INIT_CLIST(&mDOMMediaQueryLists);
 }
 
 nsPresContext::~nsPresContext()
 {
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -683,16 +683,17 @@ nsIPresShell::FrameSelection()
   nsRefPtr<nsFrameSelection> ret = mSelection;
   return ret.forget();
 }
 
 //----------------------------------------------------------------------
 
 static bool sSynthMouseMove = true;
 static uint32_t sNextPresShellId;
+static bool sPointerEventEnabled = true;
 
 PresShell::PresShell()
   : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
 {
   mSelection = nullptr;
 #ifdef MOZ_REFLOW_PERF
   mReflowCountMgr = new ReflowCountMgr();
   mReflowCountMgr->SetPresContext(mPresContext);
@@ -731,16 +732,22 @@ PresShell::PresShell()
   mMaxLineBoxWidth = 0;
 
   static bool addedSynthMouseMove = false;
   if (!addedSynthMouseMove) {
     Preferences::AddBoolVarCache(&sSynthMouseMove,
                                  "layout.reflow.synthMouseMove", true);
     addedSynthMouseMove = true;
   }
+  static bool addedPointerEventEnabled = false;
+  if (addedPointerEventEnabled) {
+    Preferences::AddBoolVarCache(&sPointerEventEnabled,
+                                 "dom.w3c_pointer_events.enabled", true);
+    addedPointerEventEnabled = true;
+  }
 
   mPaintingIsFrozen = false;
 }
 
 NS_IMPL_ISUPPORTS7(PresShell, nsIPresShell, nsIDocumentObserver,
                    nsISelectionController,
                    nsISelectionDisplay, nsIObserver, nsISupportsWeakReference,
                    nsIMutationObserver)
@@ -6294,22 +6301,112 @@ FlushThrottledStyles(nsIDocument *aDocum
       presContext->TransitionManager()->UpdateAllThrottledStyles();
       presContext->AnimationManager()->UpdateAllThrottledStyles();
     }
   }
 
   return true;
 }
 
+static nsresult
+DispatchPointerFromMouseOrTouch(PresShell* aShell,
+                                nsIFrame* aFrame,
+                                WidgetGUIEvent* aEvent,
+                                bool aDontRetargetEvents,
+                                nsEventStatus* aStatus)
+{
+  uint32_t pointerMessage = 0;
+  if (aEvent->eventStructType == NS_MOUSE_EVENT) {
+    WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
+    // if it is not mouse then it is likely will come as touch event
+    if (!mouseEvent->convertToPointer) {
+      return NS_OK;
+    }
+    int16_t button = mouseEvent->button;
+    switch (mouseEvent->message) {
+    case NS_MOUSE_MOVE:
+      if (mouseEvent->buttons == 0) {
+        button = -1;
+      }
+      pointerMessage = NS_POINTER_MOVE;
+      break;
+    case NS_MOUSE_BUTTON_UP:
+      pointerMessage = NS_POINTER_UP;
+      break;
+    case NS_MOUSE_BUTTON_DOWN:
+      pointerMessage = NS_POINTER_DOWN;
+      break;
+    default:
+      return NS_OK;
+    }
+
+    WidgetPointerEvent event(*mouseEvent);
+    event.message = pointerMessage;
+    event.button = button;
+    event.convertToPointer = mouseEvent->convertToPointer = false;
+    aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
+  } else if (aEvent->eventStructType == NS_TOUCH_EVENT) {
+    WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
+    // loop over all touches and dispatch pointer events on each touch
+    // copy the event
+    switch (touchEvent->message) {
+    case NS_TOUCH_MOVE:
+      pointerMessage = NS_POINTER_MOVE;
+      break;
+    case NS_TOUCH_END:
+      pointerMessage = NS_POINTER_UP;
+      break;
+    case NS_TOUCH_START:
+      pointerMessage = NS_POINTER_DOWN;
+      break;
+    case NS_TOUCH_CANCEL:
+      pointerMessage = NS_POINTER_CANCEL;
+      break;
+    default:
+      return NS_OK;
+    }
+
+    for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) {
+      mozilla::dom::Touch* touch = touchEvent->touches[i];
+      if (!touch || !touch->convertToPointer) {
+        continue;
+      }
+
+      WidgetPointerEvent event(touchEvent->mFlags.mIsTrusted, pointerMessage, touchEvent->widget);
+      event.isPrimary = i == 0;
+      event.pointerId = touch->Identifier();
+      event.refPoint.x = touch->mRefPoint.x;
+      event.refPoint.y = touch->mRefPoint.y;
+      event.modifiers = touchEvent->modifiers;
+      event.width = touch->RadiusX();
+      event.height = touch->RadiusY();
+      event.tiltX = touch->tiltX;
+      event.tiltY = touch->tiltY;
+      event.time = touchEvent->time;
+      event.mFlags = touchEvent->mFlags;
+      event.button = WidgetMouseEvent::eLeftButton;
+      event.buttons = WidgetMouseEvent::eLeftButtonFlag;
+      event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
+      event.convertToPointer = touch->convertToPointer = false;
+      aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus);
+    }
+  }
+  return NS_OK;
+}
+
 nsresult
 PresShell::HandleEvent(nsIFrame* aFrame,
                        WidgetGUIEvent* aEvent,
                        bool aDontRetargetEvents,
                        nsEventStatus* aEventStatus)
 {
+  if (sPointerEventEnabled) {
+    DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents, aEventStatus);
+  }
+
   NS_ASSERTION(aFrame, "null frame");
 
   if (mIsDestroying ||
       (sDisableNonTestMouseEvents && !aEvent->mFlags.mIsSynthesizedForTests &&
        aEvent->HasMouseEventMessage())) {
     return NS_OK;
   }
 
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug970964_inner.html
@@ -0,0 +1,326 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=970964
+-->
+<head>
+  <title>Test for Bug 970964</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=970964">Mozilla Bug 970964</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 970964 **/
+
+function ok(condition, msg) {
+  parent.ok(condition, msg);
+}
+
+function is(a, b, msg) {
+  parent.is(a, b, msg);
+}
+
+function testtouch(aOptions) {
+  if (!aOptions)
+    aOptions = {};
+  this.identifier = aOptions.identifier || 0;
+  this.target = aOptions.target || 0;
+  this.page = aOptions.page || {x: 0, y: 0};
+  this.radius = aOptions.radius || {x: 0, y: 0};
+  this.rotationAngle = aOptions.rotationAngle || 0;
+  this.force = aOptions.force || 1;
+}
+
+function touchEvent(aOptions) {
+  if (!aOptions) {
+    aOptions = {};
+  }
+  this.ctrlKey = aOptions.ctrlKey || false;
+  this.altKey = aOptions.altKey || false;
+  this.shiftKey = aOptions.shiftKey || false;
+  this.metaKey = aOptions.metaKey || false;
+  this.touches = aOptions.touches || [];
+  this.targetTouches = aOptions.targetTouches || [];
+  this.changedTouches = aOptions.changedTouches || [];
+}
+
+function sendTouchEvent(windowUtils, aType, aEvent, aModifiers) {
+  var ids = [], xs=[], ys=[], rxs = [], rys = [],
+      rotations = [], forces = [];
+
+  for (var touchType of ["touches", "changedTouches", "targetTouches"]) {
+    for (var i = 0; i < aEvent[touchType].length; i++) {
+      if (ids.indexOf(aEvent[touchType][i].identifier) == -1) {
+        ids.push(aEvent[touchType][i].identifier);
+        xs.push(aEvent[touchType][i].page.x);
+        ys.push(aEvent[touchType][i].page.y);
+        rxs.push(aEvent[touchType][i].radius.x);
+        rys.push(aEvent[touchType][i].radius.y);
+        rotations.push(aEvent[touchType][i].rotationAngle);
+        forces.push(aEvent[touchType][i].force);
+      }
+    }
+  }
+  return windowUtils.sendTouchEvent(aType,
+                                    ids, xs, ys, rxs, rys,
+                                    rotations, forces,
+                                    ids.length, aModifiers, 0);
+}
+
+function getDefaultArgEvent(eventname) {
+  return new PointerEvent(eventname, {
+    bubbles: true, cancelable: true, view: window,
+    detail: 0, screenX: 0, screenY: 0, clientX: 0, clientY: 0,
+    ctrlKey: false, altKey: false, shiftKey: false, metaKey: false,
+    button: 0, relatedTarget: null, pointerId: 0
+  });
+}
+
+function getTouchEventForTarget(target, cwu, id) {
+  var bcr = target.getBoundingClientRect();
+  var touch = new testtouch({
+    page: {x: Math.round(bcr.left + bcr.width/2),
+           y: Math.round(bcr.top  + bcr.height/2)},
+    target: target,
+    identifier: id,
+  });
+  var event = new touchEvent({
+    touches: [touch],
+    targetTouches: [touch],
+    changedTouches: [touch]
+  });
+  return event;
+}
+
+function runTests() {
+  var d0 = document.getElementById("d0");
+  var d1 = document.getElementById("d1");
+  var d2 = document.getElementById("d2");
+  var d3 = document.getElementById("d3");
+
+  // Test Pointer firing before any mouse/touch original source
+
+  var mouseDownTriggered = 0;
+  var pointerDownTriggered = 0;
+  var touchDownTriggered = 0;
+  var touchCancelTriggered = 0;
+  var pointerCancelTriggered = 0;
+
+  d0.onmousedown = function(e) {
+    mouseDownTriggered = 1;
+    is(pointerDownTriggered , 1, "Mouse event must be triggered after pointer event!");
+  };
+  d0.ontouchstart = function(e) {
+    touchDownTriggered = 1;
+    is(touchDownTriggered , 1, "Touch event must be triggered after pointer event!");
+  }
+  d0.ontouchcancel = function(e) {
+    touchCancelTriggered = 1;
+    is(pointerCancelTriggered, 1, "Touch cancel event must be triggered after pointer event!");
+  }
+  d0.onpointerdown = function(e) {
+    pointerDownTriggered = 1;
+    is(mouseDownTriggered, 0, "Pointer event must be triggered before mouse event!");
+    is(touchDownTriggered, 0, "Pointer event must be triggered before touch event!");
+  };
+  d0.addEventListener("pointercancel", function(ev) {
+    d0.removeEventListener("pointercancel", arguments.callee, false);
+    is(ev.pointerId, 0, "Correct default pointerId");
+    pointerCancelTriggered = 1;
+    is(touchCancelTriggered, 0, "Pointer event must be triggered before touch event!");
+  }, false);
+
+  // Test pointer event generated from mouse event
+  synthesizeMouse(d1, 3, 3, { type: "mousemove"});
+  synthesizeMouse(d1, 3, 3, { type: "mousedown"});
+  synthesizeMouse(d1, 3, 3, { type: "mouseup"});
+
+  // Test pointer event generated from touch event
+  pointerDownTriggered = 0;
+  mouseDownTriggered = 0;
+
+  var cwu = SpecialPowers.getDOMWindowUtils(window);
+  var event1 = getTouchEventForTarget(d1, cwu, 0);
+  sendTouchEvent(cwu, "touchmove", event1, 0);
+  sendTouchEvent(cwu, "touchstart", event1, 0);
+  // Test Touch to Pointer Cancel
+  sendTouchEvent(cwu, "touchcancel", event1, 0);
+
+  // Check Pointer enter/leave from mouse generated event
+  var mouseEnterTriggered = 0;
+  var pointerEnterTriggered = 0;
+  d2.onpointerenter = function(e) {
+    pointerEnterTriggered = 1;
+    is(mouseEnterTriggered, 0, "Pointer event must be triggered before mouse event!");
+  };
+  d2.onmouseenter = function(e) {
+    mouseEnterTriggered = 1;
+    is(pointerEnterTriggered , 1, "Mouse event must be triggered after pointer event!");
+  };
+  synthesizeMouse(d2, 3, 3, { type: "mousemove"});
+  d2.onmouseenter = function(e) {}
+
+  // Test Multi Pointer enter/leave for pointers generated from Mouse and Touch at the same time
+  // Enter mouse and touch generated pointers to different elements
+  var d1enterCount = 0;
+  var d2enterCount = 0;
+  var d3enterCount = 0;
+  var d1leaveCount = 0;
+  var d2leaveCount = 0;
+  var d3leaveCount = 0;
+  var mousePointerEnterLeaveCount = 0;
+  var touchPointerEnterLeaveCount = 0;
+
+  var checkPointerType = function(pointerType) {
+    if (pointerType == "mouse") {
+      ++mousePointerEnterLeaveCount;
+    } else if (pointerType == "touch") {
+      ++touchPointerEnterLeaveCount;
+    }
+  };
+
+  d1.onpointerenter = function(e) {
+    ++d1enterCount;
+    checkPointerType(e.pointerType);
+  };
+  d2.onpointerenter = function(e) {
+    ++d2enterCount;
+    checkPointerType(e.pointerType);
+  };
+  d3.onpointerenter = function(e) {
+    ++d3enterCount;
+    checkPointerType(e.pointerType);
+  };
+  d1.onpointerleave = function(e) {
+    ++d1leaveCount;
+    checkPointerType(e.pointerType);
+  };
+  d2.onpointerleave = function(e) {
+    ++d2leaveCount;
+    checkPointerType(e.pointerType);
+  };
+  d3.onpointerleave = function(e) {
+    ++d3leaveCount;
+    checkPointerType(e.pointerType);
+  };
+
+  synthesizeMouse(d1, 3, 3, { type: "mousemove"});
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d3, cwu, 3), 0);
+  is(touchPointerEnterLeaveCount, 1, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 2, "Wrong mouse enterLeave count for!");
+
+  is(d1enterCount, 1, "Wrong enter count for! d1");
+  is(d2leaveCount, 1, "Wrong leave count for! d2");
+  is(d3enterCount, 1, "Wrong enter count for! d3");
+
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 3), 0);
+  synthesizeMouse(d3, 3, 3, { type: "mousemove"});
+  is(touchPointerEnterLeaveCount, 3, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 4, "Wrong mouse enterLeave count for!");
+
+  is(d3leaveCount, 1, "Wrong leave count for! d3");
+  is(d1leaveCount, 1, "Wrong leave count for! d1");
+  is(d1enterCount, 2, "Wrong enter count for! d1");
+  is(d3enterCount, 2, "Wrong enter count for! d3");
+
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d2, cwu, 3), 0);
+  synthesizeMouse(d2, 3, 3, { type: "mousemove"});
+  is(touchPointerEnterLeaveCount, 5, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 6, "Wrong mouse enterLeave count for!");
+
+  is(d1leaveCount, 2, "Wrong leave count for! d1");
+  is(d2enterCount, 2, "Wrong enter count for! d2");
+  is(d3leaveCount, 2, "Wrong leave count for! d3");
+
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 3), 0);
+  synthesizeMouse(d1, 3, 3, { type: "mousemove"});
+  is(touchPointerEnterLeaveCount, 7, "Wrong touch enterLeave count for!");
+  is(mousePointerEnterLeaveCount, 8, "Wrong mouse enterLeave count for!");
+
+  is(d2leaveCount, 3, "Wrong leave count for! d2");
+  is(d1enterCount, 4, "Wrong enter count for! d1");
+
+  // Test for pointer buttons when it generated from mousemove event
+  d1.onpointermove = function(e) {
+    is(e.buttons, 0, "Buttons must be 0 on pointer generated from mousemove");
+    is(e.button, -1, "Button must be -1 on pointer generated from mousemove when no buttons pressed");
+    is(e.pointerType, "mouse", "Pointer type must be mouse");
+  };
+  cwu.sendMouseEvent("mousemove", 4, 4, 0, 0, 0, false, 0, 0);
+
+  d1.onpointermove = function(e) {
+    is(e.buttons, 1, "Buttons must be 1 on pointer generated from touch event");
+    is(e.button, 0, "Button must be 0 on pointer generated from touch eventd");
+    is(e.pointerType, "touch", "Pointer type must be touch");
+  };
+  sendTouchEvent(cwu, "touchmove", getTouchEventForTarget(d1, cwu, 2), 0);
+
+  // Test for cancel trigger pointerOut (Touch Pointer must be at d1 now)
+  pointerCancelTriggered = 0;
+  var pointerOutTriggeredForCancelEvent = 0;
+  var pointerLeaveTriggeredForCancelEvent = 0;
+  d1.onpointerout = function(e) {
+    if (pointerOutTriggeredForCancelEvent == 0) {
+      is(e.pointerId, 3, "Wrong Pointer type, should be id from Touch event");
+      is(e.pointerType, "touch", "Wrong Pointer type, should be touch type");
+    } else {
+      is(e.pointerId, 0, "Wrong Pointer type, should be id from mouse event");
+      is(e.pointerType, "mouse", "Wrong Pointer type, should be mouse type");
+    }
+    pointerOutTriggeredForCancelEvent = 1;
+ };
+ d1.onpointerleave = function(e) {
+    is(pointerOutTriggeredForCancelEvent, 1, "Pointer Out must be dispatched bedore Pointer leave");
+    if (pointerLeaveTriggeredForCancelEvent == 0) {
+      is(e.pointerId, 3, "Wrong Pointer type, should be id from Touch event");
+      is(e.pointerType, "touch", "Wrong Pointer type, should be touch type");
+    } else {
+      is(e.pointerId, 0, "Wrong Pointer type, should be id from mouse event");
+      is(e.pointerType, "mouse", "Wrong Pointer type, should be mouse type");
+    }
+    pointerLeaveTriggeredForCancelEvent = 1;
+  }
+
+  sendTouchEvent(cwu, "touchcancel", getTouchEventForTarget(d1, cwu, 3), 0);
+  is(pointerOutTriggeredForCancelEvent, 1, "Pointer Out not dispatched on PointerCancel");
+  is(pointerLeaveTriggeredForCancelEvent, 1, "Pointer Leave not dispatched on PointerCancel");
+
+  finishTest();
+}
+
+function finishTest() {
+  // Let window.onerror have a chance to fire
+  setTimeout(function() {
+    setTimeout(function() {
+      window.parent.postMessage("SimpleTest.finish();", "*");
+    }, 0);
+  }, 0);
+}
+
+window.onload = function () {
+  SpecialPowers.pushPrefEnv({
+    "set": [
+      ["dom.w3c_pointer_events.enabled", true],
+    ]
+  }, runTests);
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</pre>
+<div id="d0">
+Test divs --
+<div id="d1">t</div><div id="d2">t</div><div id="d3">t</div>
+--
+</div>
+</body>
+</html>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -187,16 +187,18 @@ skip-if = toolkit == 'android'
 [test_remote_frame.html]
 [test_remote_passpointerevents.html]
 [test_bug842853.html]
 [test_bug842853-2.html]
 [test_bug849219.html]
 [test_bug851485.html]
 [test_bug851445.html]
 support-files = bug851445_helper.html
+[test_bug970964.html]
+support-files = bug970964_inner.html
 [test_emulateMedium.html]
 [test_getClientRects_emptytext.html]
 [test_bug858459.html]
 skip-if = toolkit == "gonk"
 
 # Tests for bugs 441782, 467672 and 570378 do not pass reliably on Windows,
 # because of bug 469208.
 [test_bug332655-1.html]
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/test_bug970964.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=970964
+-->
+<head>
+  <title>Test for Bug 970964</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="text/javascript;version=1.7">
+    function setRemoteFrame() {
+      var iframe = document.getElementById("testFrame");
+      iframe.src = "bug970964_inner.html";
+
+      function messageListener(event) {
+        eval(event.data);
+      }
+
+      window.addEventListener("message", messageListener, false);
+    }
+
+    function runTest() {
+      SimpleTest.waitForExplicitFinish();
+
+      SpecialPowers.pushPrefEnv({
+        "set": [
+          ["dom.w3c_pointer_events.enabled", true]
+        ]
+      }, setRemoteFrame);
+    }
+  </script>
+</head>
+<body onload="runTest();">
+  <iframe id="testFrame" height="500" width="500"></iframe>
+</body>
+
--- a/layout/build/nsLayoutStatics.h
+++ b/layout/build/nsLayoutStatics.h
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsLayoutStatics_h__
 #define nsLayoutStatics_h__
 
 #include "nscore.h"
 #include "MainThreadUtils.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "nsDebug.h"
 
 // This isn't really a class, it's a namespace for static methods.
 // Documents and other objects can hold a reference to the layout static
 // objects so that they last past the xpcom-shutdown notification.
 
 class nsLayoutStatics
 {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1053,26 +1053,24 @@ nsIFrame::HasPerspective() const
   if (!IsTransformed()) {
     return false;
   }
   nsStyleContext* parentStyleContext = StyleContext()->GetParent();
   if (!parentStyleContext) {
     return false;
   }
   const nsStyleDisplay* parentDisp = parentStyleContext->StyleDisplay();
-  return parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
-         parentDisp->mChildPerspective.GetCoordValue() > 0.0;
+  return parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord;
 }
 
 bool
 nsIFrame::ChildrenHavePerspective() const
 {
   const nsStyleDisplay *disp = StyleDisplay();
-  return disp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
-         disp->mChildPerspective.GetCoordValue() > 0.0;
+  return disp->mChildPerspective.GetUnit() == eStyleUnit_Coord;
 }
 
 nsRect
 nsIFrame::GetContentRectRelativeToSelf() const
 {
   nsMargin bp(GetUsedBorderAndPadding());
   ApplySkipSides(bp);
   nsRect r(0, 0, mRect.width, mRect.height);
@@ -2177,16 +2175,19 @@ nsIFrame::BuildDisplayListForChild(nsDis
     return;
 
   // Child is composited if it's transformed, partially transparent, or has
   // SVG effects or a blend mode..
   const nsStyleDisplay* disp = child->StyleDisplay();
   const nsStylePosition* pos = child->StylePosition();
   bool isVisuallyAtomic = child->HasOpacity()
     || child->IsTransformed()
+    // strictly speaking, 'perspective' doesn't require visual atomicity,
+    // but the spec says it acts like the rest of these
+    || disp->mChildPerspective.GetUnit() == eStyleUnit_Coord
     || disp->mMixBlendMode != NS_STYLE_BLEND_NORMAL
     || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
 
   bool isPositioned = disp->IsPositioned(child);
   bool isStackingContext =
     (isPositioned && (disp->mPosition == NS_STYLE_POSITION_STICKY ||
                       pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
      (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
--- a/layout/media/symbols.def.in
+++ b/layout/media/symbols.def.in
@@ -122,16 +122,17 @@ speex_resampler_set_quality
 speex_resampler_get_quality
 speex_resampler_set_input_stride
 speex_resampler_get_input_stride
 speex_resampler_set_output_stride
 speex_resampler_get_output_stride
 speex_resampler_get_input_latency
 speex_resampler_get_output_latency
 speex_resampler_skip_zeros
+speex_resampler_set_skip_frac_num
 speex_resampler_reset_mem
 speex_resampler_strerror
 cubeb_destroy
 cubeb_init
 cubeb_get_max_channel_count
 cubeb_get_min_latency
 cubeb_get_preferred_sample_rate
 cubeb_stream_destroy
--- a/layout/reftests/z-index/reftest.list
+++ b/layout/reftests/z-index/reftest.list
@@ -1,2 +1,4 @@
 == 480053-1.html 480053-1-ref.html
 == z-index-1.html z-index-1-ref.html
+!= stacking-context-yes.html stacking-context-no.html
+== stacking-context-perspective.html stacking-context-yes.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/z-index/stacking-context-common.css
@@ -0,0 +1,26 @@
+.contain, .maybesc {
+  width: 100px;
+  height: 100px;
+}
+.contain, .maybesc {
+  position: relative;
+}
+.inner1, .inner3, .intruder {
+  position: absolute;
+  top: 0; left: 0; bottom: 0; right: 0;
+}
+.inner1 {
+  left: 5px; right: 30px;
+  background: rgba(0, 255, 255, 0.5); /* aqua */
+  z-index: 1;
+}
+.inner3 {
+  left: 30px; right: 5px;
+  background: rgba(255, 255, 0, 0.5); /* yellow */
+  z-index: 3;
+}
+.intruder {
+  top: 20px; bottom: 20px;
+  background: rgba(255, 0, 255, 0.5); /* fuchsia */
+  z-index: 2;
+}
new file mode 100644
--- /dev/null
+++ b/layout/reftests/z-index/stacking-context-no.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>Reference for things that do not create a stacking context</title>
+<link rel="stylesheet" href="stacking-context-common.css">
+<div class="contain">
+  <div class="maybesc">
+    <div class="inner1"></div>
+    <div class="inner3"></div>
+  </div>
+  <div class="intruder"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/z-index/stacking-context-perspective.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>Does 'perspective' create a stacking context?</title>
+<link rel="stylesheet" href="stacking-context-common.css">
+<style>
+.perspective {
+  -webkit-perspective: 200px;
+  perspective: 200px;
+}
+</style>
+<div class="contain">
+  <div class="maybesc perspective">
+    <div class="inner1"></div>
+    <div class="inner3"></div>
+  </div>
+  <div class="intruder"></div>
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/z-index/stacking-context-yes.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<meta charset="UTF-8">
+<title>Reference for things that create a stacking context</title>
+<link rel="stylesheet" href="stacking-context-common.css">
+<style>
+.sc {
+  z-index: 0;
+}
+</style>
+<div class="contain">
+  <div class="maybesc sc">
+    <div class="inner1"></div>
+    <div class="inner3"></div>
+  </div>
+  <div class="intruder"></div>
+</div>
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 /* tokenization of CSS style sheets */
 
 #include "nsCSSScanner.h"
 #include "nsStyleUtil.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/css/ErrorReporter.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 
 /* Character class tables and related helper functions. */
 
 static const uint8_t IS_HEX_DIGIT  = 0x01;
--- a/layout/svg/nsSVGEffects.h
+++ b/layout/svg/nsSVGEffects.h
@@ -15,17 +15,16 @@
 #include "nsIMutationObserver.h"
 #include "nsInterfaceHashtable.h"
 #include "nsISupportsBase.h"
 #include "nsISupportsImpl.h"
 #include "nsReferencedElement.h"
 #include "nsStubMutationObserver.h"
 #include "nsSVGUtils.h"
 #include "nsTHashtable.h"
-#include "nsTraceRefcnt.h"
 #include "nsURIHashKey.h"
 
 class nsIAtom;
 class nsIPresShell;
 class nsIURI;
 class nsSVGClipPathFrame;
 class nsSVGPaintServerFrame;
 class nsSVGFilterFrame;
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -674,21 +674,25 @@ nsSVGUtils::HitTestClip(nsIFrame *aFrame
 {
   nsSVGEffects::EffectProperties props =
     nsSVGEffects::GetEffectProperties(aFrame);
   if (!props.mClipPath)
     return true;
 
   bool isOK = true;
   nsSVGClipPathFrame *clipPathFrame = props.GetClipPathFrame(&isOK);
-  if (!clipPathFrame || !isOK) {
+  if (!isOK) {
     // clipPath is not a valid resource, so nothing gets painted, so
     // hit-testing must fail.
     return false;
   }
+  if (!clipPathFrame) {
+    // clipPath doesn't exist, ignore it.
+    return true;
+  }
 
   return clipPathFrame->ClipHitTest(aFrame, GetCanvasTM(aFrame,
                                     nsISVGChildFrame::FOR_HIT_TESTING), aPoint);
 }
 
 nsIFrame *
 nsSVGUtils::HitTestChildren(nsIFrame *aFrame, const nsPoint &aPoint)
 {
new file mode 100644
--- /dev/null
+++ b/media/libspeex_resampler/set-skip-frac.patch
@@ -0,0 +1,115 @@
+# HG changeset patch
+# Parent 091c02c13c8ba50903248432d0c7561104dace21
+# User Karl Tomlinson <karlt+@karlt.net>
+b=913854 add speex_resampler_set_skip_frac_num r=jmspeex
+
+This allows a client to align output samples consistently for independent
+resampling of contiguous input buffers.
+
+diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in
+--- a/layout/media/symbols.def.in
++++ b/layout/media/symbols.def.in
+@@ -122,16 +122,17 @@ speex_resampler_set_quality
+ speex_resampler_get_quality
+ speex_resampler_set_input_stride
+ speex_resampler_get_input_stride
+ speex_resampler_set_output_stride
+ speex_resampler_get_output_stride
+ speex_resampler_get_input_latency
+ speex_resampler_get_output_latency
+ speex_resampler_skip_zeros
++speex_resampler_set_skip_frac_num
+ speex_resampler_reset_mem
+ speex_resampler_strerror
+ cubeb_destroy
+ cubeb_init
+ cubeb_get_max_channel_count
+ cubeb_get_min_latency
+ cubeb_get_preferred_sample_rate
+ cubeb_stream_destroy
+diff --git a/media/libspeex_resampler/src/resample.c b/media/libspeex_resampler/src/resample.c
+--- a/media/libspeex_resampler/src/resample.c
++++ b/media/libspeex_resampler/src/resample.c
+@@ -1138,16 +1138,28 @@ SPX_RESAMPLE_EXPORT int speex_resampler_
+ SPX_RESAMPLE_EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
+ {
+    spx_uint32_t i;
+    for (i=0;i<st->nb_channels;i++)
+       st->last_sample[i] = st->filt_len/2;
+    return RESAMPLER_ERR_SUCCESS;
+ }
+ 
++SPX_RESAMPLE_EXPORT int speex_resampler_set_skip_frac_num(SpeexResamplerState *st, spx_uint32_t skip_frac_num)
++{
++   spx_uint32_t i;
++   spx_uint32_t last_sample = skip_frac_num / st->den_rate;
++   spx_uint32_t samp_frac_num = skip_frac_num % st->den_rate;
++   for (i=0;i<st->nb_channels;i++) {
++      st->last_sample[i] = last_sample;
++      st->samp_frac_num[i] = samp_frac_num;
++   }
++   return RESAMPLER_ERR_SUCCESS;
++}
++
+ SPX_RESAMPLE_EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
+ {
+    spx_uint32_t i;
+    for (i=0;i<st->nb_channels;i++)
+    {
+       st->last_sample[i] = 0;
+       st->magic_samples[i] = 0;
+       st->samp_frac_num[i] = 0;
+diff --git a/media/libspeex_resampler/src/speex_resampler.h b/media/libspeex_resampler/src/speex_resampler.h
+--- a/media/libspeex_resampler/src/speex_resampler.h
++++ b/media/libspeex_resampler/src/speex_resampler.h
+@@ -69,16 +69,17 @@
+ #define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
+ #define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
+ #define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
+ #define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
+ #define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
+ #define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
+ #define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
+ #define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
++#define speex_resampler_set_skip_frac_num CAT_PREFIX(RANDOM_PREFIX,_resampler_set_skip_frac_num)
+ #define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
+ #define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
+ 
+ #define spx_int16_t short
+ #define spx_int32_t int
+ #define spx_uint16_t unsigned short
+ #define spx_uint32_t unsigned int
+       
+@@ -321,16 +322,32 @@ int speex_resampler_get_output_latency(S
+  * resampler. It is recommended to use that when resampling an audio file, as
+  * it will generate a file with the same length. For real-time processing,
+  * it is probably easier not to use this call (so that the output duration
+  * is the same for the first frame).
+  * @param st Resampler state
+  */
+ int speex_resampler_skip_zeros(SpeexResamplerState *st);
+ 
++/** Set the numerator in a fraction determining the advance through input
++ * samples before writing any output samples. The denominator of the fraction
++ * is the value returned from speex_resampler_get_ratio() in ratio_den. This
++ * is only useful before starting to use a newly created or reset resampler.
++ * If the first input sample is interpreted as the signal at time
++ * input_latency*in_rate, then the first output sample represents the signal
++ * at the time frac_num/ratio_num*out_rate.
++ * This is intended for careful alignment of output sample points wrt input
++ * sample points. Large values are not an efficient offset into the in buffer.
++ * @param st Resampler state
++ * @param skip_frac_num Numerator of the offset fraction,
++ *                      between 0 and ratio_den-1.
++ */
++int speex_resampler_set_skip_frac_num(SpeexResamplerState *st,
++                                      spx_uint32_t skip_frac_num);
++
+ /** Reset a resampler so a new (unrelated) stream can be processed.
+  * @param st Resampler state
+  */
+ int speex_resampler_reset_mem(SpeexResamplerState *st);
+ 
+ /** Returns the English meaning for an error code
+  * @param err Error code
+  * @return English string
--- a/media/libspeex_resampler/src/resample.c
+++ b/media/libspeex_resampler/src/resample.c
@@ -1138,16 +1138,28 @@ SPX_RESAMPLE_EXPORT int speex_resampler_
 SPX_RESAMPLE_EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st)
 {
    spx_uint32_t i;
    for (i=0;i<st->nb_channels;i++)
       st->last_sample[i] = st->filt_len/2;
    return RESAMPLER_ERR_SUCCESS;
 }
 
+SPX_RESAMPLE_EXPORT int speex_resampler_set_skip_frac_num(SpeexResamplerState *st, spx_uint32_t skip_frac_num)
+{
+   spx_uint32_t i;
+   spx_uint32_t last_sample = skip_frac_num / st->den_rate;
+   spx_uint32_t samp_frac_num = skip_frac_num % st->den_rate;
+   for (i=0;i<st->nb_channels;i++) {
+      st->last_sample[i] = last_sample;
+      st->samp_frac_num[i] = samp_frac_num;
+   }
+   return RESAMPLER_ERR_SUCCESS;
+}
+
 SPX_RESAMPLE_EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st)
 {
    spx_uint32_t i;
    for (i=0;i<st->nb_channels;i++)
    {
       st->last_sample[i] = 0;
       st->magic_samples[i] = 0;
       st->samp_frac_num[i] = 0;
--- a/media/libspeex_resampler/src/speex_resampler.h
+++ b/media/libspeex_resampler/src/speex_resampler.h
@@ -69,16 +69,17 @@
 #define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
 #define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
 #define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
 #define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
 #define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
 #define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
 #define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
 #define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
+#define speex_resampler_set_skip_frac_num CAT_PREFIX(RANDOM_PREFIX,_resampler_set_skip_frac_num)
 #define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
 #define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
 
 #define spx_int16_t short
 #define spx_int32_t int
 #define spx_uint16_t unsigned short
 #define spx_uint32_t unsigned int
       
@@ -321,16 +322,32 @@ int speex_resampler_get_output_latency(S
  * resampler. It is recommended to use that when resampling an audio file, as
  * it will generate a file with the same length. For real-time processing,
  * it is probably easier not to use this call (so that the output duration
  * is the same for the first frame).
  * @param st Resampler state
  */
 int speex_resampler_skip_zeros(SpeexResamplerState *st);
 
+/** Set the numerator in a fraction determining the advance through input
+ * samples before writing any output samples. The denominator of the fraction
+ * is the value returned from speex_resampler_get_ratio() in ratio_den. This
+ * is only useful before starting to use a newly created or reset resampler.
+ * If the first input sample is interpreted as the signal at time
+ * input_latency*in_rate, then the first output sample represents the signal
+ * at the time frac_num/ratio_num*out_rate.
+ * This is intended for careful alignment of output sample points wrt input
+ * sample points. Large values are not an efficient offset into the in buffer.
+ * @param st Resampler state
+ * @param skip_frac_num Numerator of the offset fraction,
+ *                      between 0 and ratio_den-1.
+ */
+int speex_resampler_set_skip_frac_num(SpeexResamplerState *st,
+                                      spx_uint32_t skip_frac_num);
+
 /** Reset a resampler so a new (unrelated) stream can be processed.
  * @param st Resampler state
  */
 int speex_resampler_reset_mem(SpeexResamplerState *st);
 
 /** Returns the English meaning for an error code
  * @param err Error code
  * @return English string
--- a/media/libspeex_resampler/update.sh
+++ b/media/libspeex_resampler/update.sh
@@ -15,8 +15,9 @@ cp $1/src/arch.h src
 cp $1/src/stack_alloc.h src
 cp $1/src/speex_resampler.h src
 cp $1/AUTHORS .
 cp $1/COPYING .
 
 # apply outstanding local patches
 patch -p1 < sse-detect-runtime.patch
 patch -p3 < reset.patch
+patch -p3 < set-skip-frac.patch
--- a/modules/libpref/src/nsPrefBranch.h
+++ b/modules/libpref/src/nsPrefBranch.h
@@ -16,17 +16,17 @@
 #include "nsIRelativeFilePref.h"
 #include "nsIFile.h"
 #include "nsString.h"
 #include "nsVoidArray.h"
 #include "nsTArray.h"
 #include "nsWeakReference.h"
 #include "nsClassHashtable.h"
 #include "nsCRT.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/MemoryReporting.h"
 
 namespace mozilla {
 class PreferenceServiceReporter;
 } // namespace mozilla;
 
 class nsPrefBranch;
--- a/netwerk/protocol/about/nsAboutBloat.cpp
+++ b/netwerk/protocol/about/nsAboutBloat.cpp
@@ -1,14 +1,14 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "nsTraceRefcntImpl.h"
+#include "nsTraceRefcnt.h"
 
 // if NS_BUILD_REFCNT_LOGGING isn't defined, don't try to build
 #ifdef NS_BUILD_REFCNT_LOGGING
 
 #include "nsAboutBloat.h"
 #include "nsStringStream.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
@@ -24,35 +24,35 @@ NS_IMETHODIMP
 nsAboutBloat::NewChannel(nsIURI *aURI, nsIChannel **result)
 {
     NS_ENSURE_ARG_POINTER(aURI);
     nsresult rv;
     nsAutoCString path;
     rv = aURI->GetPath(path);
     if (NS_FAILED(rv)) return rv;
 
-    nsTraceRefcntImpl::StatisticsType statType = nsTraceRefcntImpl::ALL_STATS;
+    nsTraceRefcnt::StatisticsType statType = nsTraceRefcnt::ALL_STATS;
     bool clear = false;
     bool leaks = false;
 
     int32_t pos = path.Find("?");
     if (pos > 0) {
         nsAutoCString param;
         (void)path.Right(param, path.Length() - (pos+1));
         if (param.EqualsLiteral("new"))
-            statType = nsTraceRefcntImpl::NEW_STATS;
+            statType = nsTraceRefcnt::NEW_STATS;
         else if (param.EqualsLiteral("clear"))
             clear = true;
         else if (param.EqualsLiteral("leaks"))
             leaks = true;
     }
 
     nsCOMPtr<nsIInputStream> inStr;
     if (clear) {
-        nsTraceRefcntImpl::ResetStatistics();
+        nsTraceRefcnt::ResetStatistics();
 
         rv = NS_NewCStringInputStream(getter_AddRefs(inStr),
             NS_LITERAL_CSTRING("Bloat statistics cleared."));
         if (NS_FAILED(rv)) return rv;
     }
     else if (leaks) {
         // dump the current set of leaks.
         GC_gcollect();
@@ -78,33 +78,33 @@ nsAboutBloat::NewChannel(nsIURI *aURI, n
             // On all the platforms that I know use permissions,
             // directories need to have the executable flag set
             // if you want to do anything inside the directory.
             rv = file->Create(nsIFile::DIRECTORY_TYPE, 0755);
             if (NS_FAILED(rv)) return rv;
         }
 
         nsAutoCString dumpFileName;
-        if (statType == nsTraceRefcntImpl::ALL_STATS)
+        if (statType == nsTraceRefcnt::ALL_STATS)
             dumpFileName.AssignLiteral("all-");
         else
             dumpFileName.AssignLiteral("new-");
         PRExplodedTime expTime;
         PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &expTime);
         char time[128];
         PR_FormatTimeUSEnglish(time, 128, "%Y-%m-%d-%H%M%S.txt", &expTime);
         dumpFileName += time;
         rv = file->AppendNative(dumpFileName);
         if (NS_FAILED(rv)) return rv;
 
         FILE* out;
         rv = file->OpenANSIFileDesc("w", &out);
         if (NS_FAILED(rv)) return rv;
 
-        rv = nsTraceRefcntImpl::DumpStatistics(statType, out);
+        rv = nsTraceRefcnt::DumpStatistics(statType, out);
         ::fclose(out);
         if (NS_FAILED(rv)) return rv;
 
         rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), file);
         if (NS_FAILED(rv)) return rv;
     }
 
     nsIChannel* channel;
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -21,16 +21,17 @@
 #include "nsIApplicationCacheChannel.h"
 #include "nsEscape.h"
 #include "nsStreamListenerWrapper.h"
 #include "nsISecurityConsoleMessage.h"
 #include "nsURLHelper.h"
 #include "nsICookieService.h"
 #include "nsIStreamConverterService.h"
 #include "nsCRT.h"
+#include "nsIObserverService.h"
 
 #include <algorithm>
 
 namespace mozilla {
 namespace net {
 
 HttpBaseChannel::HttpBaseChannel()
   : mStartPos(UINT64_MAX)
@@ -1308,32 +1309,65 @@ HttpBaseChannel::GetResponseVersion(uint
   nsHttpVersion version = mResponseHead->Version();
 
   if (major) { *major = version / 10; }
   if (minor) { *minor = version % 10; }
 
   return NS_OK;
 }
 
+namespace {
+
+class CookieNotifierRunnable : public nsRunnable
+{
+public:
+  CookieNotifierRunnable(HttpBaseChannel* aChannel, char const * aCookie)
+    : mChannel(aChannel), mCookie(aCookie)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+    if (obs) {
+      obs->NotifyObservers(static_cast<nsIChannel*>(mChannel.get()),
+                           "http-on-response-set-cookie",
+                           mCookie.get());
+    }
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<HttpBaseChannel> mChannel;
+  NS_ConvertASCIItoUTF16 mCookie;
+};
+
+} // anonymous namespace
+
 NS_IMETHODIMP
 HttpBaseChannel::SetCookie(const char *aCookieHeader)
 {
   if (mLoadFlags & LOAD_ANONYMOUS)
     return NS_OK;
 
   // empty header isn't an error
   if (!(aCookieHeader && *aCookieHeader))
     return NS_OK;
 
   nsICookieService *cs = gHttpHandler->GetCookieService();
   NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
 
-  return cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, aCookieHeader,
-                                     mResponseHead->PeekHeader(nsHttp::Date),
-                                     this);
+  nsresult rv =
+    cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, aCookieHeader,
+                                mResponseHead->PeekHeader(nsHttp::Date), this);
+  if (NS_SUCCEEDED(rv)) {
+    nsRefPtr<CookieNotifierRunnable> r =
+      new CookieNotifierRunnable(this, aCookieHeader);
+    NS_DispatchToMainThread(r);
+  }
+  return rv;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
 {
   *aForce = mForceAllowThirdPartyCookie;
   return NS_OK;
 }
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -58,16 +58,17 @@
 #include "nsInputStreamPump.h"
 #include "nsURLHelper.h"
 #include "nsISocketTransport.h"
 #include "nsICacheSession.h"
 #include "nsIStreamConverterService.h"
 #include "nsISiteSecurityService.h"
 #include "nsCRT.h"
 #include "CacheObserver.h"
+#include "mozilla/Telemetry.h"
 
 namespace mozilla { namespace net {
 
 namespace {
 
 // True if the local cache should be bypassed when processing a request.
 #define BYPASS_LOCAL_CACHE(loadFlags) \
         (loadFlags & (nsIRequest::LOAD_BYPASS_CACHE | \
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -18,17 +18,16 @@
 #include "nsIHttpAuthenticableChannel.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsITimedChannel.h"
 #include "nsIThreadRetargetableRequest.h"
 #include "nsIThreadRetargetableStreamListener.h"
 #include "nsWeakReference.h"
 #include "TimingStruct.h"
 #include "AutoClose.h"
-#include "mozilla/Telemetry.h"
 
 class nsIPrincipal;
 class nsDNSPrefetch;
 class nsICacheEntryDescriptor;
 class nsICancelable;
 class nsIHttpChannelAuthProvider;
 class nsInputStreamPump;
 
--- a/parser/html/nsHtml5AttributeName.cpp
+++ b/parser/html/nsHtml5AttributeName.cpp
@@ -27,17 +27,17 @@
 
 #define nsHtml5AttributeName_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5AttributeName.h
+++ b/parser/html/nsHtml5AttributeName.h
@@ -28,17 +28,17 @@
 #ifndef nsHtml5AttributeName_h
 #define nsHtml5AttributeName_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5ElementName.cpp
+++ b/parser/html/nsHtml5ElementName.cpp
@@ -27,17 +27,17 @@
 
 #define nsHtml5ElementName_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5ElementName.h
+++ b/parser/html/nsHtml5ElementName.h
@@ -28,17 +28,17 @@
 #ifndef nsHtml5ElementName_h
 #define nsHtml5ElementName_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5HtmlAttributes.cpp
+++ b/parser/html/nsHtml5HtmlAttributes.cpp
@@ -28,17 +28,17 @@
 
 #define nsHtml5HtmlAttributes_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5HtmlAttributes.h
+++ b/parser/html/nsHtml5HtmlAttributes.h
@@ -29,17 +29,17 @@
 #ifndef nsHtml5HtmlAttributes_h
 #define nsHtml5HtmlAttributes_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5MetaScanner.cpp
+++ b/parser/html/nsHtml5MetaScanner.cpp
@@ -28,17 +28,17 @@
 
 #define nsHtml5MetaScanner_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5MetaScanner.h
+++ b/parser/html/nsHtml5MetaScanner.h
@@ -29,17 +29,17 @@
 #ifndef nsHtml5MetaScanner_h
 #define nsHtml5MetaScanner_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5MetaScannerCppSupplement.h
+++ b/parser/html/nsHtml5MetaScannerCppSupplement.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
 #include "nsEncoderDecoderUtils.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 
 #include "mozilla/dom/EncodingUtils.h"
 
 using mozilla::dom::EncodingUtils;
 
 void
 nsHtml5MetaScanner::sniff(nsHtml5ByteReadable* bytes, nsACString& charset)
 {
--- a/parser/html/nsHtml5Portability.h
+++ b/parser/html/nsHtml5Portability.h
@@ -28,17 +28,17 @@
 #ifndef nsHtml5Portability_h
 #define nsHtml5Portability_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5StackNode.cpp
+++ b/parser/html/nsHtml5StackNode.cpp
@@ -28,17 +28,17 @@
 
 #define nsHtml5StackNode_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5StackNode.h
+++ b/parser/html/nsHtml5StackNode.h
@@ -29,17 +29,17 @@
 #ifndef nsHtml5StackNode_h
 #define nsHtml5StackNode_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5StateSnapshot.cpp
+++ b/parser/html/nsHtml5StateSnapshot.cpp
@@ -27,17 +27,17 @@
 
 #define nsHtml5StateSnapshot_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5StateSnapshot.h
+++ b/parser/html/nsHtml5StateSnapshot.h
@@ -28,17 +28,17 @@
 #ifndef nsHtml5StateSnapshot_h
 #define nsHtml5StateSnapshot_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5Tokenizer.cpp
+++ b/parser/html/nsHtml5Tokenizer.cpp
@@ -29,17 +29,17 @@
  */
 
 #define nsHtml5Tokenizer_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5NamedCharacters.h"
 #include "nsHtml5NamedCharactersAccel.h"
 #include "nsHtml5Atoms.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
--- a/parser/html/nsHtml5Tokenizer.h
+++ b/parser/html/nsHtml5Tokenizer.h
@@ -30,17 +30,17 @@
 
 #ifndef nsHtml5Tokenizer_h
 #define nsHtml5Tokenizer_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5NamedCharacters.h"
 #include "nsHtml5NamedCharactersAccel.h"
 #include "nsHtml5Atoms.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Macros.h"
--- a/parser/html/nsHtml5TreeBuilder.cpp
+++ b/parser/html/nsHtml5TreeBuilder.cpp
@@ -31,17 +31,17 @@
 #define nsHtml5TreeBuilder_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsITimer.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5Parser.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsHtml5PendingNotification.h"
 #include "nsHtml5StateSnapshot.h"
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -32,17 +32,17 @@
 #define nsHtml5TreeBuilder_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsITimer.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsHtml5Parser.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsHtml5PendingNotification.h"
 #include "nsHtml5StateSnapshot.h"
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -4,17 +4,17 @@
 
 #ifndef nsHtml5TreeOpExecutor_h
 #define nsHtml5TreeOpExecutor_h
 
 #include "nsIAtom.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsHtml5SpeculativeLoad.h"
 #include "nsHtml5PendingNotification.h"
 #include "nsTArray.h"
 #include "nsContentSink.h"
 #include "nsNodeInfoManager.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsIScriptElement.h"
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -14,17 +14,17 @@
 #include "mozAutoDocUpdate.h"
 #include "nsBindingManager.h"
 #include "nsXBLBinding.h"
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5HtmlAttributes.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsIScriptElement.h"
 #include "nsIDTD.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIFormControl.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIDOMDocumentType.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "nsIMutationObserver.h"
 #include "nsIFormProcessor.h"
--- a/parser/html/nsHtml5UTF16Buffer.cpp
+++ b/parser/html/nsHtml5UTF16Buffer.cpp
@@ -27,17 +27,17 @@
 
 #define nsHtml5UTF16Buffer_cpp__
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/parser/html/nsHtml5UTF16Buffer.h
+++ b/parser/html/nsHtml5UTF16Buffer.h
@@ -28,17 +28,17 @@
 #ifndef nsHtml5UTF16Buffer_h
 #define nsHtml5UTF16Buffer_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
-#include "nsTraceRefcnt.h"
+#include "nsISupportsImpl.h"
 #include "jArray.h"
 #include "nsHtml5ArrayCopy.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5Atoms.h"
 #include "nsHtml5ByteReadable.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5Macros.h"
 
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -237,25 +237,26 @@ class TreeMetadataEmitter(LoggingMixin):
             'LIBXUL_LIBRARY',
             'MSVC_ENABLE_PGO',
             'NO_DIST_INSTALL',
             'OS_LIBS',
             'RCFILE',
             'RESFILE',
             'DEFFILE',
             'SDK_LIBRARY',
-            'CFLAGS',
-            'CXXFLAGS',
-            'LDFLAGS',
             'WIN32_EXE_LDFLAGS',
         ]
         for v in varlist:
             if v in sandbox and sandbox[v]:
                 passthru.variables[v] = sandbox[v]
 
+        for v in ['CFLAGS', 'CXXFLAGS', 'CMFLAGS', 'CMMFLAGS', 'LDFLAGS']:
+            if v in sandbox and sandbox[v]:
+                passthru.variables['MOZBUILD_' + v] = sandbox[v]
+
         # NO_VISIBILITY_FLAGS is slightly different
         if sandbox['NO_VISIBILITY_FLAGS']:
             passthru.variables['VISIBILITY_FLAGS'] = ''
 
         if sandbox['DELAYLOAD_DLLS']:
             passthru.variables['DELAYLOAD_LDFLAGS'] = [('-DELAYLOAD:%s' % dll) for dll in sandbox['DELAYLOAD_DLLS']]
             passthru.variables['USE_DELAYIMP'] = True
 
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -683,35 +683,53 @@ VARIABLES = {
     'SPHINX_PYTHON_PACKAGE_DIRS': (StrictOrderingOnAppendList, list,
         """Directories containing Python packages that Sphinx documents.
         """, None),
 
     'CFLAGS': (list, list,
         """Flags passed to the C compiler for all of the C source files
            declared in this directory.
 
-           Note that the ordering of flags matter here, these flags will be
+           Note that the ordering of flags matters here, these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """, 'binaries'),
 
     'CXXFLAGS': (list, list,
         """Flags passed to the C++ compiler for all of the C++ source files
            declared in this directory.
 
-           Note that the ordering of flags matter here, these flags will be
+           Note that the ordering of flags matters here; these flags will be
+           added to the compiler's command line in the same order as they
+           appear in the moz.build file.
+        """, 'binaries'),
+
+    'CMFLAGS': (list, list,
+        """Flags passed to the Objective-C compiler for all of the Objective-C
+           source files declared in this directory.
+
+           Note that the ordering of flags matters here; these flags will be
+           added to the compiler's command line in the same order as they
+           appear in the moz.build file.
+        """, 'binaries'),
+
+    'CMMFLAGS': (list, list,
+        """Flags passed to the Objective-C++ compiler for all of the
+           Objective-C++ source files declared in this directory.
+
+           Note that the ordering of flags matters here; these flags will be
            added to the compiler's command line in the same order as they
            appear in the moz.build file.
         """, 'binaries'),
 
     'LDFLAGS': (list, list,
         """Flags passed to the linker when linking all of the libraries and
            executables declared in this directory.
 
-           Note that the ordering of flags matter here, these flags will be
+           Note that the ordering of flags matters here; these flags will be
            added to the linker's command line in the same order as they
            appear in the moz.build file.
         """, 'libs'),
 
     'WIN32_EXE_LDFLAGS': (list, list,
         """Flags passed to the linker when linking a Windows .exe executable
            declared in this directory.
 
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -335,27 +335,27 @@ class TestRecursiveMakeBackend(BackendTe
                 'RESFILE := bar.res',
             ],
             'DEFFILE': [
                 'DEFFILE := baz.def',
             ],
             'USE_STATIC_LIBS': [
                 'USE_STATIC_LIBS := 1',
             ],
-            'CFLAGS': [
-                'CFLAGS += -fno-exceptions',
-                'CFLAGS += -w',
+            'MOZBUILD_CFLAGS': [
+                'MOZBUILD_CFLAGS += -fno-exceptions',
+                'MOZBUILD_CFLAGS += -w',
             ],
-            'CXXFLAGS': [
-                'CXXFLAGS += -fcxx-exceptions',
-                'CXXFLAGS += -include foo.h',
+            'MOZBUILD_CXXFLAGS': [
+                'MOZBUILD_CXXFLAGS += -fcxx-exceptions',
+                'MOZBUILD_CXXFLAGS += -include foo.h',
             ],
-            'LDFLAGS': [
-                'LDFLAGS += -framework Foo',
-                'LDFLAGS += -x',
+            'MOZBUILD_LDFLAGS': [
+                'MOZBUILD_LDFLAGS += -framework Foo',
+                'MOZBUILD_LDFLAGS += -x',
             ],
             'WIN32_EXE_LDFLAGS': [
                 'WIN32_EXE_LDFLAGS += -subsystem:console',
             ],
         }
 
         for var, val in expected.items():
             # print("test_variable_passthru[%s]" % (var))
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -171,19 +171,19 @@ class TestEmitterBasic(unittest.TestCase
             SSRCS=['bans.S', 'fans.S'],
             VISIBILITY_FLAGS='',
             DELAYLOAD_LDFLAGS=['-DELAYLOAD:foo.dll', '-DELAYLOAD:bar.dll'],
             USE_DELAYIMP=True,
             RCFILE='foo.rc',
             RESFILE='bar.res',
             DEFFILE='baz.def',
             USE_STATIC_LIBS=True,
-            CFLAGS=['-fno-exceptions', '-w'],
-            CXXFLAGS=['-fcxx-exceptions', '-include foo.h'],
-            LDFLAGS=['-framework Foo', '-x'],
+            MOZBUILD_CFLAGS=['-fno-exceptions', '-w'],
+            MOZBUILD_CXXFLAGS=['-fcxx-exceptions', '-include foo.h'],
+            MOZBUILD_LDFLAGS=['-framework Foo', '-x'],
             WIN32_EXE_LDFLAGS=['-subsystem:console'],
         )
 
         variables = objs[0].variables
         maxDiff = self.maxDiff
         self.maxDiff = None
         self.assertEqual(wanted, variables)
         self.maxDiff = maxDiff
--- a/security/apps/AppSignatureVerification.cpp
+++ b/security/apps/AppSignatureVerification.cpp
@@ -600,17 +600,18 @@ VerifySignature(AppTrustedRoot trustedRo
 
   // Verify certificate.
   AppTrustDomain trustDomain(nullptr); // TODO: null pinArg
   if (trustDomain.SetTrustedRoot(trustedRoot) != SECSuccess) {
     return MapSECStatus(SECFailure);
   }
   if (BuildCertChain(trustDomain, signerCert, PR_Now(), MustBeEndEntity,
                      KU_DIGITAL_SIGNATURE, SEC_OID_EXT_KEY_USAGE_CODE_SIGN,
-                     nullptr, builtChain) != SECSuccess) {
+                     SEC_OID_X509_ANY_POLICY, nullptr, builtChain)
+        != SECSuccess) {
     return MapSECStatus(SECFailure);
   }
 
   // See NSS_CMSContentInfo_GetContentTypeOID, which isn't exported from NSS.
   SECOidData* contentTypeOidData =
     SECOID_FindOID(&signedData->contentInfo.contentType);
   if (!contentTypeOidData) {
     return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
--- a/security/apps/AppTrustDomain.cpp
+++ b/security/apps/AppTrustDomain.cpp
@@ -107,23 +107,25 @@ AppTrustDomain::FindPotentialIssuers(con
     return SECFailure;
   }
 
   return SECSuccess;
 }
 
 SECStatus
 AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
+                             SECOidTag policy,
                              const CERTCertificate* candidateCert,
                      /*out*/ TrustLevel* trustLevel)
 {
+  MOZ_ASSERT(policy == SEC_OID_X509_ANY_POLICY);
   MOZ_ASSERT(candidateCert);
   MOZ_ASSERT(trustLevel);
   MOZ_ASSERT(mTrustedRoot);
-  if (!candidateCert || !trustLevel) {
+  if (!candidateCert || !trustLevel || policy != SEC_OID_X509_ANY_POLICY) {
     PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
     return SECFailure;
   }
   if (!mTrustedRoot) {
     PR_SetError(PR_INVALID_STATE_ERROR, 0);
     return SECFailure;
   }
 
--- a/security/apps/AppTrustDomain.h
+++ b/security/apps/AppTrustDomain.h
@@ -16,16 +16,17 @@ namespace mozilla { namespace psm {
 class AppTrustDomain MOZ_FINAL : public insanity::pkix::TrustDomain
 {
 public:
   AppTrustDomain(void* pinArg);
 
   SECStatus SetTrustedRoot(AppTrustedRoot trustedRoot);
 
   SECStatus GetCertTrust(insanity::pkix::EndEntityOrCA endEntityOrCA,
+                         SECOidTag policy,
                          const CERTCertificate* candidateCert,
                  /*out*/ TrustLevel* trustLevel) MOZ_OVERRIDE;
   SECStatus FindPotentialIssuers(const SECItem* encodedIssuerName,
                                  PRTime time,
                          /*out*/ insanity::pkix::ScopedCERTCertList& results)
                                  MOZ_OVERRIDE;
   SECStatus VerifySignedData(const CERTSignedData* signedData,
                              const CERTCertificate* cert) MOZ_OVERRIDE;
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -189,132 +189,196 @@ destroyCertListThatShouldNotExist(CERTCe
   }
 }
 #endif
 
 static SECStatus
 BuildCertChainForOneKeyUsage(TrustDomain& trustDomain, CERTCertificate* cert,
                              PRTime time, KeyUsages ku1, KeyUsages ku2,
                              KeyUsages ku3, SECOidTag eku,
+                             SECOidTag requiredPolicy,
                              const SECItem* stapledOCSPResponse,
                              ScopedCERTCertList& builtChain)
 {
   PR_ASSERT(ku1);
   PR_ASSERT(ku2);
 
   SECStatus rv = BuildCertChain(trustDomain, cert, time, MustBeEndEntity,
-                                ku1, eku, stapledOCSPResponse, builtChain);
+                                ku1, eku, requiredPolicy, stapledOCSPResponse,
+                                builtChain);
   if (rv != SECSuccess && ku2 &&
       PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
     rv = BuildCertChain(trustDomain, cert, time, MustBeEndEntity,
-                        ku2, eku, stapledOCSPResponse, builtChain);
+                        ku2, eku, requiredPolicy, stapledOCSPResponse,
+                        builtChain);
     if (rv != SECSuccess && ku3 &&
         PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
       rv = BuildCertChain(trustDomain, cert, time, MustBeEndEntity,
-                          ku3, eku, stapledOCSPResponse, builtChain);
+                          ku3, eku, requiredPolicy, stapledOCSPResponse,
+                          builtChain);
       if (rv != SECSuccess) {
         PR_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE, 0);
       }
     }
   }
   return rv;
 }
 
 SECStatus
 CertVerifier::InsanityVerifyCert(
                    CERTCertificate* cert,
                    const SECCertificateUsage usage,
                    const PRTime time,
                    void* pinArg,
                    const Flags flags,
       /*optional*/ const SECItem* stapledOCSPResponse,
-  /*optional out*/ insanity::pkix::ScopedCERTCertList* validationChain)
+  /*optional out*/ insanity::pkix::ScopedCERTCertList* validationChain,
+  /*optional out*/ SECOidTag* evOidPolicy)
 {
   PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("Top of InsanityVerifyCert\n"));
+
+  PR_ASSERT(cert);
+  PR_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
+
+  if (validationChain) {
+    *validationChain = nullptr;
+  }
+  if (evOidPolicy) {
+    *evOidPolicy = SEC_OID_UNKNOWN;
+  }
+
+  if (!cert ||
+      (usage != certificateUsageSSLServer && (flags & FLAG_MUST_BE_EV))) {
+    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+    return SECFailure;
+  }
+
+  NSSCertDBTrustDomain::OCSPFetching ocspFetching
+    = !mOCSPDownloadEnabled ||
+      (flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::NeverFetchOCSP
+    : !mOCSPStrict              ? NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
+                                : NSSCertDBTrustDomain::FetchOCSPForDVHardFail;
+
   SECStatus rv;
 
   // TODO(bug 970750): anyExtendedKeyUsage
   // TODO: encipherOnly/decipherOnly
   // S/MIME Key Usage: http://tools.ietf.org/html/rfc3850#section-4.4.2
   // S/MIME EKU:       http://tools.ietf.org/html/rfc3850#section-4.4.4
 
   // TODO(bug 915931): Pass in stapled OCSP response in all calls to
   //                   BuildCertChain.
 
   insanity::pkix::ScopedCERTCertList builtChain;
   switch (usage) {
     case certificateUsageSSLClient: {
       // XXX: We don't really have a trust bit for SSL client authentication so
       // just use trustEmail as it is the closest alternative.
-      NSSCertDBTrustDomain trustDomain(trustEmail, mOCSPDownloadEnabled,
-                                       mOCSPStrict, pinArg);
+      NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, pinArg);
       rv = BuildCertChain(trustDomain, cert, time, MustBeEndEntity,
                           KU_DIGITAL_SIGNATURE,
                           SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH,
+                          SEC_OID_X509_ANY_POLICY,
                           stapledOCSPResponse, builtChain);
       break;
     }
 
     case certificateUsageSSLServer: {
       // TODO: When verifying a certificate in an SSL handshake, we should
       // restrict the acceptable key usage based on the key exchange method
       // chosen by the server.
-      NSSCertDBTrustDomain trustDomain(trustSSL, mOCSPDownloadEnabled,
-                                       mOCSPStrict, pinArg);
+
+#ifndef MOZ_NO_EV_CERTS
+      // Try to validate for EV first.
+      SECOidTag evPolicy = SEC_OID_UNKNOWN;
+      rv = GetFirstEVPolicy(cert, evPolicy);
+      if (rv == SECSuccess && evPolicy != SEC_OID_UNKNOWN) {
+        NSSCertDBTrustDomain
+          trustDomain(trustSSL,
+                      ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP
+                        ? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
+                        : NSSCertDBTrustDomain::FetchOCSPForEV,
+                      pinArg);
+        rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
+                                          KU_DIGITAL_SIGNATURE, // ECDHE/DHE
+                                          KU_KEY_ENCIPHERMENT, // RSA
+                                          KU_KEY_AGREEMENT, // ECDH/DH
+                                          SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
+                                          evPolicy, stapledOCSPResponse,
+                                          builtChain);
+        if (rv == SECSuccess) {
+          if (evOidPolicy) {
+            *evOidPolicy = evPolicy;
+          }
+          break;
+        }
+        builtChain = nullptr; // clear built chain, just in case.
+      }
+#endif
+
+      if (flags & FLAG_MUST_BE_EV) {
+        PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
+        rv = SECFailure;
+        break;
+      }
+
+      // Now try non-EV.
+      NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, pinArg);
       rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
                                         KU_DIGITAL_SIGNATURE, // ECDHE/DHE
                                         KU_KEY_ENCIPHERMENT, // RSA
                                         KU_KEY_AGREEMENT, // ECDH/DH
                                         SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
+                                        SEC_OID_X509_ANY_POLICY,
                                         stapledOCSPResponse, builtChain);
       break;
     }
 
     case certificateUsageSSLCA: {
-      NSSCertDBTrustDomain trustDomain(trustSSL, mOCSPDownloadEnabled,
-                                       mOCSPStrict, pinArg);
+      NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, pinArg);
       rv = BuildCertChain(trustDomain, cert, time, MustBeCA,
                           KU_KEY_CERT_SIGN,
                           SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
+                          SEC_OID_X509_ANY_POLICY,
                           stapledOCSPResponse, builtChain);
       break;
     }
 
     case certificateUsageEmailSigner: {
-      NSSCertDBTrustDomain trustDomain(trustEmail, mOCSPDownloadEnabled,
-                                       mOCSPStrict, pinArg);
+      NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, pinArg);
       rv = BuildCertChain(trustDomain, cert, time, MustBeEndEntity,
                           KU_DIGITAL_SIGNATURE,
                           SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT,
+                          SEC_OID_X509_ANY_POLICY,
                           stapledOCSPResponse, builtChain);
       break;
     }
 
     case certificateUsageEmailRecipient: {
       // TODO: The higher level S/MIME processing should pass in which key
       // usage it is trying to verify for, and base its algorithm choices
       // based on the result of the verification(s).
-      NSSCertDBTrustDomain trustDomain(trustEmail, mOCSPDownloadEnabled,
-                                       mOCSPStrict, pinArg);
+      NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, pinArg);
       rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
                                         KU_KEY_ENCIPHERMENT, // RSA
                                         KU_KEY_AGREEMENT, // ECDH/DH
                                         0,
                                         SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT,
+                                        SEC_OID_X509_ANY_POLICY,
                                         stapledOCSPResponse, builtChain);
       break;
     }
 
     case certificateUsageObjectSigner: {
-      NSSCertDBTrustDomain trustDomain(trustObjectSigning,
-                                       mOCSPDownloadEnabled, mOCSPStrict,
+      NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching,
                                        pinArg);
       rv = BuildCertChain(trustDomain, cert, time, MustBeEndEntity,
                           KU_DIGITAL_SIGNATURE,
                           SEC_OID_EXT_KEY_USAGE_CODE_SIGN,
+                          SEC_OID_X509_ANY_POLICY,
                           stapledOCSPResponse, builtChain);
       break;
     }
 
     case certificateUsageVerifyCA:
     case certificateUsageStatusResponder: {
       // XXX This is a pretty useless way to verify a certificate. It is used
       // by the implementation of window.crypto.importCertificates and in the
@@ -328,31 +392,31 @@ CertVerifier::InsanityVerifyCert(
         keyUsage = KU_KEY_CERT_SIGN;
         eku = SEC_OID_UNKNOWN;
       } else {
         endEntityOrCA = MustBeEndEntity;
         keyUsage = KU_DIGITAL_SIGNATURE;
         eku = SEC_OID_OCSP_RESPONDER;
       }
 
-      NSSCertDBTrustDomain sslTrust(trustSSL,
-                                    mOCSPDownloadEnabled, mOCSPStrict, pinArg);
+      NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, pinArg);
       rv = BuildCertChain(sslTrust, cert, time, endEntityOrCA,
-                          keyUsage, eku, stapledOCSPResponse, builtChain);
+                          keyUsage, eku, SEC_OID_X509_ANY_POLICY,
+                          stapledOCSPResponse, builtChain);
       if (rv == SECFailure && PR_GetError() == SEC_ERROR_UNKNOWN_ISSUER) {
-        NSSCertDBTrustDomain emailTrust(trustEmail, mOCSPDownloadEnabled,
-                                        mOCSPStrict, pinArg);
+        NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, pinArg);
         rv = BuildCertChain(emailTrust, cert, time, endEntityOrCA, keyUsage,
-                            eku, stapledOCSPResponse, builtChain);
+                            eku, SEC_OID_X509_ANY_POLICY,
+                            stapledOCSPResponse, builtChain);
         if (rv == SECFailure && SEC_ERROR_UNKNOWN_ISSUER) {
           NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
-                                                  mOCSPDownloadEnabled,
-                                                  mOCSPStrict, pinArg);
+                                                  ocspFetching, pinArg);
           rv = BuildCertChain(objectSigningTrust, cert, time, endEntityOrCA,
-                              keyUsage, eku, stapledOCSPResponse, builtChain);
+                              keyUsage, eku, SEC_OID_X509_ANY_POLICY,
+                              stapledOCSPResponse, builtChain);
         }
       }
 
       break;
     }
 
     default:
       PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
@@ -372,16 +436,22 @@ CertVerifier::VerifyCert(CERTCertificate
                          const SECCertificateUsage usage,
                          const PRTime time,
                          void* pinArg,
                          const Flags flags,
                          /*optional out*/ ScopedCERTCertList* validationChain,
                          /*optional out*/ SECOidTag* evOidPolicy,
                          /*optional out*/ CERTVerifyLog* verifyLog)
 {
+  if (mImplementation == insanity) {
+    return InsanityVerifyCert(cert, usage, time, pinArg, flags,
+                              stapledOCSPResponse, validationChain,
+                              evOidPolicy);
+  }
+
   if (!cert)
   {
     PR_NOT_REACHED("Invalid arguments to CertVerifier::VerifyCert");
     PORT_SetError(SEC_ERROR_INVALID_ARGS);
     return SECFailure;
   }
   if (validationChain) {
     *validationChain = nullptr;
@@ -595,21 +665,16 @@ CertVerifier::VerifyCert(CERTCertificate
 #ifdef NSS_NO_LIBPKIX
     PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
 #else
     PR_SetError(PR_INVALID_STATE_ERROR, 0);
 #endif
     return SECFailure;
   }
 
-  if (mImplementation == insanity) {
-    return InsanityVerifyCert(cert, usage, time, pinArg, flags,
-                              stapledOCSPResponse, validationChain);
-  }
-
   if (mImplementation == classic) {
     // XXX: we do not care about the localOnly flag (currently) as the
     // caller that wants localOnly should disable and reenable the fetching.
     return ClassicVerifyCert(cert, usage, time, pinArg, validationChain,
                              verifyLog);
   }
 
 #ifdef NSS_NO_LIBPKIX
--- a/security/certverifier/CertVerifier.h
+++ b/security/certverifier/CertVerifier.h
@@ -78,15 +78,16 @@ public:
 
 private:
   SECStatus InsanityVerifyCert(CERTCertificate* cert,
       const SECCertificateUsage usage,
       const PRTime time,
       void* pinArg,
       const Flags flags,
       /*optional*/ const SECItem* stapledOCSPResponse,
-      /*optional out*/ insanity::pkix::ScopedCERTCertList* validationChain);
+      /*optional out*/ insanity::pkix::ScopedCERTCertList* validationChain,
+      /*optional out*/ SECOidTag* evOidPolicy);
 };
 
 void InitCertVerifierLog();
 } } // namespace mozilla::psm
 
 #endif // mozilla_psm__CertVerifier_h
--- a/security/certverifier/ExtendedValidation.cpp
+++ b/security/certverifier/ExtendedValidation.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ExtendedValidation.h"
 
 #include "cert.h"
 #include "certdb.h"
 #include "base64.h"
+#include "insanity/nullptr.h"
 #include "pk11pub.h"
 #include "secerr.h"
 #include "prerror.h"
 #include "prinit.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
 #endif
@@ -785,60 +786,85 @@ register_oid(const SECItem* oid_item, co
   od.oid.data = oid_item->data;
   od.offset = SEC_OID_UNKNOWN;
   od.desc = oid_name;
   od.mechanism = CKM_INVALID_MECHANISM;
   od.supportedExtension = INVALID_CERT_EXTENSION;
   return SECOID_AddEntry(&od);
 }
 
+#ifndef NSS_NO_LIBPKIX
 static void
 addToCertListIfTrusted(CERTCertList* certList, CERTCertificate* cert) {
   CERTCertTrust nssTrust;
   if (CERT_GetCertTrust(cert, &nssTrust) != SECSuccess) {
     return;
   }
   unsigned int flags = SEC_GET_TRUST_FLAGS(&nssTrust, trustSSL);
 
   if (flags & CERTDB_TRUSTED_CA) {
     CERT_AddCertToListTail(certList, CERT_DupCertificate(cert));
   }
 }
+#endif
 
 static bool
 isEVPolicy(SECOidTag policyOIDTag)
 {
   for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
     nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
     if (policyOIDTag == entry.oid_tag) {
       return true;
     }
   }
 
   return false;
 }
 
 namespace mozilla { namespace psm {
 
+#ifndef NSS_NO_LIBPKIX
 CERTCertList*
 GetRootsForOid(SECOidTag oid_tag)
 {
   CERTCertList* certList = CERT_NewCertList();
   if (!certList)
     return nullptr;
 
   for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
     nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
     if (entry.oid_tag == oid_tag) {
       addToCertListIfTrusted(certList, entry.cert);
     }
   }
 
   return certList;
 }
+#endif
+
+bool
+CertIsAuthoritativeForEVPolicy(const CERTCertificate* cert,
+                               SECOidTag policyOidTag)
+{
+  PR_ASSERT(cert);
+  PR_ASSERT(policyOidTag != SEC_OID_UNKNOWN);
+  if (!cert || !policyOidTag) {
+    return false;
+  }
+
+  for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
+    nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
+    if (entry.oid_tag == policyOidTag && entry.cert &&
+        CERT_CompareCerts(cert, entry.cert)) {
+      return true;
+    }
+  }
+
+  return false;
+}
 
 static PRStatus
 IdentityInfoInit()
 {
   for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) {
     nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV];
 
     SECStatus rv;
--- a/security/certverifier/ExtendedValidation.h
+++ b/security/certverifier/ExtendedValidation.h
@@ -6,18 +6,26 @@
 #ifndef mozilla_psm_ExtendedValidation_h
 #define mozilla_psm_ExtendedValidation_h
 
 #include "certt.h"
 #include "prtypes.h"
 
 namespace mozilla { namespace psm {
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
 void EnsureIdentityInfoLoaded();
-SECStatus GetFirstEVPolicy(CERTCertificate *cert, SECOidTag &outOidTag);
+void CleanupIdentityInfo();
+SECStatus GetFirstEVPolicy(CERTCertificate* cert, SECOidTag& outOidTag);
+
+// CertIsAuthoritativeForEVPolicy does NOT evaluate whether the cert is trusted
+// or distrusted.
+bool CertIsAuthoritativeForEVPolicy(const CERTCertificate* cert,
+                                    SECOidTag policyOidTag);
+#endif
+
+#ifndef NSS_NO_LIBPKIX
 CERTCertList* GetRootsForOid(SECOidTag oid_tag);
-void CleanupIdentityInfo();
 #endif
 
 } } // namespace mozilla::psm
 
 #endif // mozilla_psm_ExtendedValidation_h
--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "NSSCertDBTrustDomain.h"
 
 #include <stdint.h>
 
+#include "ExtendedValidation.h"
 #include "insanity/pkix.h"
 #include "certdb.h"
 #include "nss.h"
 #include "ocsp.h"
 #include "pk11pub.h"
 #include "prerror.h"
 #include "prmem.h"
 #include "prprf.h"
@@ -33,22 +34,20 @@ namespace {
 
 inline void PORT_Free_string(char* str) { PORT_Free(str); }
 
 typedef ScopedPtr<SECMODModule, SECMOD_DestroyModule> ScopedSECMODModule;
 
 } // unnamed namespace
 
 NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
-                                           bool ocspDownloadEnabled,
-                                           bool ocspStrict,
+                                           OCSPFetching ocspFetching,
                                            void* pinArg)
   : mCertDBTrustType(certDBTrustType)
-  , mOCSPDownloadEnabled(ocspDownloadEnabled)
-  , mOCSPStrict(ocspStrict)
+  , mOCSPFetching(ocspFetching)
   , mPinArg(pinArg)
 {
 }
 
 SECStatus
 NSSCertDBTrustDomain::FindPotentialIssuers(
   const SECItem* encodedIssuerName, PRTime time,
   /*out*/ insanity::pkix::ScopedCERTCertList& results)
@@ -67,26 +66,35 @@ NSSCertDBTrustDomain::FindPotentialIssue
     return SECFailure;
   }
 
   return SECSuccess;
 }
 
 SECStatus
 NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
+                                   SECOidTag policy,
                                    const CERTCertificate* candidateCert,
                                    /*out*/ TrustLevel* trustLevel)
 {
-  PORT_Assert(candidateCert);
-  PORT_Assert(trustLevel);
+  PR_ASSERT(candidateCert);
+  PR_ASSERT(trustLevel);
+
   if (!candidateCert || !trustLevel) {
-    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
     return SECFailure;
   }
 
+#ifdef MOZ_NO_EV_CERTS
+  if (policy != SEC_OID_X509_ANY_POLICY) {
+    PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
+    return SECFailure;
+  }
+#endif
+
   // XXX: CERT_GetCertTrust seems to be abusing SECStatus as a boolean, where
   // SECSuccess means that there is a trust record and SECFailure means there
   // is not a trust record. I looked at NSS's internal uses of
   // CERT_GetCertTrust, and all that code uses the result as a boolean meaning
   // "We have a trust record."
   CERTCertTrust trust;
   if (CERT_GetCertTrust(candidateCert, &trust) == SECSuccess) {
     PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, mCertDBTrustType);
@@ -103,18 +111,26 @@ NSSCertDBTrustDomain::GetCertTrust(EndEn
       *trustLevel = ActivelyDistrusted;
       return SECSuccess;
     }
 
     // For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Gecko hasn't
     // needed to consider end-entity certs to be their own trust anchors since
     // Gecko implemented nsICertOverrideService.
     if (flags & CERTDB_TRUSTED_CA) {
-      *trustLevel = TrustAnchor;
-      return SECSuccess;
+      if (policy == SEC_OID_X509_ANY_POLICY) {
+        *trustLevel = TrustAnchor;
+        return SECSuccess;
+      }
+#ifndef MOZ_NO_EV_CERTS
+      if (CertIsAuthoritativeForEVPolicy(candidateCert, policy)) {
+        *trustLevel = TrustAnchor;
+        return SECSuccess;
+      }
+#endif
     }
   }
 
   *trustLevel = InheritsTrust;
   return SECSuccess;
 }
 
 SECStatus
@@ -159,80 +175,93 @@ NSSCertDBTrustDomain::CheckRevocation(
     if (rv == SECSuccess) {
       return rv;
     }
     if (PR_GetError() != SEC_ERROR_OCSP_OLD_RESPONSE) {
       return rv;
     }
   }
 
-  // TODO(bug 921885): We need to change this when we add EV support.
+  // TODO(bug 915932): Need to change this when we add the OCSP cache.
+
+  // TODO: We still need to handle the fallback for expired responses. But,
+  // if/when we disable OCSP fetching by default, it would be ambiguous whether
+  // security.OCSP.enable==0 means "I want the default" or "I really never want
+  // you to ever fetch OCSP."
+
+  if ((mOCSPFetching == NeverFetchOCSP) ||
+      (endEntityOrCA == MustBeCA && (mOCSPFetching == FetchOCSPForDVHardFail ||
+                                     mOCSPFetching == FetchOCSPForDVSoftFail))) {
+    return SECSuccess;
+  }
 
-  // TODO: when !mOCSPDownloadEnabled, we still need to handle the fallback for
-  // expired responses. But, if/when we disable OCSP fetching by default, it
-  // would be ambiguous whether !mOCSPDownloadEnabled means "I want the default"
-  // or "I really never want you to ever fetch OCSP."
-  if (mOCSPDownloadEnabled) {
-    // We don't do OCSP fetching for intermediates.
-    if (endEntityOrCA == MustBeCA) {
-      PR_ASSERT(!stapledOCSPResponse);
-      return SECSuccess;
+  if (mOCSPFetching == LocalOnlyOCSPForEV) {
+    PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0);
+    return SECFailure;
+  }
+
+  ScopedPtr<char, PORT_Free_string>
+    url(CERT_GetOCSPAuthorityInfoAccessLocation(cert));
+
+  if (!url) {
+    if (stapledOCSPResponse) {
+      PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0);
+      return SECFailure;
     }
-
-    ScopedPtr<char, PORT_Free_string>
-      url(CERT_GetOCSPAuthorityInfoAccessLocation(cert));
+    if (mOCSPFetching == FetchOCSPForEV) {
+      PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0);
+      return SECFailure;
+    }
 
     // Nothing to do if we don't have an OCSP responder URI for the cert; just
     // assume it is good. Note that this is the confusing, but intended,
     // interpretation of "strict" revocation checking in the face of a
     // certificate that lacks an OCSP responder URI.
-    if (!url) {
-      if (stapledOCSPResponse) {
-        PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0);
-        return SECFailure;
-      }
-      return SECSuccess;
-    }
+    return SECSuccess;
+  }
+
+  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+  if (!arena) {
+    return SECFailure;
+  }
 
-    ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
-    if (!arena) {
-      return SECFailure;
-    }
+  const SECItem* request(CreateEncodedOCSPRequest(arena.get(), cert,
+                                                  issuerCert));
+  if (!request) {
+    return SECFailure;
+  }
 
-    const SECItem* request
-      = CreateEncodedOCSPRequest(arena.get(), cert, issuerCert);
-    if (!request) {
+  const SECItem* response(CERT_PostOCSPRequest(arena.get(), url.get(),
+                                               request));
+  if (!response) {
+    if (mOCSPFetching != FetchOCSPForDVSoftFail) {
+      PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
+             ("NSSCertDBTrustDomain: returning SECFailure after "
+              "CERT_PostOCSPRequest failure"));
       return SECFailure;
     }
 
-    const SECItem* response(CERT_PostOCSPRequest(arena.get(), url.get(),
-                                                 request));
-    if (!response) {
-      if (mOCSPStrict) {
-        return SECFailure;
-      }
-      // Soft fail -> success :(
-    } else {
-      SECStatus rv = VerifyEncodedOCSPResponse(*this, cert, issuerCert, time,
-                                               response);
-      if (rv == SECSuccess) {
-        return SECSuccess;
-      }
-      PRErrorCode error = PR_GetError();
-      switch (error) {
-        case SEC_ERROR_OCSP_UNKNOWN_CERT:
-        case SEC_ERROR_REVOKED_CERTIFICATE:
-          return SECFailure;
-        default:
-          if (mOCSPStrict) {
-            return SECFailure;
-          }
-          break; // Soft fail -> success :(
-      }
-    }
+    PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
+           ("NSSCertDBTrustDomain: returning SECSuccess after "
+            "CERT_PostOCSPRequest failure"));
+    return SECSuccess; // Soft fail -> success :(
+  }
+
+  SECStatus rv = VerifyEncodedOCSPResponse(*this, cert, issuerCert, time,
+                                           response);
+  if (rv == SECSuccess || mOCSPFetching != FetchOCSPForDVSoftFail) {
+    PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
+      ("NSSCertDBTrustDomain: returning after VerifyEncodedOCSPResponse"));
+    return rv;
+  }
+
+  PRErrorCode error = PR_GetError();
+  if (error == SEC_ERROR_OCSP_UNKNOWN_CERT ||
+      error == SEC_ERROR_REVOKED_CERTIFICATE) {
+    return rv;
   }
 
   PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
          ("NSSCertDBTrustDomain: end of CheckRevocation"));
 
   return SECSuccess;
 }
 
--- a/security/certverifier/NSSCertDBTrustDomain.h
+++ b/security/certverifier/NSSCertDBTrustDomain.h
@@ -42,40 +42,46 @@ SetClassicOCSPBehavior(CertVerifier::ocs
 char* DefaultServerNicknameForCert(CERTCertificate* cert);
 
 void SaveIntermediateCerts(const insanity::pkix::ScopedCERTCertList& certList);
 
 class NSSCertDBTrustDomain : public insanity::pkix::TrustDomain
 {
 
 public:
-  NSSCertDBTrustDomain(SECTrustType certDBTrustType,
-                       bool ocspDownloadEnabled, bool ocspStrict,
+  enum OCSPFetching {
+    NeverFetchOCSP = 0,
+    FetchOCSPForDVSoftFail = 1,
+    FetchOCSPForDVHardFail = 2,
+    FetchOCSPForEV = 3,
+    LocalOnlyOCSPForEV = 4,
+  };
+  NSSCertDBTrustDomain(SECTrustType certDBTrustType, OCSPFetching ocspFetching,
                        void* pinArg);
 
   virtual SECStatus FindPotentialIssuers(
                         const SECItem* encodedIssuerName,
                         PRTime time,
                 /*out*/ insanity::pkix::ScopedCERTCertList& results);
 
   virtual SECStatus GetCertTrust(insanity::pkix::EndEntityOrCA endEntityOrCA,
+                                 SECOidTag policy,
                                  const CERTCertificate* candidateCert,
                          /*out*/ TrustLevel* trustLevel);
 
   virtual SECStatus VerifySignedData(const CERTSignedData* signedData,
                                      const CERTCertificate* cert);
 
   virtual SECStatus CheckRevocation(insanity::pkix::EndEntityOrCA endEntityOrCA,
                                     const CERTCertificate* cert,
                           /*const*/ CERTCertificate* issuerCert,
                                     PRTime time,
                        /*optional*/ const SECItem* stapledOCSPResponse);
 
 private:
   const SECTrustType mCertDBTrustType;
-  const bool mOCSPDownloadEnabled;
-  const bool mOCSPStrict;
+  const OCSPFetching mOCSPFetching;
   void* mPinArg; // non-owning!
 };
 
 } } // namespace mozilla::psm
 
 #endif // mozilla_psm__NSSCertDBTrustDomain_h
--- a/security/certverifier/moz.build
+++ b/security/certverifier/moz.build
@@ -9,17 +9,17 @@ UNIFIED_SOURCES += [
     '../insanity/lib/pkixcheck.cpp',
     '../insanity/lib/pkixder.cpp',
     '../insanity/lib/pkixkey.cpp',
     '../insanity/lib/pkixocsp.cpp',
     'CertVerifier.cpp',
     'NSSCertDBTrustDomain.cpp',
 ]
 
-if not CONFIG['NSS_NO_LIBPKIX']:
+if not CONFIG['NSS_NO_EV_CERTS']:
     UNIFIED_SOURCES += [
         'ExtendedValidation.cpp',
     ]
 
 LOCAL_INCLUDES += [
     '../insanity/include',
 ]
 
--- a/security/insanity/include/insanity/pkix.h
+++ b/security/insanity/include/insanity/pkix.h
@@ -19,16 +19,33 @@
 #define insanity_pkix__pkix_h
 
 #include "pkixtypes.h"
 #include "prtime.h"
 
 namespace insanity { namespace pkix {
 
 // ----------------------------------------------------------------------------
+// LIMITED SUPPORT FOR CERTIFICATE POLICIES
+//
+// If SEC_OID_X509_ANY_POLICY is passed as the value of the requiredPolicy
+// parameter then all policy validation will be skipped. Otherwise, path
+// building and validation will be done for the given policy.
+//
+// In RFC 5280 terms:
+//
+//    * user-initial-policy-set = { requiredPolicy }.
+//    * initial-explicit-policy = true
+//    * initial-any-policy-inhibit = true
+//
+// Because we force explicit policy and because we prohibit policy mapping, we
+// do not bother processing the policy mapping, policy constraint, or inhibit
+// anyPolicy extensions.
+//
+// ----------------------------------------------------------------------------
 // ERROR RANKING
 //
 // BuildCertChain prioritizes certain checks ahead of others so that when a
 // certificate chain has multiple errors, the "most serious" error is
 // returned. In practice, this ranking of seriousness is tied directly to how
 // Firefox's certificate error override mechanism.
 //
 // The ranking is:
@@ -66,16 +83,17 @@ namespace insanity { namespace pkix {
 // TODO(bug 968451): Document more of these.
 
 SECStatus BuildCertChain(TrustDomain& trustDomain,
                          CERTCertificate* cert,
                          PRTime time,
                          EndEntityOrCA endEntityOrCA,
             /*optional*/ KeyUsages requiredKeyUsagesIfPresent,
             /*optional*/ SECOidTag requiredEKUIfPresent,
+            /*optional*/ SECOidTag requiredPolicy,
             /*optional*/ const SECItem* stapledOCSPResponse,
                  /*out*/ ScopedCERTCertList& results);
 
 // Verify the given signed data using the public key of the given certificate.
 // (EC)DSA parameter inheritance is not supported.
 SECStatus VerifySignedData(const CERTSignedData* sd,
                            const CERTCertificate* cert,
                            void* pkcs11PinArg);
--- a/security/insanity/include/insanity/pkixtypes.h
+++ b/security/insanity/include/insanity/pkixtypes.h
@@ -43,25 +43,35 @@ enum EndEntityOrCA { MustBeEndEntity, Mu
 // distrusted.
 class TrustDomain
 {
 public:
   virtual ~TrustDomain() { }
 
   enum TrustLevel {
     TrustAnchor = 1,        // certificate is a trusted root CA certificate or
-                            // equivalent
+                            // equivalent *for the given policy*.
     ActivelyDistrusted = 2, // certificate is known to be bad
     InheritsTrust = 3       // certificate must chain to a trust anchor
   };
 
   // Determine the level of trust in the given certificate for the given role.
   // This will be called for every certificate encountered during path
   // building.
+  //
+  // When policy == SEC_OID_X509_ANY_POLICY, then no policy-related checking
+  // should be done. When policy != SEC_OID_X509_ANY_POLICY, then GetCertTrust
+  // MUST NOT return with *trustLevel == TrustAnchor unless the given cert is
+  // considered a trust anchor *for that policy*. In particular, if the user
+  // has marked an intermediate certificate as trusted, but that intermediate
+  // isn't in the list of EV roots, then GetCertTrust must result in
+  // *trustLevel == InheritsTrust instead of *trustLevel == TrustAnchor
+  // (assuming the candidate cert is not actively distrusted).
   virtual SECStatus GetCertTrust(EndEntityOrCA endEntityOrCA,
+                                 SECOidTag policy,
                                  const CERTCertificate* candidateCert,
                          /*out*/ TrustLevel* trustLevel) = 0;
 
   // Find all certificates (intermediate and/or root) in the certificate
   // database that have a subject name matching |encodedIssuerName| at
   // the given time. Certificates where the given time is not within the
   // certificate's validity period may be excluded. The results should be
   // added to the |results| certificate list.
--- a/security/insanity/lib/pkixbuild.cpp
+++ b/security/insanity/lib/pkixbuild.cpp
@@ -50,16 +50,17 @@ BackCert::Init()
         ext->id.data[0] == 0x55 && ext->id.data[1] == 0x1d) {
       // { id-ce x }
       switch (ext->id.data[2]) {
         case 14: out = &dummyEncodedSubjectKeyIdentifier; break; // bug 965136
         case 15: out = &encodedKeyUsage; break;
         case 17: out = &dummyEncodedSubjectAltName; break; // bug 970542
         case 19: out = &encodedBasicConstraints; break;
         case 30: out = &encodedNameConstraints; break;
+        case 32: out = &encodedCertificatePolicies; break;
         case 35: out = &dummyEncodedAuthorityKeyIdentifier; break; // bug 965136
         case 37: out = &encodedExtendedKeyUsage; break;
       }
     } else if (ext->id.len == 9 &&
                ext->id.data[0] == 0x2b && ext->id.data[1] == 0x06 &&
                ext->id.data[2] == 0x06 && ext->id.data[3] == 0x01 &&
                ext->id.data[4] == 0x05 && ext->id.data[5] == 0x05 &&
                ext->id.data[6] == 0x07 && ext->id.data[7] == 0x01) {
@@ -91,27 +92,29 @@ BackCert::Init()
 }
 
 static Result BuildForward(TrustDomain& trustDomain,
                            BackCert& subject,
                            PRTime time,
                            EndEntityOrCA endEntityOrCA,
                            KeyUsages requiredKeyUsagesIfPresent,
                            SECOidTag requiredEKUIfPresent,
+                           SECOidTag requiredPolicy,
                            /*optional*/ const SECItem* stapledOCSPResponse,
                            unsigned int subCACount,
                            /*out*/ ScopedCERTCertList& results);
 
 // The code that executes in the inner loop of BuildForward
 static Result
 BuildForwardInner(TrustDomain& trustDomain,
                   BackCert& subject,
                   PRTime time,
                   EndEntityOrCA endEntityOrCA,
                   SECOidTag requiredEKUIfPresent,
+                  SECOidTag requiredPolicy,
                   CERTCertificate* potentialIssuerCertToDup,
                   /*optional*/ const SECItem* stapledOCSPResponse,
                   unsigned int subCACount,
                   ScopedCERTCertList& results)
 {
   PORT_Assert(potentialIssuerCertToDup);
 
   BackCert potentialIssuer(potentialIssuerCertToDup, &subject,
@@ -145,17 +148,17 @@ BuildForwardInner(TrustDomain& trustDoma
 
   unsigned int newSubCACount = subCACount;
   if (endEntityOrCA == MustBeCA) {
     newSubCACount = subCACount + 1;
   } else {
     PR_ASSERT(newSubCACount == 0);
   }
   rv = BuildForward(trustDomain, potentialIssuer, time, MustBeCA,
-                    KU_KEY_CERT_SIGN, requiredEKUIfPresent,
+                    KU_KEY_CERT_SIGN, requiredEKUIfPresent, requiredPolicy,
                     nullptr, newSubCACount, results);
   if (rv != Success) {
     return rv;
   }
 
   if (trustDomain.VerifySignedData(&subject.GetNSSCert()->signatureWrap,
                                    potentialIssuer.GetNSSCert()) != SECSuccess) {
     return MapSECStatus(SECFailure);
@@ -172,16 +175,17 @@ BuildForwardInner(TrustDomain& trustDoma
 // insanity/pkix.h.
 static Result
 BuildForward(TrustDomain& trustDomain,
              BackCert& subject,
              PRTime time,
              EndEntityOrCA endEntityOrCA,
              KeyUsages requiredKeyUsagesIfPresent,
              SECOidTag requiredEKUIfPresent,
+             SECOidTag requiredPolicy,
              /*optional*/ const SECItem* stapledOCSPResponse,
              unsigned int subCACount,
              /*out*/ ScopedCERTCertList& results)
 {
   // Avoid stack overflows and poor performance by limiting cert length.
   // XXX: 6 is not enough for chains.sh anypolicywithlevel.cfg tests
   static const size_t MAX_DEPTH = 8;
   if (subCACount >= MAX_DEPTH - 1) {
@@ -190,18 +194,18 @@ BuildForward(TrustDomain& trustDomain,
 
   Result rv;
 
   TrustDomain::TrustLevel trustLevel;
   bool expiredEndEntity = false;
   rv = CheckIssuerIndependentProperties(trustDomain, subject, time,
                                         endEntityOrCA,
                                         requiredKeyUsagesIfPresent,
-                                        requiredEKUIfPresent, subCACount,
-                                        &trustLevel);
+                                        requiredEKUIfPresent, requiredPolicy,
+                                        subCACount, &trustLevel);
   if (rv != Success) {
     // CheckIssuerIndependentProperties checks for expiration last, so if
     // it returned SEC_ERROR_EXPIRED_CERTIFICATE we know that is the only
     // problem with the cert found so far. Keep going to see if we can build
     // a path; if not, it's better to return the path building failure.
     expiredEndEntity = endEntityOrCA == MustBeEndEntity &&
                        trustLevel != TrustDomain::TrustAnchor &&
                        PR_GetError() == SEC_ERROR_EXPIRED_CERTIFICATE;
@@ -233,17 +237,17 @@ BuildForward(TrustDomain& trustDomain,
     return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER);
   }
 
   PRErrorCode errorToReturn = 0;
 
   for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
        !CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
     rv = BuildForwardInner(trustDomain, subject, time, endEntityOrCA,
-                           requiredEKUIfPresent,
+                           requiredEKUIfPresent, requiredPolicy,
                            n->cert, stapledOCSPResponse, subCACount,
                            results);
     if (rv == Success) {
       if (expiredEndEntity) {
         // We deferred returning this error to see if we should return
         // "unknown issuer" instead. Since we found a valid issuer, it's
         // time to return "expired."
         PR_SetError(SEC_ERROR_EXPIRED_CERTIFICATE, 0);
@@ -293,16 +297,17 @@ BuildForward(TrustDomain& trustDomain,
 
 SECStatus
 BuildCertChain(TrustDomain& trustDomain,
                CERTCertificate* certToDup,
                PRTime time,
                EndEntityOrCA endEntityOrCA,
                /*optional*/ KeyUsages requiredKeyUsagesIfPresent,
                /*optional*/ SECOidTag requiredEKUIfPresent,
+               /*optional*/ SECOidTag requiredPolicy,
                /*optional*/ const SECItem* stapledOCSPResponse,
                /*out*/ ScopedCERTCertList& results)
 {
   PORT_Assert(certToDup);
 
   if (!certToDup) {
     PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
     return SECFailure;
@@ -322,17 +327,17 @@ BuildCertChain(TrustDomain& trustDomain,
   BackCert cert(certToDup, nullptr, cnOptions);
   Result rv = cert.Init();
   if (rv != Success) {
     return SECFailure;
   }
 
   rv = BuildForward(trustDomain, cert, time, endEntityOrCA,
                     requiredKeyUsagesIfPresent, requiredEKUIfPresent,
-                    stapledOCSPResponse, 0, results);
+                    requiredPolicy, stapledOCSPResponse, 0, results);
   if (rv != Success) {
     results = nullptr;
     return SECFailure;
   }
 
   return SECSuccess;
 }
 
--- a/security/insanity/lib/pkixcheck.cpp
+++ b/security/insanity/lib/pkixcheck.cpp
@@ -92,16 +92,66 @@ CheckKeyUsage(EndEntityOrCA endEntityOrC
     //  // XXX: better error code.
     //  return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
     //}
   }
 
   return Success;
 }
 
+// RFC5820 4.2.1.4. Certificate Policies
+//
+// "The user-initial-policy-set contains the special value any-policy if the
+// user is not concerned about certificate policy."
+Result
+CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA,
+                         bool isTrustAnchor, SECOidTag requiredPolicy)
+{
+  if (requiredPolicy == SEC_OID_X509_ANY_POLICY) {
+    return Success;
+  }
+
+  // It is likely some callers will pass SEC_OID_UNKNOWN when they don't care,
+  // instead of passing SEC_OID_X509_ANY_POLICY. Help them out by failing hard.
+  if (requiredPolicy == SEC_OID_UNKNOWN) {
+    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
+    return FatalError;
+  }
+
+  // The root CA certificate may omit the policies that it has been
+  // trusted for, so we cannot require the policies to be present in those
+  // certificates. Instead, the determination of which roots are trusted for
+  // which policies is made by the TrustDomain's GetCertTrust method.
+  if (isTrustAnchor && endEntityOrCA == MustBeCA) {
+    return Success;
+  }
+
+  if (!cert.encodedCertificatePolicies) {
+    PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
+    return RecoverableError;
+  }
+
+  ScopedPtr<CERTCertificatePolicies, CERT_DestroyCertificatePoliciesExtension>
+    policies(CERT_DecodeCertificatePoliciesExtension(
+                cert.encodedCertificatePolicies));
+  if (!policies) {
+    return MapSECStatus(SECFailure);
+  }
+
+  for (const CERTPolicyInfo* const* policyInfos = policies->policyInfos;
+       *policyInfos; ++policyInfos) {
+    if ((*policyInfos)->oid == requiredPolicy) {
+      return Success;
+    }
+  }
+
+  PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
+  return RecoverableError;
+}
+
 // RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints)
 Result
 CheckBasicConstraints(const BackCert& cert,
                       EndEntityOrCA endEntityOrCA,
                       bool isTrustAnchor,
                       unsigned int subCACount)
 {
   CERTBasicConstraints basicConstraints;
@@ -324,23 +374,25 @@ CheckExtendedKeyUsage(EndEntityOrCA endE
 
 Result
 CheckIssuerIndependentProperties(TrustDomain& trustDomain,
                                  BackCert& cert,
                                  PRTime time,
                                  EndEntityOrCA endEntityOrCA,
                                  KeyUsages requiredKeyUsagesIfPresent,
                                  SECOidTag requiredEKUIfPresent,
+                                 SECOidTag requiredPolicy,
                                  unsigned int subCACount,
                 /*optional out*/ TrustDomain::TrustLevel* trustLevelOut)
 {
   Result rv;
 
   TrustDomain::TrustLevel trustLevel;
   rv = MapSECStatus(trustDomain.GetCertTrust(endEntityOrCA,
+                                             requiredPolicy,
                                              cert.GetNSSCert(),
                                              &trustLevel));
   if (rv != Success) {
     return rv;
   }
   if (trustLevel == TrustDomain::ActivelyDistrusted) {
     PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
     return RecoverableError;
@@ -353,58 +405,74 @@ CheckIssuerIndependentProperties(TrustDo
   }
   if (trustLevelOut) {
     *trustLevelOut = trustLevel;
   }
 
   bool isTrustAnchor = endEntityOrCA == MustBeCA &&
                        trustLevel == TrustDomain::TrustAnchor;
 
-  // 4.2.1.1. Authority Key Identifier dealt with as part of path building
-  // 4.2.1.2. Subject Key Identifier dealt with as part of path building
-
   PLArenaPool* arena = cert.GetArena();
   if (!arena) {
     return FatalError;
   }
 
+  // 4.2.1.1. Authority Key Identifier is ignored (see bug 965136).
+
+  // 4.2.1.2. Subject Key Identifier is ignored (see bug 965136).
+
   // 4.2.1.3. Key Usage
-
   rv = CheckKeyUsage(endEntityOrCA, isTrustAnchor, cert.encodedKeyUsage,
                      requiredKeyUsagesIfPresent, arena);
   if (rv != Success) {
     return rv;
   }
 
   // 4.2.1.4. Certificate Policies
-  // 4.2.1.5. Policy Mappings are rejected in BackCert::Init()
-  // 4.2.1.6. Subject Alternative Name dealt with elsewhere
-  // 4.2.1.7. Issuer Alternative Name is not something that needs checking
-  // 4.2.1.8. Subject Directory Attributes is not something that needs checking
+  rv = CheckCertificatePolicies(cert, endEntityOrCA, isTrustAnchor,
+                                requiredPolicy);
+  if (rv != Success) {
+    return rv;
+  }
+
+  // 4.2.1.5. Policy Mappings are not supported; see the documentation about
+  //          policy enforcement in pkix.h.
 
-  // 4.2.1.9. Basic Constraints. We check basic constraints before other
-  // properties that take endEntityOrCA so that those checks can use
-  // endEntityOrCA as a proxy for the isCA bit from the basic constraints.
+  // 4.2.1.6. Subject Alternative Name dealt with during name constraint
+  //          checking and during name verification (CERT_VerifyCertName).
+
+  // 4.2.1.7. Issuer Alternative Name is not something that needs checking.
+
+  // 4.2.1.8. Subject Directory Attributes is not something that needs
+  //          checking.
+
+  // 4.2.1.9. Basic Constraints.
   rv = CheckBasicConstraints(cert, endEntityOrCA, isTrustAnchor, subCACount);
   if (rv != Success) {
     return rv;
   }
 
-  // 4.2.1.10. Name Constraints
-  // 4.2.1.11. Policy Constraints
+  // 4.2.1.10. Name Constraints is dealt with in during path building.
+
+  // 4.2.1.11. Policy Constraints are implicitly supported; see the
+  //           documentation about policy enforcement in pkix.h.
 
   // 4.2.1.12. Extended Key Usage
   rv = CheckExtendedKeyUsage(endEntityOrCA, cert.encodedExtendedKeyUsage,
                              requiredEKUIfPresent);
   if (rv != Success) {
     return rv;
   }
 
-  // 4.2.1.13. CRL Distribution Points will be dealt with elsewhere
-  // 4.2.1.14. Inhibit anyPolicy
+  // 4.2.1.13. CRL Distribution Points is not supported, though the
+  //           TrustDomain's CheckRevocation method may parse it and process it
+  //           on its own.
+
+  // 4.2.1.14. Inhibit anyPolicy is implicitly supported; see the documentation
+  //           about policy enforcement in pkix.h.
 
   // IMPORTANT: This check must come after the other checks in order for error
   // ranking to work correctly.
   rv = CheckTimes(cert.GetNSSCert(), time);
   if (rv != Success) {
     return rv;
   }
 
--- a/security/insanity/lib/pkixcheck.h
+++ b/security/insanity/lib/pkixcheck.h
@@ -25,16 +25,17 @@ namespace insanity { namespace pkix {
 
 Result CheckIssuerIndependentProperties(
           TrustDomain& trustDomain,
           BackCert& cert,
           PRTime time,
           EndEntityOrCA endEntityOrCA,
           KeyUsages requiredKeyUsagesIfPresent,
           SECOidTag requiredEKUIfPresent,
+          SECOidTag requiredPolicy,
           unsigned int subCACount,
           /*optional out*/ TrustDomain::TrustLevel* trustLevel = nullptr);
 
 Result CheckNameConstraints(BackCert& cert);
 
 } } // namespace insanity::pkix
 
 #endif // insanity__pkixcheck_h
--- a/security/insanity/lib/pkixocsp.cpp
+++ b/security/insanity/lib/pkixocsp.cpp
@@ -110,17 +110,18 @@ CheckOCSPResponseSignerCert(TrustDomain&
   // SEC_OID_OCSP_RESPONDER in the way that the OCSP specification requires us
   // to--in particular, it doesn't allow SEC_OID_OCSP_RESPONDER to be implied
   // by a missing EKU extension, unlike other EKUs.
   //
   // TODO(bug 926261): If we're validating for a policy then the policy OID we
   // are validating for should be passed to CheckIssuerIndependentProperties.
   rv = CheckIssuerIndependentProperties(trustDomain, cert, time,
                                         MustBeEndEntity, 0,
-                                        SEC_OID_OCSP_RESPONDER, 0);
+                                        SEC_OID_OCSP_RESPONDER,
+                                        SEC_OID_X509_ANY_POLICY, 0);
   if (rv != Success) {
     return rv;
   }
 
   // It is possible that there exists a certificate with the same key as the
   // issuer but with a different name, so we need to compare names
   // TODO: needs test
   if (!SECITEM_ItemsAreEqual(&cert.GetNSSCert()->derIssuer,
--- a/security/insanity/lib/pkixutil.h
+++ b/security/insanity/lib/pkixutil.h
@@ -85,29 +85,31 @@ public:
   // its results. IncludeCN means that GetConstrainedNames will include the
   // subject CN in its results.
   enum ConstrainedNameOptions { ExcludeCN = 0, IncludeCN = 1 };
 
   // nssCert and childCert must be valid for the lifetime of BackCert
   BackCert(CERTCertificate* nssCert, BackCert* childCert,
            ConstrainedNameOptions cnOptions)
     : encodedBasicConstraints(nullptr)
+    , encodedCertificatePolicies(nullptr)
     , encodedExtendedKeyUsage(nullptr)
     , encodedKeyUsage(nullptr)
     , encodedNameConstraints(nullptr)
     , childCert(childCert)
     , nssCert(nssCert)
     , constrainedNames(nullptr)
     , cnOptions(cnOptions)
   {
   }
 
   Result Init();
 
   const SECItem* encodedBasicConstraints;
+  const SECItem* encodedCertificatePolicies;
   const SECItem* encodedExtendedKeyUsage;
   const SECItem* encodedKeyUsage;
   const SECItem* encodedNameConstraints;
 
   BackCert* const childCert;
 
   // Only non-const so that we can pass this to TrustDomain::IsRevoked,
   // which only takes a non-const pointer because VerifyEncodedOCSPResponse
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -1320,33 +1320,33 @@ AuthCertificateHook(void* arg, PRFileDes
     NS_ERROR("error code not set");
     error = PR_UNKNOWN_ERROR;
   }
 
   PR_SetError(error, 0);
   return SECFailure;
 }
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
 class InitializeIdentityInfo : public CryptoTask
 {
   virtual nsresult CalculateResult() MOZ_OVERRIDE
   {
     EnsureIdentityInfoLoaded();
     return NS_OK;
   }
 
   virtual void ReleaseNSSResources() MOZ_OVERRIDE { } // no-op
   virtual void CallCallback(nsresult rv) MOZ_OVERRIDE { } // no-op
 };
 #endif
 
 void EnsureServerVerificationInitialized()
 {
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
   // Should only be called from socket transport thread due to the static
   // variable and the reference to gCertVerificationThreadPool
 
   static bool triggeredCertVerifierInit = false;
   if (triggeredCertVerifierInit)
     return;
   triggeredCertVerifierInit = true;
 
--- a/security/manager/ssl/src/nsNSSCertHelper.cpp
+++ b/security/manager/ssl/src/nsNSSCertHelper.cpp
@@ -2083,17 +2083,17 @@ nsNSSCertificate::CreateTBSCertificateAS
     nssComponent->GetPIPNSSBundleString("CertDumpSubjectUniqueID", text);
     printableItem->SetDisplayName(text);
     asn1Objects->AppendElement(printableItem, false);
 
   }
   if (mCert->extensions) {
     SECOidTag ev_oid_tag = SEC_OID_UNKNOWN;
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
     bool validEV;
     rv = hasValidEVOidTag(ev_oid_tag, validEV);
     if (NS_FAILED(rv))
       return rv;
 
     if (!validEV)
       ev_oid_tag = SEC_OID_UNKNOWN;
 #endif
--- a/security/manager/ssl/src/nsNSSCertificate.cpp
+++ b/security/manager/ssl/src/nsNSSCertificate.cpp
@@ -1416,17 +1416,17 @@ nsNSSCertificate::SaveSMimeProfile()
     return NS_ERROR_NOT_AVAILABLE;
 
   if (SECSuccess != CERT_SaveSMimeProfile(mCert.get(), nullptr, nullptr))
     return NS_ERROR_FAILURE;
   else
     return NS_OK;
 }
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
 
 nsresult
 nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV)
 {
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown())
     return NS_ERROR_NOT_AVAILABLE;
 
@@ -1471,22 +1471,22 @@ nsNSSCertificate::getValidEVOidTag(SECOi
     if (validEV) {
       mCachedEVOidTag = resultOidTag;
     }
     mCachedEVStatus = validEV ? ev_status_valid : ev_status_invalid;
   }
   return rv;
 }
 
-#endif // NSS_NO_LIBPKIX
+#endif // MOZ_NO_EV_CERTS
 
 NS_IMETHODIMP
 nsNSSCertificate::GetIsExtendedValidation(bool* aIsEV)
 {
-#ifdef NSS_NO_LIBPKIX
+#ifdef MOZ_NO_EV_CERTS
   *aIsEV = false;
   return NS_OK;
 #else
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
@@ -1503,17 +1503,17 @@ nsNSSCertificate::GetIsExtendedValidatio
 #endif
 }
 
 NS_IMETHODIMP
 nsNSSCertificate::GetValidEVPolicyOid(nsACString& outDottedOid)
 {
   outDottedOid.Truncate();
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   SECOidTag oid_tag;
   bool valid;
   nsresult rv = getValidEVOidTag(oid_tag, valid);
--- a/security/manager/ssl/src/nsNSSCertificateDB.cpp
+++ b/security/manager/ssl/src/nsNSSCertificateDB.cpp
@@ -1709,17 +1709,17 @@ nsNSSCertificateDB::VerifyCertNow(nsIX50
   *aHasEVPolicy = false;
   *_retval = PR_UNKNOWN_ERROR;
 
   nsNSSShutDownPreventionLock locker;
   if (isAlreadyShutDown()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
   EnsureIdentityInfoLoaded();
 #endif
 
   nsCOMPtr<nsIX509Cert2> x509Cert = do_QueryInterface(aCert);
   if (!x509Cert) {
     return NS_ERROR_INVALID_ARG;
   }
   ScopedCERTCertificate nssCert(x509Cert->GetCert());
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -1237,17 +1237,17 @@ nsNSSComponent::ShutdownNSS()
       PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("nsNSSComponent::ShutdownNSS cannot stop observing cipher suite change\n"));
     }
 
 #ifndef MOZ_DISABLE_CRYPTOLEGACY
     ShutdownSmartCardThreads();
 #endif
     SSL_ClearSessionCache();
     UnloadLoadableRoots();
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
     CleanupIdentityInfo();
 #endif
     PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("evaporating psm resources\n"));
     mShutdownObjectList->evaporateAllNSSResources();
     EnsureNSSInitialized(nssShutdown);
     if (SECSuccess != ::NSS_Shutdown()) {
       PR_LOG(gPIPNSSLog, PR_LOG_ALWAYS, ("NSS SHUTDOWN FAILURE\n"));
     }
@@ -1804,17 +1804,16 @@ nsNSSComponent::IsNSSInitialized(bool* i
 {
   MutexAutoLock lock(mutex);
   *initialized = mNSSInitialized;
   return NS_OK;
 }
 
 SharedCertVerifier::~SharedCertVerifier() { }
 
-//#ifndef NSS_NO_LIBPKIX
 TemporaryRef<SharedCertVerifier>
 nsNSSComponent::GetDefaultCertVerifier()
 {
   MutexAutoLock lock(mutex);
   MOZ_ASSERT(mNSSInitialized);
   return mDefaultCertVerifier;
 }
 
--- a/security/manager/ssl/src/nsNSSIOLayer.cpp
+++ b/security/manager/ssl/src/nsNSSIOLayer.cpp
@@ -20,17 +20,17 @@
 #include "nsISSLErrorListener.h"
 
 #include "nsNetUtil.h"
 #include "nsPrintfCString.h"
 #include "SSLServerCertVerification.h"
 #include "nsNSSCertHelper.h"
 #include "nsNSSCleaner.h"
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsISecureBrowserUI.h"
 #include "nsIInterfaceRequestorUtils.h"
 #endif
 
 #include "nsCharSeparatedTokenizer.h"
 #include "nsIConsoleService.h"
@@ -212,17 +212,17 @@ nsNSSSocketInfo::SetNotificationCallback
     return NS_OK;
   }
 
   mCallbacks = aCallbacks;
 
   return NS_OK;
 }
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
 static void
 getSecureBrowserUI(nsIInterfaceRequestor* callbacks,
                    nsISecureBrowserUI** result)
 {
   NS_ASSERTION(result, "result parameter to getSecureBrowserUI is null");
   *result = nullptr;
 
   NS_ASSERTION(NS_IsMainThread(),
@@ -474,17 +474,17 @@ nsNSSSocketInfo::GetFileDescPtr(PRFileDe
 
 nsresult
 nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
 {
   mFd = aFilePtr;
   return NS_OK;
 }
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
 class PreviousCertRunnable : public SyncRunnableBase
 {
 public:
   PreviousCertRunnable(nsIInterfaceRequestor* callbacks)
     : mCallbacks(callbacks)
   {
   }
 
@@ -509,17 +509,17 @@ private:
 #endif
 
 void
 nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
 {
   NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
   *_result = nullptr;
 
-#ifndef NSS_NO_LIBPKIX
+#ifndef MOZ_NO_EV_CERTS
   RefPtr<PreviousCertRunnable> runnable(new PreviousCertRunnable(mCallbacks));
   DebugOnly<nsresult> rv = runnable->DispatchToMainThreadAndWait();
   NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
   runnable->mPreviousCert.forget(_result);
 #endif
 }
 
 void
--- a/security/manager/ssl/src/nsSSLStatus.cpp
+++ b/security/manager/ssl/src/nsSSLStatus.cpp
@@ -90,17 +90,17 @@ nsSSLStatus::GetIsUntrusted(bool* _resul
 }
 
 NS_IMETHODIMP
 nsSSLStatus::GetIsExtendedValidation(bool* aIsEV)
 {
   NS_ENSURE_ARG_POINTER(aIsEV);
   *aIsEV = false;
 
-#ifdef NSS_NO_LIBPKIX
+#ifdef MOZ_NO_EV_CERTS
   return NS_OK;
 #else
   nsCOMPtr<nsIX509Cert> cert = mServerCert;
   nsresult rv;
   nsCOMPtr<nsIIdentityInfo> idinfo = do_QueryInterface(cert, &rv);
 
   // mServerCert should never be null when this method is called because
   // nsSSLStatus objects always have mServerCert set right after they are
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -18,36 +18,37 @@ let gIsWindows = ("@mozilla.org/windows-
 const isDebugBuild = Cc["@mozilla.org/xpcom/debug;1"]
                        .getService(Ci.nsIDebug2).isDebugBuild;
 
 const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
 const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
 
 // Sort in numerical order
 const SEC_ERROR_EXPIRED_CERTIFICATE                     = SEC_ERROR_BASE +  11;
-const SEC_ERROR_REVOKED_CERTIFICATE                     = SEC_ERROR_BASE +  12;
+const SEC_ERROR_REVOKED_CERTIFICATE                     = SEC_ERROR_BASE +  12; // -8180
 const SEC_ERROR_UNKNOWN_ISSUER                          = SEC_ERROR_BASE +  13;
 const SEC_ERROR_BAD_DATABASE                            = SEC_ERROR_BASE +  18;
-const SEC_ERROR_UNTRUSTED_ISSUER                        = SEC_ERROR_BASE +  20;
-const SEC_ERROR_UNTRUSTED_CERT                          = SEC_ERROR_BASE +  21;
-const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE              = SEC_ERROR_BASE +  30;
-const SEC_ERROR_EXTENSION_NOT_FOUND                     = SEC_ERROR_BASE +  35;
+const SEC_ERROR_UNTRUSTED_ISSUER                        = SEC_ERROR_BASE +  20; // -8172
+const SEC_ERROR_UNTRUSTED_CERT                          = SEC_ERROR_BASE +  21; // -8171
+const SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE              = SEC_ERROR_BASE +  30; // -8162
+const SEC_ERROR_EXTENSION_NOT_FOUND                     = SEC_ERROR_BASE +  35; // -8157
 const SEC_ERROR_CA_CERT_INVALID                         = SEC_ERROR_BASE +  36;
 const SEC_ERROR_INADEQUATE_KEY_USAGE                    = SEC_ERROR_BASE +  90; // -8102  
 const SEC_ERROR_CERT_NOT_IN_NAME_SPACE                  = SEC_ERROR_BASE + 112; // -8080
 const SEC_ERROR_OCSP_MALFORMED_REQUEST                  = SEC_ERROR_BASE + 120;
 const SEC_ERROR_OCSP_SERVER_ERROR                       = SEC_ERROR_BASE + 121;
 const SEC_ERROR_OCSP_TRY_SERVER_LATER                   = SEC_ERROR_BASE + 122;
 const SEC_ERROR_OCSP_REQUEST_NEEDS_SIG                  = SEC_ERROR_BASE + 123;
 const SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST               = SEC_ERROR_BASE + 124;
-const SEC_ERROR_OCSP_UNKNOWN_CERT                       = SEC_ERROR_BASE + 126;
+const SEC_ERROR_OCSP_UNKNOWN_CERT                       = SEC_ERROR_BASE + 126; // -8066
 const SEC_ERROR_OCSP_MALFORMED_RESPONSE                 = SEC_ERROR_BASE + 129;
 const SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE              = SEC_ERROR_BASE + 130;
 const SEC_ERROR_OCSP_OLD_RESPONSE                       = SEC_ERROR_BASE + 132;
 const SEC_ERROR_OCSP_INVALID_SIGNING_CERT               = SEC_ERROR_BASE + 144;
+const SEC_ERROR_POLICY_VALIDATION_FAILE